#include <linux/lockdep.h>
#include <linux/ar8216_platform.h>
#include <linux/workqueue.h>
+#include <linux/of_device.h>
+
#include "ar8216.h"
/* size of the vlan table */
#define AR8XXX_MIB_WORK_DELAY 2000 /* msecs */
-struct ar8216_priv;
+struct ar8xxx_priv;
#define AR8XXX_CAP_GIGE BIT(0)
#define AR8XXX_CAP_MIB_COUNTERS BIT(1)
struct ar8xxx_chip {
unsigned long caps;
- int (*hw_init)(struct ar8216_priv *priv);
- void (*init_globals)(struct ar8216_priv *priv);
- void (*init_port)(struct ar8216_priv *priv, int port);
- void (*setup_port)(struct ar8216_priv *priv, int port, u32 egress,
+ int (*hw_init)(struct ar8xxx_priv *priv);
+ void (*init_globals)(struct ar8xxx_priv *priv);
+ void (*init_port)(struct ar8xxx_priv *priv, int port);
+ void (*setup_port)(struct ar8xxx_priv *priv, int port, u32 egress,
u32 ingress, u32 members, u32 pvid);
- u32 (*read_port_status)(struct ar8216_priv *priv, int port);
- int (*atu_flush)(struct ar8216_priv *priv);
- void (*vtu_flush)(struct ar8216_priv *priv);
- void (*vtu_load_vlan)(struct ar8216_priv *priv, u32 vid, u32 port_mask);
+ u32 (*read_port_status)(struct ar8xxx_priv *priv, int port);
+ int (*atu_flush)(struct ar8xxx_priv *priv);
+ void (*vtu_flush)(struct ar8xxx_priv *priv);
+ void (*vtu_load_vlan)(struct ar8xxx_priv *priv, u32 vid, u32 port_mask);
const struct ar8xxx_mib_desc *mib_decs;
unsigned num_mibs;
};
-struct ar8216_priv {
+struct ar8327_data {
+ u32 port0_status;
+ u32 port6_status;
+};
+
+struct ar8xxx_priv {
struct switch_dev dev;
struct mii_bus *mii_bus;
struct phy_device *phy;
- u32 (*read)(struct ar8216_priv *priv, int reg);
- void (*write)(struct ar8216_priv *priv, int reg, u32 val);
+
+ u32 (*read)(struct ar8xxx_priv *priv, int reg);
+ void (*write)(struct ar8xxx_priv *priv, int reg, u32 val);
+
+ int (*get_port_link)(unsigned port);
+
const struct net_device_ops *ndo_old;
struct net_device_ops ndo;
struct mutex reg_mutex;
u8 chip_ver;
u8 chip_rev;
const struct ar8xxx_chip *chip;
+ union {
+ struct ar8327_data ar8327;
+ } chip_data;
bool initialized;
bool port4_phy;
char buf[2048];
u8 vlan_table[AR8X16_MAX_VLANS];
u8 vlan_tagged;
u16 pvid[AR8X16_MAX_PORTS];
+
+ /* mirroring */
+ bool mirror_rx;
+ bool mirror_tx;
+ int source_port;
+ int monitor_port;
};
#define MIB_DESC(_s , _o, _n) \
static DEFINE_MUTEX(ar8xxx_dev_list_lock);
static LIST_HEAD(ar8xxx_dev_list);
-static inline struct ar8216_priv *
-swdev_to_ar8216(struct switch_dev *swdev)
+static inline struct ar8xxx_priv *
+swdev_to_ar8xxx(struct switch_dev *swdev)
{
- return container_of(swdev, struct ar8216_priv, dev);
+ return container_of(swdev, struct ar8xxx_priv, dev);
}
-static inline bool ar8xxx_has_gige(struct ar8216_priv *priv)
+static inline bool ar8xxx_has_gige(struct ar8xxx_priv *priv)
{
return priv->chip->caps & AR8XXX_CAP_GIGE;
}
-static inline bool ar8xxx_has_mib_counters(struct ar8216_priv *priv)
+static inline bool ar8xxx_has_mib_counters(struct ar8xxx_priv *priv)
{
return priv->chip->caps & AR8XXX_CAP_MIB_COUNTERS;
}
-static inline bool chip_is_ar8216(struct ar8216_priv *priv)
+static inline bool chip_is_ar8216(struct ar8xxx_priv *priv)
{
return priv->chip_ver == AR8XXX_VER_AR8216;
}
-static inline bool chip_is_ar8236(struct ar8216_priv *priv)
+static inline bool chip_is_ar8236(struct ar8xxx_priv *priv)
{
return priv->chip_ver == AR8XXX_VER_AR8236;
}
-static inline bool chip_is_ar8316(struct ar8216_priv *priv)
+static inline bool chip_is_ar8316(struct ar8xxx_priv *priv)
{
return priv->chip_ver == AR8XXX_VER_AR8316;
}
-static inline bool chip_is_ar8327(struct ar8216_priv *priv)
+static inline bool chip_is_ar8327(struct ar8xxx_priv *priv)
{
return priv->chip_ver == AR8XXX_VER_AR8327;
}
}
static u32
-ar8216_mii_read(struct ar8216_priv *priv, int reg)
+ar8xxx_mii_read(struct ar8xxx_priv *priv, int reg)
{
struct mii_bus *bus = priv->mii_bus;
u16 r1, r2, page;
}
static void
-ar8216_mii_write(struct ar8216_priv *priv, int reg, u32 val)
+ar8xxx_mii_write(struct ar8xxx_priv *priv, int reg, u32 val)
{
struct mii_bus *bus = priv->mii_bus;
u16 r1, r2, r3;
}
static void
-ar8216_phy_dbg_write(struct ar8216_priv *priv, int phy_addr,
+ar8xxx_phy_dbg_write(struct ar8xxx_priv *priv, int phy_addr,
u16 dbg_addr, u16 dbg_data)
{
struct mii_bus *bus = priv->mii_bus;
}
static void
-ar8216_phy_mmd_write(struct ar8216_priv *priv, int phy_addr, u16 addr, u16 data)
+ar8xxx_phy_mmd_write(struct ar8xxx_priv *priv, int phy_addr, u16 addr, u16 data)
{
struct mii_bus *bus = priv->mii_bus;
}
static u32
-ar8216_rmw(struct ar8216_priv *priv, int reg, u32 mask, u32 val)
+ar8xxx_rmw(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val)
{
u32 v;
}
static inline void
-ar8216_reg_set(struct ar8216_priv *priv, int reg, u32 val)
+ar8xxx_reg_set(struct ar8xxx_priv *priv, int reg, u32 val)
{
u32 v;
}
static int
-ar8216_reg_wait(struct ar8216_priv *priv, u32 reg, u32 mask, u32 val,
+ar8xxx_reg_wait(struct ar8xxx_priv *priv, u32 reg, u32 mask, u32 val,
unsigned timeout)
{
int i;
}
static int
-ar8216_mib_op(struct ar8216_priv *priv, u32 op)
+ar8xxx_mib_op(struct ar8xxx_priv *priv, u32 op)
{
unsigned mib_func;
int ret;
mutex_lock(&priv->reg_mutex);
/* Capture the hardware statistics for all ports */
- ar8216_rmw(priv, mib_func, AR8216_MIB_FUNC, (op << AR8216_MIB_FUNC_S));
+ ar8xxx_rmw(priv, mib_func, AR8216_MIB_FUNC, (op << AR8216_MIB_FUNC_S));
mutex_unlock(&priv->reg_mutex);
/* Wait for the capturing to complete. */
- ret = ar8216_reg_wait(priv, mib_func, AR8216_MIB_BUSY, 0, 10);
+ ret = ar8xxx_reg_wait(priv, mib_func, AR8216_MIB_BUSY, 0, 10);
if (ret)
goto out;
}
static int
-ar8216_mib_capture(struct ar8216_priv *priv)
+ar8xxx_mib_capture(struct ar8xxx_priv *priv)
{
- return ar8216_mib_op(priv, AR8216_MIB_FUNC_CAPTURE);
+ return ar8xxx_mib_op(priv, AR8216_MIB_FUNC_CAPTURE);
}
static int
-ar8216_mib_flush(struct ar8216_priv *priv)
+ar8xxx_mib_flush(struct ar8xxx_priv *priv)
{
- return ar8216_mib_op(priv, AR8216_MIB_FUNC_FLUSH);
+ return ar8xxx_mib_op(priv, AR8216_MIB_FUNC_FLUSH);
}
static void
-ar8216_mib_fetch_port_stat(struct ar8216_priv *priv, int port, bool flush)
+ar8xxx_mib_fetch_port_stat(struct ar8xxx_priv *priv, int port, bool flush)
{
unsigned int base;
u64 *mib_stats;
}
static void
-ar8216_read_port_link(struct ar8216_priv *priv, int port,
+ar8216_read_port_link(struct ar8xxx_priv *priv, int port,
struct switch_port_link *link)
{
u32 status;
link->aneg = !!(status & AR8216_PORT_STATUS_LINK_AUTO);
if (link->aneg) {
link->link = !!(status & AR8216_PORT_STATUS_LINK_UP);
- if (!link->link)
- return;
} else {
link->link = true;
+
+ if (priv->get_port_link) {
+ int err;
+
+ err = priv->get_port_link(port);
+ if (err >= 0)
+ link->link = !!err;
+ }
}
+ if (!link->link)
+ return;
+
link->duplex = !!(status & AR8216_PORT_STATUS_DUPLEX);
link->tx_flow = !!(status & AR8216_PORT_STATUS_TXFLOW);
link->rx_flow = !!(status & AR8216_PORT_STATUS_RXFLOW);
static struct sk_buff *
ar8216_mangle_tx(struct net_device *dev, struct sk_buff *skb)
{
- struct ar8216_priv *priv = dev->phy_ptr;
+ struct ar8xxx_priv *priv = dev->phy_ptr;
unsigned char *buf;
if (unlikely(!priv))
static void
ar8216_mangle_rx(struct net_device *dev, struct sk_buff *skb)
{
- struct ar8216_priv *priv;
+ struct ar8xxx_priv *priv;
unsigned char *buf;
int port, vlan;
}
static int
-ar8216_wait_bit(struct ar8216_priv *priv, int reg, u32 mask, u32 val)
+ar8216_wait_bit(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val)
{
int timeout = 20;
u32 t = 0;
}
static void
-ar8216_vtu_op(struct ar8216_priv *priv, u32 op, u32 val)
+ar8216_vtu_op(struct ar8xxx_priv *priv, u32 op, u32 val)
{
if (ar8216_wait_bit(priv, AR8216_REG_VTU, AR8216_VTU_ACTIVE, 0))
return;
}
static void
-ar8216_vtu_flush(struct ar8216_priv *priv)
+ar8216_vtu_flush(struct ar8xxx_priv *priv)
{
ar8216_vtu_op(priv, AR8216_VTU_OP_FLUSH, 0);
}
static void
-ar8216_vtu_load_vlan(struct ar8216_priv *priv, u32 vid, u32 port_mask)
+ar8216_vtu_load_vlan(struct ar8xxx_priv *priv, u32 vid, u32 port_mask)
{
u32 op;
}
static int
-ar8216_atu_flush(struct ar8216_priv *priv)
+ar8216_atu_flush(struct ar8xxx_priv *priv)
{
int ret;
}
static u32
-ar8216_read_port_status(struct ar8216_priv *priv, int port)
+ar8216_read_port_status(struct ar8xxx_priv *priv, int port)
{
return priv->read(priv, AR8216_REG_PORT_STATUS(port));
}
static void
-ar8216_setup_port(struct ar8216_priv *priv, int port, u32 egress, u32 ingress,
+ar8216_setup_port(struct ar8xxx_priv *priv, int port, u32 egress, u32 ingress,
u32 members, u32 pvid)
{
u32 header;
else
header = 0;
- ar8216_rmw(priv, AR8216_REG_PORT_CTRL(port),
+ ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(port),
AR8216_PORT_CTRL_LEARN | AR8216_PORT_CTRL_VLAN_MODE |
AR8216_PORT_CTRL_SINGLE_VLAN | AR8216_PORT_CTRL_STATE |
AR8216_PORT_CTRL_HEADER | AR8216_PORT_CTRL_LEARN_LOCK,
(egress << AR8216_PORT_CTRL_VLAN_MODE_S) |
(AR8216_PORT_STATE_FORWARD << AR8216_PORT_CTRL_STATE_S));
- ar8216_rmw(priv, AR8216_REG_PORT_VLAN(port),
+ ar8xxx_rmw(priv, AR8216_REG_PORT_VLAN(port),
AR8216_PORT_VLAN_DEST_PORTS | AR8216_PORT_VLAN_MODE |
AR8216_PORT_VLAN_DEFAULT_ID,
(members << AR8216_PORT_VLAN_DEST_PORTS_S) |
}
static int
-ar8216_hw_init(struct ar8216_priv *priv)
+ar8216_hw_init(struct ar8xxx_priv *priv)
{
return 0;
}
static void
-ar8216_init_globals(struct ar8216_priv *priv)
+ar8216_init_globals(struct ar8xxx_priv *priv)
{
/* standard atheros magic */
priv->write(priv, 0x38, 0xc000050e);
- ar8216_rmw(priv, AR8216_REG_GLOBAL_CTRL,
+ ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL,
AR8216_GCTRL_MTU, 1518 + 8 + 2);
}
static void
-ar8216_init_port(struct ar8216_priv *priv, int port)
+ar8216_init_port(struct ar8xxx_priv *priv, int port)
{
/* Enable port learning and tx */
priv->write(priv, AR8216_REG_PORT_CTRL(port),
};
static void
-ar8236_setup_port(struct ar8216_priv *priv, int port, u32 egress, u32 ingress,
+ar8236_setup_port(struct ar8xxx_priv *priv, int port, u32 egress, u32 ingress,
u32 members, u32 pvid)
{
- ar8216_rmw(priv, AR8216_REG_PORT_CTRL(port),
+ ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(port),
AR8216_PORT_CTRL_LEARN | AR8216_PORT_CTRL_VLAN_MODE |
AR8216_PORT_CTRL_SINGLE_VLAN | AR8216_PORT_CTRL_STATE |
AR8216_PORT_CTRL_HEADER | AR8216_PORT_CTRL_LEARN_LOCK,
(egress << AR8216_PORT_CTRL_VLAN_MODE_S) |
(AR8216_PORT_STATE_FORWARD << AR8216_PORT_CTRL_STATE_S));
- ar8216_rmw(priv, AR8236_REG_PORT_VLAN(port),
+ ar8xxx_rmw(priv, AR8236_REG_PORT_VLAN(port),
AR8236_PORT_VLAN_DEFAULT_ID,
(pvid << AR8236_PORT_VLAN_DEFAULT_ID_S));
- ar8216_rmw(priv, AR8236_REG_PORT_VLAN2(port),
+ ar8xxx_rmw(priv, AR8236_REG_PORT_VLAN2(port),
AR8236_PORT_VLAN2_VLAN_MODE |
AR8236_PORT_VLAN2_MEMBER,
(ingress << AR8236_PORT_VLAN2_VLAN_MODE_S) |
}
static int
-ar8236_hw_init(struct ar8216_priv *priv)
+ar8236_hw_init(struct ar8xxx_priv *priv)
{
int i;
struct mii_bus *bus;
}
static void
-ar8236_init_globals(struct ar8216_priv *priv)
+ar8236_init_globals(struct ar8xxx_priv *priv)
{
/* enable jumbo frames */
- ar8216_rmw(priv, AR8216_REG_GLOBAL_CTRL,
+ ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL,
AR8316_GCTRL_MTU, 9018 + 8 + 2);
/* Enable MIB counters */
- ar8216_rmw(priv, AR8216_REG_MIB_FUNC, AR8216_MIB_FUNC | AR8236_MIB_EN,
+ ar8xxx_rmw(priv, AR8216_REG_MIB_FUNC, AR8216_MIB_FUNC | AR8236_MIB_EN,
(AR8216_MIB_FUNC_NO_OP << AR8216_MIB_FUNC_S) |
AR8236_MIB_EN);
}
};
static int
-ar8316_hw_init(struct ar8216_priv *priv)
+ar8316_hw_init(struct ar8xxx_priv *priv)
{
int i;
u32 val, newval;
priv->write(priv, AR8316_REG_POSTRIP, newval);
+ if (priv->port4_phy &&
+ priv->phy->interface == PHY_INTERFACE_MODE_RGMII) {
+ /* work around for phy4 rgmii mode */
+ ar8xxx_phy_dbg_write(priv, 4, 0x12, 0x480c);
+ /* rx delay */
+ ar8xxx_phy_dbg_write(priv, 4, 0x0, 0x824e);
+ /* tx delay */
+ ar8xxx_phy_dbg_write(priv, 4, 0x5, 0x3d47);
+ msleep(1000);
+ }
+
/* Initialize the ports */
bus = priv->mii_bus;
for (i = 0; i < 5; i++) {
- if ((i == 4) && priv->port4_phy &&
- priv->phy->interface == PHY_INTERFACE_MODE_RGMII) {
- /* work around for phy4 rgmii mode */
- ar8216_phy_dbg_write(priv, i, 0x12, 0x480c);
- /* rx delay */
- ar8216_phy_dbg_write(priv, i, 0x0, 0x824e);
- /* tx delay */
- ar8216_phy_dbg_write(priv, i, 0x5, 0x3d47);
- msleep(1000);
- }
-
/* initialize the port itself */
mdiobus_write(bus, i, MII_ADVERTISE,
ADVERTISE_ALL | ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM);
}
static void
-ar8316_init_globals(struct ar8216_priv *priv)
+ar8316_init_globals(struct ar8xxx_priv *priv)
{
/* standard atheros magic */
priv->write(priv, 0x38, 0xc000050e);
priv->write(priv, AR8216_REG_FLOOD_MASK, 0x003f003f);
/* enable jumbo frames */
- ar8216_rmw(priv, AR8216_REG_GLOBAL_CTRL,
+ ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CTRL,
AR8316_GCTRL_MTU, 9018 + 8 + 2);
/* Enable MIB counters */
- ar8216_rmw(priv, AR8216_REG_MIB_FUNC, AR8216_MIB_FUNC | AR8236_MIB_EN,
+ ar8xxx_rmw(priv, AR8216_REG_MIB_FUNC, AR8216_MIB_FUNC | AR8236_MIB_EN,
(AR8216_MIB_FUNC_NO_OP << AR8216_MIB_FUNC_S) |
AR8236_MIB_EN);
}
}
static void
-ar8327_phy_fixup(struct ar8216_priv *priv, int phy)
+ar8327_phy_fixup(struct ar8xxx_priv *priv, int phy)
{
switch (priv->chip_rev) {
case 1:
/* For 100M waveform */
- ar8216_phy_dbg_write(priv, phy, 0, 0x02ea);
+ ar8xxx_phy_dbg_write(priv, phy, 0, 0x02ea);
/* Turn on Gigabit clock */
- ar8216_phy_dbg_write(priv, phy, 0x3d, 0x68a0);
+ ar8xxx_phy_dbg_write(priv, phy, 0x3d, 0x68a0);
break;
case 2:
- ar8216_phy_mmd_write(priv, phy, 0x7, 0x3c);
- ar8216_phy_mmd_write(priv, phy, 0x4007, 0x0);
+ ar8xxx_phy_mmd_write(priv, phy, 0x7, 0x3c);
+ ar8xxx_phy_mmd_write(priv, phy, 0x4007, 0x0);
/* fallthrough */
case 4:
- ar8216_phy_mmd_write(priv, phy, 0x3, 0x800d);
- ar8216_phy_mmd_write(priv, phy, 0x4003, 0x803f);
+ ar8xxx_phy_mmd_write(priv, phy, 0x3, 0x800d);
+ ar8xxx_phy_mmd_write(priv, phy, 0x4003, 0x803f);
+
+ ar8xxx_phy_dbg_write(priv, phy, 0x3d, 0x6860);
+ ar8xxx_phy_dbg_write(priv, phy, 0x5, 0x2c46);
+ ar8xxx_phy_dbg_write(priv, phy, 0x3c, 0x6000);
+ break;
+ }
+}
- ar8216_phy_dbg_write(priv, phy, 0x3d, 0x6860);
- ar8216_phy_dbg_write(priv, phy, 0x5, 0x2c46);
- ar8216_phy_dbg_write(priv, phy, 0x3c, 0x6000);
+static u32
+ar8327_get_port_init_status(struct ar8327_port_cfg *cfg)
+{
+ u32 t;
+
+ if (!cfg->force_link)
+ return AR8216_PORT_STATUS_LINK_AUTO;
+
+ t = AR8216_PORT_STATUS_TXMAC | AR8216_PORT_STATUS_RXMAC;
+ t |= cfg->duplex ? AR8216_PORT_STATUS_DUPLEX : 0;
+ t |= cfg->rxpause ? AR8216_PORT_STATUS_RXFLOW : 0;
+ t |= cfg->txpause ? AR8216_PORT_STATUS_TXFLOW : 0;
+
+ switch (cfg->speed) {
+ case AR8327_PORT_SPEED_10:
+ t |= AR8216_PORT_SPEED_10M;
+ break;
+ case AR8327_PORT_SPEED_100:
+ t |= AR8216_PORT_SPEED_100M;
+ break;
+ case AR8327_PORT_SPEED_1000:
+ t |= AR8216_PORT_SPEED_1000M;
break;
}
+
+ return t;
}
static int
-ar8327_hw_init(struct ar8216_priv *priv)
+ar8327_hw_config_pdata(struct ar8xxx_priv *priv,
+ struct ar8327_platform_data *pdata)
{
- struct ar8327_platform_data *pdata;
struct ar8327_led_cfg *led_cfg;
- struct mii_bus *bus;
+ struct ar8327_data *data;
u32 pos, new_pos;
u32 t;
- int i;
- pdata = priv->phy->dev.platform_data;
if (!pdata)
return -EINVAL;
+ priv->get_port_link = pdata->get_port_link;
+
+ data = &priv->chip_data.ar8327;
+
+ data->port0_status = ar8327_get_port_init_status(&pdata->port0_cfg);
+ data->port6_status = ar8327_get_port_init_status(&pdata->port6_cfg);
+
t = ar8327_get_pad_cfg(pdata->pad0_cfg);
priv->write(priv, AR8327_REG_PAD0_MODE, t);
t = ar8327_get_pad_cfg(pdata->pad5_cfg);
priv->write(priv, AR8327_REG_LED_CTRL1, led_cfg->led_ctrl1);
priv->write(priv, AR8327_REG_LED_CTRL2, led_cfg->led_ctrl2);
priv->write(priv, AR8327_REG_LED_CTRL3, led_cfg->led_ctrl3);
+
+ if (new_pos != pos)
+ new_pos |= AR8327_POWER_ON_STRIP_POWER_ON_SEL;
}
- if (new_pos != pos) {
- new_pos |= AR8327_POWER_ON_STRIP_POWER_ON_SEL;
- priv->write(priv, AR8327_REG_POWER_ON_STRIP, new_pos);
+ if (pdata->sgmii_cfg) {
+ t = pdata->sgmii_cfg->sgmii_ctrl;
+ if (priv->chip_rev == 1)
+ t |= AR8327_SGMII_CTRL_EN_PLL |
+ AR8327_SGMII_CTRL_EN_RX |
+ AR8327_SGMII_CTRL_EN_TX;
+ else
+ t &= ~(AR8327_SGMII_CTRL_EN_PLL |
+ AR8327_SGMII_CTRL_EN_RX |
+ AR8327_SGMII_CTRL_EN_TX);
+
+ priv->write(priv, AR8327_REG_SGMII_CTRL, t);
+
+ if (pdata->sgmii_cfg->serdes_aen)
+ new_pos &= ~AR8327_POWER_ON_STRIP_SERDES_AEN;
+ else
+ new_pos |= AR8327_POWER_ON_STRIP_SERDES_AEN;
}
+ priv->write(priv, AR8327_REG_POWER_ON_STRIP, new_pos);
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static int
+ar8327_hw_config_of(struct ar8xxx_priv *priv, struct device_node *np)
+{
+ const __be32 *paddr;
+ int len;
+ int i;
+
+ paddr = of_get_property(np, "qca,ar8327-initvals", &len);
+ if (!paddr || len < (2 * sizeof(*paddr)))
+ return -EINVAL;
+
+ len /= sizeof(*paddr);
+
+ for (i = 0; i < len - 1; i += 2) {
+ u32 reg;
+ u32 val;
+
+ reg = be32_to_cpup(paddr + i);
+ val = be32_to_cpup(paddr + i + 1);
+
+ switch (reg) {
+ case AR8327_REG_PORT_STATUS(0):
+ priv->chip_data.ar8327.port0_status = val;
+ break;
+ case AR8327_REG_PORT_STATUS(6):
+ priv->chip_data.ar8327.port6_status = val;
+ break;
+ default:
+ priv->write(priv, reg, val);
+ break;
+ }
+ }
+
+ return 0;
+}
+#else
+static inline int
+ar8327_hw_config_of(struct ar8xxx_priv *priv, struct device_node *np)
+{
+ return -EINVAL;
+}
+#endif
+
+static int
+ar8327_hw_init(struct ar8xxx_priv *priv)
+{
+ struct mii_bus *bus;
+ int ret;
+ int i;
+
+ if (priv->phy->dev.of_node)
+ ret = ar8327_hw_config_of(priv, priv->phy->dev.of_node);
+ else
+ ret = ar8327_hw_config_pdata(priv,
+ priv->phy->dev.platform_data);
+
+ if (ret)
+ return ret;
+
bus = priv->mii_bus;
for (i = 0; i < AR8327_NUM_PHYS; i++) {
ar8327_phy_fixup(priv, i);
}
static void
-ar8327_init_globals(struct ar8216_priv *priv)
+ar8327_init_globals(struct ar8xxx_priv *priv)
{
u32 t;
priv->write(priv, AR8327_REG_FWD_CTRL1, t);
/* setup MTU */
- ar8216_rmw(priv, AR8327_REG_MAX_FRAME_SIZE,
+ ar8xxx_rmw(priv, AR8327_REG_MAX_FRAME_SIZE,
AR8327_MAX_FRAME_SIZE_MTU, 1518 + 8 + 2);
/* Enable MIB counters */
- ar8216_reg_set(priv, AR8327_REG_MODULE_EN,
+ ar8xxx_reg_set(priv, AR8327_REG_MODULE_EN,
AR8327_MODULE_EN_MIB);
}
static void
-ar8327_config_port(struct ar8216_priv *priv, unsigned int port,
- struct ar8327_port_cfg *cfg)
+ar8327_init_port(struct ar8xxx_priv *priv, int port)
{
u32 t;
- if (!cfg || !cfg->force_link) {
- priv->write(priv, AR8327_REG_PORT_STATUS(port),
- AR8216_PORT_STATUS_LINK_AUTO);
- return;
- }
-
- t = AR8216_PORT_STATUS_TXMAC | AR8216_PORT_STATUS_RXMAC;
- t |= cfg->duplex ? AR8216_PORT_STATUS_DUPLEX : 0;
- t |= cfg->rxpause ? AR8216_PORT_STATUS_RXFLOW : 0;
- t |= cfg->txpause ? AR8216_PORT_STATUS_TXFLOW : 0;
-
- switch (cfg->speed) {
- case AR8327_PORT_SPEED_10:
- t |= AR8216_PORT_SPEED_10M;
- break;
- case AR8327_PORT_SPEED_100:
- t |= AR8216_PORT_SPEED_100M;
- break;
- case AR8327_PORT_SPEED_1000:
- t |= AR8216_PORT_SPEED_1000M;
- break;
- }
-
- priv->write(priv, AR8327_REG_PORT_STATUS(port), t);
-}
-
-static void
-ar8327_init_port(struct ar8216_priv *priv, int port)
-{
- struct ar8327_platform_data *pdata;
- struct ar8327_port_cfg *cfg;
- u32 t;
-
- pdata = priv->phy->dev.platform_data;
-
- if (pdata && port == AR8216_PORT_CPU)
- cfg = &pdata->port0_cfg;
- else if (pdata && port == 6)
- cfg = &pdata->port6_cfg;
+ if (port == AR8216_PORT_CPU)
+ t = priv->chip_data.ar8327.port0_status;
+ else if (port == 6)
+ t = priv->chip_data.ar8327.port6_status;
else
- cfg = NULL;
-
- ar8327_config_port(priv, port, cfg);
+ t = AR8216_PORT_STATUS_LINK_AUTO;
+ priv->write(priv, AR8327_REG_PORT_STATUS(port), t);
priv->write(priv, AR8327_REG_PORT_HEADER(port), 0);
t = 1 << AR8327_PORT_VLAN0_DEF_SVID_S;
}
static u32
-ar8327_read_port_status(struct ar8216_priv *priv, int port)
+ar8327_read_port_status(struct ar8xxx_priv *priv, int port)
{
return priv->read(priv, AR8327_REG_PORT_STATUS(port));
}
static int
-ar8327_atu_flush(struct ar8216_priv *priv)
+ar8327_atu_flush(struct ar8xxx_priv *priv)
{
int ret;
}
static void
-ar8327_vtu_op(struct ar8216_priv *priv, u32 op, u32 val)
+ar8327_vtu_op(struct ar8xxx_priv *priv, u32 op, u32 val)
{
if (ar8216_wait_bit(priv, AR8327_REG_VTU_FUNC1,
AR8327_VTU_FUNC1_BUSY, 0))
}
static void
-ar8327_vtu_flush(struct ar8216_priv *priv)
+ar8327_vtu_flush(struct ar8xxx_priv *priv)
{
ar8327_vtu_op(priv, AR8327_VTU_FUNC1_OP_FLUSH, 0);
}
static void
-ar8327_vtu_load_vlan(struct ar8216_priv *priv, u32 vid, u32 port_mask)
+ar8327_vtu_load_vlan(struct ar8xxx_priv *priv, u32 vid, u32 port_mask)
{
u32 op;
u32 val;
}
static void
-ar8327_setup_port(struct ar8216_priv *priv, int port, u32 egress, u32 ingress,
+ar8327_setup_port(struct ar8xxx_priv *priv, int port, u32 egress, u32 ingress,
u32 members, u32 pvid)
{
u32 t;
};
static int
-ar8216_sw_set_vlan(struct switch_dev *dev, const struct switch_attr *attr,
+ar8xxx_sw_set_vlan(struct switch_dev *dev, const struct switch_attr *attr,
struct switch_val *val)
{
- struct ar8216_priv *priv = swdev_to_ar8216(dev);
+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
priv->vlan = !!val->value.i;
return 0;
}
static int
-ar8216_sw_get_vlan(struct switch_dev *dev, const struct switch_attr *attr,
+ar8xxx_sw_get_vlan(struct switch_dev *dev, const struct switch_attr *attr,
struct switch_val *val)
{
- struct ar8216_priv *priv = swdev_to_ar8216(dev);
+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
val->value.i = priv->vlan;
return 0;
}
static int
-ar8216_sw_set_pvid(struct switch_dev *dev, int port, int vlan)
+ar8xxx_sw_set_pvid(struct switch_dev *dev, int port, int vlan)
{
- struct ar8216_priv *priv = swdev_to_ar8216(dev);
+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
/* make sure no invalid PVIDs get set */
}
static int
-ar8216_sw_get_pvid(struct switch_dev *dev, int port, int *vlan)
+ar8xxx_sw_get_pvid(struct switch_dev *dev, int port, int *vlan)
{
- struct ar8216_priv *priv = swdev_to_ar8216(dev);
+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
*vlan = priv->pvid[port];
return 0;
}
static int
-ar8216_sw_set_vid(struct switch_dev *dev, const struct switch_attr *attr,
+ar8xxx_sw_set_vid(struct switch_dev *dev, const struct switch_attr *attr,
struct switch_val *val)
{
- struct ar8216_priv *priv = swdev_to_ar8216(dev);
+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
priv->vlan_id[val->port_vlan] = val->value.i;
return 0;
}
static int
-ar8216_sw_get_vid(struct switch_dev *dev, const struct switch_attr *attr,
+ar8xxx_sw_get_vid(struct switch_dev *dev, const struct switch_attr *attr,
struct switch_val *val)
{
- struct ar8216_priv *priv = swdev_to_ar8216(dev);
+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
val->value.i = priv->vlan_id[val->port_vlan];
return 0;
}
static int
-ar8216_sw_get_port_link(struct switch_dev *dev, int port,
+ar8xxx_sw_get_port_link(struct switch_dev *dev, int port,
struct switch_port_link *link)
{
- struct ar8216_priv *priv = swdev_to_ar8216(dev);
+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
ar8216_read_port_link(priv, port, link);
return 0;
}
static int
-ar8216_sw_get_ports(struct switch_dev *dev, struct switch_val *val)
+ar8xxx_sw_get_ports(struct switch_dev *dev, struct switch_val *val)
{
- struct ar8216_priv *priv = swdev_to_ar8216(dev);
+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
u8 ports = priv->vlan_table[val->port_vlan];
int i;
}
static int
-ar8216_sw_set_ports(struct switch_dev *dev, struct switch_val *val)
+ar8xxx_sw_set_ports(struct switch_dev *dev, struct switch_val *val)
{
- struct ar8216_priv *priv = swdev_to_ar8216(dev);
+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
u8 *vt = &priv->vlan_table[val->port_vlan];
int i, j;
return 0;
}
+static void
+ar8327_set_mirror_regs(struct ar8xxx_priv *priv)
+{
+ int port;
+
+ /* reset all mirror registers */
+ ar8xxx_rmw(priv, AR8327_REG_FWD_CTRL0,
+ AR8327_FWD_CTRL0_MIRROR_PORT,
+ (0xF << AR8327_FWD_CTRL0_MIRROR_PORT_S));
+ for (port = 0; port < AR8327_NUM_PORTS; port++) {
+ ar8xxx_rmw(priv, AR8327_REG_PORT_LOOKUP(port),
+ AR8327_PORT_LOOKUP_ING_MIRROR_EN,
+ 0);
+
+ ar8xxx_rmw(priv, AR8327_REG_PORT_HOL_CTRL1(port),
+ AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN,
+ 0);
+ }
+
+ /* now enable mirroring if necessary */
+ if (priv->source_port >= AR8327_NUM_PORTS ||
+ priv->monitor_port >= AR8327_NUM_PORTS ||
+ priv->source_port == priv->monitor_port) {
+ return;
+ }
+
+ ar8xxx_rmw(priv, AR8327_REG_FWD_CTRL0,
+ AR8327_FWD_CTRL0_MIRROR_PORT,
+ (priv->monitor_port << AR8327_FWD_CTRL0_MIRROR_PORT_S));
+
+ if (priv->mirror_rx)
+ ar8xxx_rmw(priv, AR8327_REG_PORT_LOOKUP(priv->source_port),
+ AR8327_PORT_LOOKUP_ING_MIRROR_EN,
+ AR8327_PORT_LOOKUP_ING_MIRROR_EN);
+
+ if (priv->mirror_tx)
+ ar8xxx_rmw(priv, AR8327_REG_PORT_HOL_CTRL1(priv->source_port),
+ AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN,
+ AR8327_PORT_HOL_CTRL1_EG_MIRROR_EN);
+}
+
+static void
+ar8216_set_mirror_regs(struct ar8xxx_priv *priv)
+{
+ int port;
+
+ /* reset all mirror registers */
+ ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CPUPORT,
+ AR8216_GLOBAL_CPUPORT_MIRROR_PORT,
+ (0xF << AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S));
+ for (port = 0; port < AR8216_NUM_PORTS; port++) {
+ ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(port),
+ AR8216_PORT_CTRL_MIRROR_RX,
+ 0);
+
+ ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(port),
+ AR8216_PORT_CTRL_MIRROR_TX,
+ 0);
+ }
+
+ /* now enable mirroring if necessary */
+ if (priv->source_port >= AR8216_NUM_PORTS ||
+ priv->monitor_port >= AR8216_NUM_PORTS ||
+ priv->source_port == priv->monitor_port) {
+ return;
+ }
+
+ ar8xxx_rmw(priv, AR8216_REG_GLOBAL_CPUPORT,
+ AR8216_GLOBAL_CPUPORT_MIRROR_PORT,
+ (priv->monitor_port << AR8216_GLOBAL_CPUPORT_MIRROR_PORT_S));
+
+ if (priv->mirror_rx)
+ ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(priv->source_port),
+ AR8216_PORT_CTRL_MIRROR_RX,
+ AR8216_PORT_CTRL_MIRROR_RX);
+
+ if (priv->mirror_tx)
+ ar8xxx_rmw(priv, AR8216_REG_PORT_CTRL(priv->source_port),
+ AR8216_PORT_CTRL_MIRROR_TX,
+ AR8216_PORT_CTRL_MIRROR_TX);
+}
+
+static void
+ar8xxx_set_mirror_regs(struct ar8xxx_priv *priv)
+{
+ if (chip_is_ar8327(priv)) {
+ ar8327_set_mirror_regs(priv);
+ } else {
+ ar8216_set_mirror_regs(priv);
+ }
+}
+
static int
-ar8216_sw_hw_apply(struct switch_dev *dev)
+ar8xxx_sw_hw_apply(struct switch_dev *dev)
{
- struct ar8216_priv *priv = swdev_to_ar8216(dev);
+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
u8 portmask[AR8X16_MAX_PORTS];
int i, j;
priv->chip->setup_port(priv, i, egress, ingress, portmask[i],
pvid);
}
+
+ ar8xxx_set_mirror_regs(priv);
+
mutex_unlock(&priv->reg_mutex);
return 0;
}
static int
-ar8216_sw_reset_switch(struct switch_dev *dev)
+ar8xxx_sw_reset_switch(struct switch_dev *dev)
{
- struct ar8216_priv *priv = swdev_to_ar8216(dev);
+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
int i;
mutex_lock(&priv->reg_mutex);
- memset(&priv->vlan, 0, sizeof(struct ar8216_priv) -
- offsetof(struct ar8216_priv, vlan));
+ memset(&priv->vlan, 0, sizeof(struct ar8xxx_priv) -
+ offsetof(struct ar8xxx_priv, vlan));
for (i = 0; i < AR8X16_MAX_VLANS; i++)
priv->vlan_id[i] = i;
for (i = 0; i < dev->ports; i++)
priv->chip->init_port(priv, i);
+ priv->mirror_rx = false;
+ priv->mirror_tx = false;
+ priv->source_port = 0;
+ priv->monitor_port = 0;
+
priv->chip->init_globals(priv);
+
mutex_unlock(&priv->reg_mutex);
- return ar8216_sw_hw_apply(dev);
+ return ar8xxx_sw_hw_apply(dev);
}
static int
-ar8216_sw_set_reset_mibs(struct switch_dev *dev,
+ar8xxx_sw_set_reset_mibs(struct switch_dev *dev,
const struct switch_attr *attr,
struct switch_val *val)
{
- struct ar8216_priv *priv = swdev_to_ar8216(dev);
+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
unsigned int len;
int ret;
len = priv->dev.ports * priv->chip->num_mibs *
sizeof(*priv->mib_stats);
memset(priv->mib_stats, '\0', len);
- ret = ar8216_mib_flush(priv);
+ ret = ar8xxx_mib_flush(priv);
if (ret)
goto unlock;
}
static int
-ar8216_sw_set_port_reset_mib(struct switch_dev *dev,
+ar8xxx_sw_set_mirror_rx_enable(struct switch_dev *dev,
+ const struct switch_attr *attr,
+ struct switch_val *val)
+{
+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+
+ mutex_lock(&priv->reg_mutex);
+ priv->mirror_rx = !!val->value.i;
+ ar8xxx_set_mirror_regs(priv);
+ mutex_unlock(&priv->reg_mutex);
+
+ return 0;
+}
+
+static int
+ar8xxx_sw_get_mirror_rx_enable(struct switch_dev *dev,
+ const struct switch_attr *attr,
+ struct switch_val *val)
+{
+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+ val->value.i = priv->mirror_rx;
+ return 0;
+}
+
+static int
+ar8xxx_sw_set_mirror_tx_enable(struct switch_dev *dev,
+ const struct switch_attr *attr,
+ struct switch_val *val)
+{
+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+
+ mutex_lock(&priv->reg_mutex);
+ priv->mirror_tx = !!val->value.i;
+ ar8xxx_set_mirror_regs(priv);
+ mutex_unlock(&priv->reg_mutex);
+
+ return 0;
+}
+
+static int
+ar8xxx_sw_get_mirror_tx_enable(struct switch_dev *dev,
+ const struct switch_attr *attr,
+ struct switch_val *val)
+{
+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+ val->value.i = priv->mirror_tx;
+ return 0;
+}
+
+static int
+ar8xxx_sw_set_mirror_monitor_port(struct switch_dev *dev,
+ const struct switch_attr *attr,
+ struct switch_val *val)
+{
+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+
+ mutex_lock(&priv->reg_mutex);
+ priv->monitor_port = val->value.i;
+ ar8xxx_set_mirror_regs(priv);
+ mutex_unlock(&priv->reg_mutex);
+
+ return 0;
+}
+
+static int
+ar8xxx_sw_get_mirror_monitor_port(struct switch_dev *dev,
+ const struct switch_attr *attr,
+ struct switch_val *val)
+{
+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+ val->value.i = priv->monitor_port;
+ return 0;
+}
+
+static int
+ar8xxx_sw_set_mirror_source_port(struct switch_dev *dev,
+ const struct switch_attr *attr,
+ struct switch_val *val)
+{
+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+
+ mutex_lock(&priv->reg_mutex);
+ priv->source_port = val->value.i;
+ ar8xxx_set_mirror_regs(priv);
+ mutex_unlock(&priv->reg_mutex);
+
+ return 0;
+}
+
+static int
+ar8xxx_sw_get_mirror_source_port(struct switch_dev *dev,
+ const struct switch_attr *attr,
+ struct switch_val *val)
+{
+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+ val->value.i = priv->source_port;
+ return 0;
+}
+
+static int
+ar8xxx_sw_set_port_reset_mib(struct switch_dev *dev,
const struct switch_attr *attr,
struct switch_val *val)
{
- struct ar8216_priv *priv = swdev_to_ar8216(dev);
+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
int port;
int ret;
return -EINVAL;
mutex_lock(&priv->mib_lock);
- ret = ar8216_mib_capture(priv);
+ ret = ar8xxx_mib_capture(priv);
if (ret)
goto unlock;
- ar8216_mib_fetch_port_stat(priv, port, true);
+ ar8xxx_mib_fetch_port_stat(priv, port, true);
ret = 0;
}
static int
-ar8216_sw_get_port_mib(struct switch_dev *dev,
+ar8xxx_sw_get_port_mib(struct switch_dev *dev,
const struct switch_attr *attr,
struct switch_val *val)
{
- struct ar8216_priv *priv = swdev_to_ar8216(dev);
+ struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
const struct ar8xxx_chip *chip = priv->chip;
u64 *mib_stats;
int port;
return -EINVAL;
mutex_lock(&priv->mib_lock);
- ret = ar8216_mib_capture(priv);
+ ret = ar8xxx_mib_capture(priv);
if (ret)
goto unlock;
- ar8216_mib_fetch_port_stat(priv, port, false);
+ ar8xxx_mib_fetch_port_stat(priv, port, false);
len += snprintf(buf + len, sizeof(priv->buf) - len,
"Port %d MIB counters\n",
return ret;
}
-static struct switch_attr ar8216_globals[] = {
+static struct switch_attr ar8xxx_sw_attr_globals[] = {
{
.type = SWITCH_TYPE_INT,
.name = "enable_vlan",
.description = "Enable VLAN mode",
- .set = ar8216_sw_set_vlan,
- .get = ar8216_sw_get_vlan,
+ .set = ar8xxx_sw_set_vlan,
+ .get = ar8xxx_sw_get_vlan,
.max = 1
},
{
.type = SWITCH_TYPE_NOVAL,
.name = "reset_mibs",
.description = "Reset all MIB counters",
- .set = ar8216_sw_set_reset_mibs,
+ .set = ar8xxx_sw_set_reset_mibs,
+ },
+ {
+ .type = SWITCH_TYPE_INT,
+ .name = "enable_mirror_rx",
+ .description = "Enable mirroring of RX packets",
+ .set = ar8xxx_sw_set_mirror_rx_enable,
+ .get = ar8xxx_sw_get_mirror_rx_enable,
+ .max = 1
+ },
+ {
+ .type = SWITCH_TYPE_INT,
+ .name = "enable_mirror_tx",
+ .description = "Enable mirroring of TX packets",
+ .set = ar8xxx_sw_set_mirror_tx_enable,
+ .get = ar8xxx_sw_get_mirror_tx_enable,
+ .max = 1
},
+ {
+ .type = SWITCH_TYPE_INT,
+ .name = "mirror_monitor_port",
+ .description = "Mirror monitor port",
+ .set = ar8xxx_sw_set_mirror_monitor_port,
+ .get = ar8xxx_sw_get_mirror_monitor_port,
+ .max = AR8216_NUM_PORTS - 1
+ },
+ {
+ .type = SWITCH_TYPE_INT,
+ .name = "mirror_source_port",
+ .description = "Mirror source port",
+ .set = ar8xxx_sw_set_mirror_source_port,
+ .get = ar8xxx_sw_get_mirror_source_port,
+ .max = AR8216_NUM_PORTS - 1
+ },
+};
+static struct switch_attr ar8327_sw_attr_globals[] = {
+ {
+ .type = SWITCH_TYPE_INT,
+ .name = "enable_vlan",
+ .description = "Enable VLAN mode",
+ .set = ar8xxx_sw_set_vlan,
+ .get = ar8xxx_sw_get_vlan,
+ .max = 1
+ },
+ {
+ .type = SWITCH_TYPE_NOVAL,
+ .name = "reset_mibs",
+ .description = "Reset all MIB counters",
+ .set = ar8xxx_sw_set_reset_mibs,
+ },
+ {
+ .type = SWITCH_TYPE_INT,
+ .name = "enable_mirror_rx",
+ .description = "Enable mirroring of RX packets",
+ .set = ar8xxx_sw_set_mirror_rx_enable,
+ .get = ar8xxx_sw_get_mirror_rx_enable,
+ .max = 1
+ },
+ {
+ .type = SWITCH_TYPE_INT,
+ .name = "enable_mirror_tx",
+ .description = "Enable mirroring of TX packets",
+ .set = ar8xxx_sw_set_mirror_tx_enable,
+ .get = ar8xxx_sw_get_mirror_tx_enable,
+ .max = 1
+ },
+ {
+ .type = SWITCH_TYPE_INT,
+ .name = "mirror_monitor_port",
+ .description = "Mirror monitor port",
+ .set = ar8xxx_sw_set_mirror_monitor_port,
+ .get = ar8xxx_sw_get_mirror_monitor_port,
+ .max = AR8327_NUM_PORTS - 1
+ },
+ {
+ .type = SWITCH_TYPE_INT,
+ .name = "mirror_source_port",
+ .description = "Mirror source port",
+ .set = ar8xxx_sw_set_mirror_source_port,
+ .get = ar8xxx_sw_get_mirror_source_port,
+ .max = AR8327_NUM_PORTS - 1
+ },
};
-static struct switch_attr ar8216_port[] = {
+static struct switch_attr ar8xxx_sw_attr_port[] = {
{
.type = SWITCH_TYPE_NOVAL,
.name = "reset_mib",
.description = "Reset single port MIB counters",
- .set = ar8216_sw_set_port_reset_mib,
+ .set = ar8xxx_sw_set_port_reset_mib,
},
{
.type = SWITCH_TYPE_STRING,
.name = "mib",
.description = "Get port's MIB counters",
.set = NULL,
- .get = ar8216_sw_get_port_mib,
+ .get = ar8xxx_sw_get_port_mib,
},
};
-static struct switch_attr ar8216_vlan[] = {
+static struct switch_attr ar8xxx_sw_attr_vlan[] = {
{
.type = SWITCH_TYPE_INT,
.name = "vid",
.description = "VLAN ID (0-4094)",
- .set = ar8216_sw_set_vid,
- .get = ar8216_sw_get_vid,
+ .set = ar8xxx_sw_set_vid,
+ .get = ar8xxx_sw_get_vid,
.max = 4094,
},
};
-static const struct switch_dev_ops ar8216_sw_ops = {
+static const struct switch_dev_ops ar8xxx_sw_ops = {
+ .attr_global = {
+ .attr = ar8xxx_sw_attr_globals,
+ .n_attr = ARRAY_SIZE(ar8xxx_sw_attr_globals),
+ },
+ .attr_port = {
+ .attr = ar8xxx_sw_attr_port,
+ .n_attr = ARRAY_SIZE(ar8xxx_sw_attr_port),
+ },
+ .attr_vlan = {
+ .attr = ar8xxx_sw_attr_vlan,
+ .n_attr = ARRAY_SIZE(ar8xxx_sw_attr_vlan),
+ },
+ .get_port_pvid = ar8xxx_sw_get_pvid,
+ .set_port_pvid = ar8xxx_sw_set_pvid,
+ .get_vlan_ports = ar8xxx_sw_get_ports,
+ .set_vlan_ports = ar8xxx_sw_set_ports,
+ .apply_config = ar8xxx_sw_hw_apply,
+ .reset_switch = ar8xxx_sw_reset_switch,
+ .get_port_link = ar8xxx_sw_get_port_link,
+};
+
+static const struct switch_dev_ops ar8327_sw_ops = {
.attr_global = {
- .attr = ar8216_globals,
- .n_attr = ARRAY_SIZE(ar8216_globals),
+ .attr = ar8327_sw_attr_globals,
+ .n_attr = ARRAY_SIZE(ar8327_sw_attr_globals),
},
.attr_port = {
- .attr = ar8216_port,
- .n_attr = ARRAY_SIZE(ar8216_port),
+ .attr = ar8xxx_sw_attr_port,
+ .n_attr = ARRAY_SIZE(ar8xxx_sw_attr_port),
},
.attr_vlan = {
- .attr = ar8216_vlan,
- .n_attr = ARRAY_SIZE(ar8216_vlan),
+ .attr = ar8xxx_sw_attr_vlan,
+ .n_attr = ARRAY_SIZE(ar8xxx_sw_attr_vlan),
},
- .get_port_pvid = ar8216_sw_get_pvid,
- .set_port_pvid = ar8216_sw_set_pvid,
- .get_vlan_ports = ar8216_sw_get_ports,
- .set_vlan_ports = ar8216_sw_set_ports,
- .apply_config = ar8216_sw_hw_apply,
- .reset_switch = ar8216_sw_reset_switch,
- .get_port_link = ar8216_sw_get_port_link,
+ .get_port_pvid = ar8xxx_sw_get_pvid,
+ .set_port_pvid = ar8xxx_sw_set_pvid,
+ .get_vlan_ports = ar8xxx_sw_get_ports,
+ .set_vlan_ports = ar8xxx_sw_set_ports,
+ .apply_config = ar8xxx_sw_hw_apply,
+ .reset_switch = ar8xxx_sw_reset_switch,
+ .get_port_link = ar8xxx_sw_get_port_link,
};
static int
-ar8216_id_chip(struct ar8216_priv *priv)
+ar8xxx_id_chip(struct ar8xxx_priv *priv)
{
u32 val;
u16 id;
static void
ar8xxx_mib_work_func(struct work_struct *work)
{
- struct ar8216_priv *priv;
+ struct ar8xxx_priv *priv;
int err;
- priv = container_of(work, struct ar8216_priv, mib_work.work);
+ priv = container_of(work, struct ar8xxx_priv, mib_work.work);
mutex_lock(&priv->mib_lock);
- err = ar8216_mib_capture(priv);
+ err = ar8xxx_mib_capture(priv);
if (err)
goto next_port;
- ar8216_mib_fetch_port_stat(priv, priv->mib_next_port, false);
+ ar8xxx_mib_fetch_port_stat(priv, priv->mib_next_port, false);
next_port:
priv->mib_next_port++;
}
static int
-ar8xxx_mib_init(struct ar8216_priv *priv)
+ar8xxx_mib_init(struct ar8xxx_priv *priv)
{
unsigned int len;
}
static void
-ar8xxx_mib_start(struct ar8216_priv *priv)
+ar8xxx_mib_start(struct ar8xxx_priv *priv)
{
if (!ar8xxx_has_mib_counters(priv))
return;
}
static void
-ar8xxx_mib_stop(struct ar8216_priv *priv)
+ar8xxx_mib_stop(struct ar8xxx_priv *priv)
{
if (!ar8xxx_has_mib_counters(priv))
return;
cancel_delayed_work(&priv->mib_work);
}
-static struct ar8216_priv *
+static struct ar8xxx_priv *
ar8xxx_create(void)
{
- struct ar8216_priv *priv;
+ struct ar8xxx_priv *priv;
- priv = kzalloc(sizeof(struct ar8216_priv), GFP_KERNEL);
+ priv = kzalloc(sizeof(struct ar8xxx_priv), GFP_KERNEL);
if (priv == NULL)
return NULL;
}
static void
-ar8xxx_free(struct ar8216_priv *priv)
+ar8xxx_free(struct ar8xxx_priv *priv)
{
kfree(priv->mib_stats);
kfree(priv);
}
-static struct ar8216_priv *
+static struct ar8xxx_priv *
ar8xxx_create_mii(struct mii_bus *bus)
{
- struct ar8216_priv *priv;
+ struct ar8xxx_priv *priv;
priv = ar8xxx_create();
if (priv) {
priv->mii_bus = bus;
- priv->read = ar8216_mii_read;
- priv->write = ar8216_mii_write;
+ priv->read = ar8xxx_mii_read;
+ priv->write = ar8xxx_mii_write;
}
return priv;
}
static int
-ar8xxx_probe_switch(struct ar8216_priv *priv)
+ar8xxx_probe_switch(struct ar8xxx_priv *priv)
{
struct switch_dev *swdev;
int ret;
- ret = ar8216_id_chip(priv);
+ ret = ar8xxx_id_chip(priv);
if (ret)
return ret;
swdev = &priv->dev;
swdev->cpu_port = AR8216_PORT_CPU;
- swdev->ops = &ar8216_sw_ops;
+ swdev->ops = &ar8xxx_sw_ops;
if (chip_is_ar8316(priv)) {
swdev->name = "Atheros AR8316";
swdev->name = "Atheros AR8327";
swdev->vlans = AR8X16_MAX_VLANS;
swdev->ports = AR8327_NUM_PORTS;
+ swdev->ops = &ar8327_sw_ops;
} else {
swdev->name = "Atheros AR8216";
swdev->vlans = AR8216_NUM_VLANS;
}
static int
-ar8216_config_init(struct phy_device *phydev)
+ar8xxx_start(struct ar8xxx_priv *priv)
{
- struct ar8216_priv *priv = phydev->priv;
+ int ret;
+
+ priv->init = true;
+
+ ret = priv->chip->hw_init(priv);
+ if (ret)
+ return ret;
+
+ ret = ar8xxx_sw_reset_switch(&priv->dev);
+ if (ret)
+ return ret;
+
+ priv->init = false;
+
+ ar8xxx_mib_start(priv);
+
+ return 0;
+}
+
+static int
+ar8xxx_phy_config_init(struct phy_device *phydev)
+{
+ struct ar8xxx_priv *priv = phydev->priv;
struct net_device *dev = phydev->attached_dev;
- struct switch_dev *swdev;
int ret;
if (WARN_ON(!priv))
return -ENODEV;
+ if (chip_is_ar8327(priv))
+ return 0;
+
priv->phy = phydev;
if (phydev->addr != 0) {
return 0;
}
- swdev = &priv->dev;
- swdev->alias = dev_name(&priv->mii_bus->dev);
- ret = register_switch(swdev, NULL);
- if (ret)
- goto err;
-
- pr_info("%s: %s switch registered on %s\n",
- swdev->devname, swdev->name, dev_name(&priv->mii_bus->dev));
-
- priv->init = true;
-
- ret = priv->chip->hw_init(priv);
- if (ret)
- goto err_unregister_switch;
-
- ret = ar8216_sw_reset_switch(&priv->dev);
+ ret = ar8xxx_start(priv);
if (ret)
- goto err_unregister_switch;
+ return ret;
/* VID fixup only needed on ar8216 */
if (chip_is_ar8216(priv)) {
dev->eth_mangle_tx = ar8216_mangle_tx;
}
- priv->init = false;
-
- ar8xxx_mib_start(priv);
-
return 0;
-
-err_unregister_switch:
- unregister_switch(&priv->dev);
-err:
- return ret;
}
static int
-ar8216_read_status(struct phy_device *phydev)
+ar8xxx_phy_read_status(struct phy_device *phydev)
{
- struct ar8216_priv *priv = phydev->priv;
+ struct ar8xxx_priv *priv = phydev->priv;
struct switch_port_link link;
int ret;
}
static int
-ar8216_config_aneg(struct phy_device *phydev)
+ar8xxx_phy_config_aneg(struct phy_device *phydev)
{
if (phydev->addr == 0)
return 0;
static const u32 ar8xxx_phy_ids[] = {
0x004dd033,
+ 0x004dd034,
0x004dd041,
0x004dd042,
};
}
static int
-ar8216_probe(struct phy_device *phydev)
+ar8xxx_phy_probe(struct phy_device *phydev)
{
- struct ar8216_priv *priv;
+ struct ar8xxx_priv *priv;
+ struct switch_dev *swdev;
int ret;
/* skip PHYs at unused adresses */
if (ret)
goto free_priv;
+ swdev = &priv->dev;
+ swdev->alias = dev_name(&priv->mii_bus->dev);
+ ret = register_switch(swdev, NULL);
+ if (ret)
+ goto free_priv;
+
+ pr_info("%s: %s rev. %u switch registered on %s\n",
+ swdev->devname, swdev->name, priv->chip_rev,
+ dev_name(&priv->mii_bus->dev));
+
found:
+ priv->use_count++;
+
if (phydev->addr == 0) {
if (ar8xxx_has_gige(priv)) {
phydev->supported = SUPPORTED_1000baseT_Full;
phydev->supported = SUPPORTED_100baseT_Full;
phydev->advertising = ADVERTISED_100baseT_Full;
}
+
+ if (chip_is_ar8327(priv)) {
+ priv->phy = phydev;
+
+ ret = ar8xxx_start(priv);
+ if (ret)
+ goto err_unregister_switch;
+ }
} else {
if (ar8xxx_has_gige(priv)) {
phydev->supported |= SUPPORTED_1000baseT_Full;
}
phydev->priv = priv;
- priv->use_count++;
list_add(&priv->list, &ar8xxx_dev_list);
return 0;
+err_unregister_switch:
+ if (--priv->use_count)
+ goto unlock;
+
+ unregister_switch(&priv->dev);
+
free_priv:
ar8xxx_free(priv);
unlock:
}
static void
-ar8216_detach(struct phy_device *phydev)
+ar8xxx_phy_detach(struct phy_device *phydev)
{
struct net_device *dev = phydev->attached_dev;
}
static void
-ar8216_remove(struct phy_device *phydev)
+ar8xxx_phy_remove(struct phy_device *phydev)
{
- struct ar8216_priv *priv = phydev->priv;
+ struct ar8xxx_priv *priv = phydev->priv;
if (WARN_ON(!priv))
return;
ar8xxx_free(priv);
}
-static struct phy_driver ar8216_driver = {
+static struct phy_driver ar8xxx_phy_driver = {
.phy_id = 0x004d0000,
.name = "Atheros AR8216/AR8236/AR8316",
.phy_id_mask = 0xffff0000,
.features = PHY_BASIC_FEATURES,
- .probe = ar8216_probe,
- .remove = ar8216_remove,
- .detach = ar8216_detach,
- .config_init = &ar8216_config_init,
- .config_aneg = &ar8216_config_aneg,
- .read_status = &ar8216_read_status,
+ .probe = ar8xxx_phy_probe,
+ .remove = ar8xxx_phy_remove,
+ .detach = ar8xxx_phy_detach,
+ .config_init = ar8xxx_phy_config_init,
+ .config_aneg = ar8xxx_phy_config_aneg,
+ .read_status = ar8xxx_phy_read_status,
.driver = { .owner = THIS_MODULE },
};
int __init
-ar8216_init(void)
+ar8xxx_init(void)
{
- return phy_driver_register(&ar8216_driver);
+ return phy_driver_register(&ar8xxx_phy_driver);
}
void __exit
-ar8216_exit(void)
+ar8xxx_exit(void)
{
- phy_driver_unregister(&ar8216_driver);
+ phy_driver_unregister(&ar8xxx_phy_driver);
}
-module_init(ar8216_init);
-module_exit(ar8216_exit);
+module_init(ar8xxx_init);
+module_exit(ar8xxx_exit);
MODULE_LICENSE("GPL");