X-Git-Url: https://git.archive.openwrt.org/?a=blobdiff_plain;f=target%2Flinux%2Fgeneric%2Ffiles%2Fdrivers%2Fnet%2Fphy%2Far8216.c;h=b6df6425acf20828770a6df066291e6cdcdea379;hb=c7f3f603795f07fcb7c6c4f6bfa9c74280726bac;hp=b1791172e01d29a59c89c2d7dee9c6aff515de84;hpb=38d421179ae10e82c6fb7dc235c2231bb2d1c264;p=openwrt.git diff --git a/target/linux/generic/files/drivers/net/phy/ar8216.c b/target/linux/generic/files/drivers/net/phy/ar8216.c index b1791172e0..b6df6425ac 100644 --- a/target/linux/generic/files/drivers/net/phy/ar8216.c +++ b/target/linux/generic/files/drivers/net/phy/ar8216.c @@ -33,6 +33,8 @@ #include #include #include +#include + #include "ar8216.h" /* size of the vlan table */ @@ -42,7 +44,7 @@ #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) @@ -63,32 +65,40 @@ struct ar8xxx_mib_desc { 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); 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]; @@ -110,6 +120,12 @@ struct ar8216_priv { 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) \ @@ -204,38 +220,38 @@ static const struct ar8xxx_mib_desc ar8236_mibs[] = { 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; } @@ -254,7 +270,7 @@ split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page) } 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; @@ -275,7 +291,7 @@ ar8216_mii_read(struct ar8216_priv *priv, int reg) } 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; @@ -301,7 +317,7 @@ ar8216_mii_write(struct ar8216_priv *priv, int reg, u32 val) } 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; @@ -313,7 +329,7 @@ ar8216_phy_dbg_write(struct ar8216_priv *priv, int phy_addr, } 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; @@ -324,7 +340,7 @@ ar8216_phy_mmd_write(struct ar8216_priv *priv, int phy_addr, u16 addr, u16 data) } 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; @@ -339,7 +355,7 @@ ar8216_rmw(struct ar8216_priv *priv, int reg, u32 mask, u32 val) } 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; @@ -351,7 +367,7 @@ ar8216_reg_set(struct ar8216_priv *priv, int reg, u32 val) } 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; @@ -370,7 +386,7 @@ ar8216_reg_wait(struct ar8216_priv *priv, u32 reg, u32 mask, u32 val, } 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; @@ -384,11 +400,11 @@ ar8216_mib_op(struct ar8216_priv *priv, u32 op) 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; @@ -399,19 +415,19 @@ 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; @@ -451,7 +467,7 @@ ar8216_mib_fetch_port_stat(struct ar8216_priv *priv, int port, bool flush) } 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; @@ -496,7 +512,7 @@ ar8216_read_port_link(struct ar8216_priv *priv, int port, 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)) @@ -525,7 +541,7 @@ error: 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; @@ -560,7 +576,7 @@ ar8216_mangle_rx(struct net_device *dev, struct sk_buff *skb) } 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; @@ -582,7 +598,7 @@ ar8216_wait_bit(struct ar8216_priv *priv, int reg, u32 mask, u32 val) } 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; @@ -596,13 +612,13 @@ ar8216_vtu_op(struct ar8216_priv *priv, u32 op, u32 val) } 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; @@ -611,7 +627,7 @@ ar8216_vtu_load_vlan(struct ar8216_priv *priv, u32 vid, u32 port_mask) } static int -ar8216_atu_flush(struct ar8216_priv *priv) +ar8216_atu_flush(struct ar8xxx_priv *priv) { int ret; @@ -623,13 +639,13 @@ ar8216_atu_flush(struct ar8216_priv *priv) } 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; @@ -639,7 +655,7 @@ ar8216_setup_port(struct ar8216_priv *priv, int port, u32 egress, u32 ingress, 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, @@ -647,7 +663,7 @@ ar8216_setup_port(struct ar8216_priv *priv, int port, u32 egress, u32 ingress, (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) | @@ -656,23 +672,23 @@ ar8216_setup_port(struct ar8216_priv *priv, int port, u32 egress, u32 ingress, } 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), @@ -714,10 +730,10 @@ static const struct ar8xxx_chip ar8216_chip = { }; 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, @@ -725,11 +741,11 @@ ar8236_setup_port(struct ar8216_priv *priv, int port, u32 egress, u32 ingress, (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) | @@ -737,7 +753,7 @@ ar8236_setup_port(struct ar8216_priv *priv, int port, u32 egress, u32 ingress, } static int -ar8236_hw_init(struct ar8216_priv *priv) +ar8236_hw_init(struct ar8xxx_priv *priv) { int i; struct mii_bus *bus; @@ -760,14 +776,14 @@ ar8236_hw_init(struct ar8216_priv *priv) } 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); } @@ -788,7 +804,7 @@ static const struct ar8xxx_chip ar8236_chip = { }; static int -ar8316_hw_init(struct ar8216_priv *priv) +ar8316_hw_init(struct ar8xxx_priv *priv) { int i; u32 val, newval; @@ -820,20 +836,20 @@ ar8316_hw_init(struct ar8216_priv *priv) 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); @@ -849,7 +865,7 @@ out: } static void -ar8316_init_globals(struct ar8216_priv *priv) +ar8316_init_globals(struct ar8xxx_priv *priv) { /* standard atheros magic */ priv->write(priv, 0x38, 0xc000050e); @@ -858,11 +874,11 @@ ar8316_init_globals(struct ar8216_priv *priv) 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); } @@ -977,45 +993,76 @@ ar8327_get_pad_cfg(struct ar8327_pad_cfg *cfg) } 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; + } +} + +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; - ar8216_phy_dbg_write(priv, phy, 0x3d, 0x6860); - ar8216_phy_dbg_write(priv, phy, 0x5, 0x2c46); - ar8216_phy_dbg_write(priv, phy, 0x3c, 0x6000); + 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; + 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); @@ -1044,6 +1091,69 @@ ar8327_hw_init(struct ar8216_priv *priv) 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); @@ -1062,7 +1172,7 @@ ar8327_hw_init(struct ar8216_priv *priv) } static void -ar8327_init_globals(struct ar8216_priv *priv) +ar8327_init_globals(struct ar8xxx_priv *priv) { u32 t; @@ -1078,64 +1188,27 @@ ar8327_init_globals(struct ar8216_priv *priv) 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; @@ -1151,13 +1224,13 @@ ar8327_init_port(struct ar8216_priv *priv, int port) } 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; @@ -1171,7 +1244,7 @@ ar8327_atu_flush(struct ar8216_priv *priv) } 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)) @@ -1185,13 +1258,13 @@ ar8327_vtu_op(struct ar8216_priv *priv, u32 op, u32 val) } 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; @@ -1217,7 +1290,7 @@ ar8327_vtu_load_vlan(struct ar8216_priv *priv, u32 vid, u32 port_mask) } 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; @@ -1267,28 +1340,28 @@ static const struct ar8xxx_chip ar8327_chip = { }; 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 */ @@ -1300,45 +1373,45 @@ ar8216_sw_set_pvid(struct switch_dev *dev, int port, int vlan) } 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; @@ -1360,9 +1433,9 @@ ar8216_sw_get_ports(struct switch_dev *dev, struct switch_val *val) } 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; @@ -1390,10 +1463,102 @@ ar8216_sw_set_ports(struct switch_dev *dev, struct switch_val *val) 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; @@ -1453,19 +1618,22 @@ ar8216_sw_hw_apply(struct switch_dev *dev) 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; @@ -1474,18 +1642,24 @@ ar8216_sw_reset_switch(struct switch_dev *dev) 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; @@ -1497,7 +1671,7 @@ ar8216_sw_set_reset_mibs(struct switch_dev *dev, 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; @@ -1509,11 +1683,111 @@ 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; @@ -1525,11 +1799,11 @@ ar8216_sw_set_port_reset_mib(struct switch_dev *dev, 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; @@ -1539,11 +1813,11 @@ unlock: } 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; @@ -1559,11 +1833,11 @@ ar8216_sw_get_port_mib(struct switch_dev *dev, 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", @@ -1586,75 +1860,177 @@ unlock: 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; @@ -1707,18 +2083,18 @@ ar8216_id_chip(struct ar8216_priv *priv) 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++; @@ -1731,7 +2107,7 @@ next_port: } static int -ar8xxx_mib_init(struct ar8216_priv *priv) +ar8xxx_mib_init(struct ar8xxx_priv *priv) { unsigned int len; @@ -1751,7 +2127,7 @@ ar8xxx_mib_init(struct ar8216_priv *priv) } static void -ar8xxx_mib_start(struct ar8216_priv *priv) +ar8xxx_mib_start(struct ar8xxx_priv *priv) { if (!ar8xxx_has_mib_counters(priv)) return; @@ -1761,7 +2137,7 @@ ar8xxx_mib_start(struct ar8216_priv *priv) } static void -ar8xxx_mib_stop(struct ar8216_priv *priv) +ar8xxx_mib_stop(struct ar8xxx_priv *priv) { if (!ar8xxx_has_mib_counters(priv)) return; @@ -1769,12 +2145,12 @@ ar8xxx_mib_stop(struct ar8216_priv *priv) 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; @@ -1786,40 +2162,40 @@ ar8xxx_create(void) } 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"; @@ -1833,6 +2209,7 @@ ar8xxx_probe_switch(struct ar8216_priv *priv) 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; @@ -1847,32 +2224,44 @@ ar8xxx_probe_switch(struct ar8216_priv *priv) } static int -ar8216_config_init(struct phy_device *phydev) +ar8xxx_start(struct ar8xxx_priv *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 ar8216_priv *priv = phydev->priv; + 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) { if (chip_is_ar8316(priv)) { - /* check if we're attaching to the switch twice */ - phydev = phydev->bus->phy_map[0]; - if (!phydev) - return 0; - - /* switch device has not been initialized, reuse priv */ - if (!phydev->priv) { - priv->port4_phy = true; - priv->dev.ports = (AR8216_NUM_PORTS - 1); - return 0; - } - /* switch device has been initialized, reinit */ priv->dev.ports = (AR8216_NUM_PORTS - 1); priv->initialized = false; @@ -1884,24 +2273,9 @@ ar8216_config_init(struct phy_device *phydev) return 0; } - swdev = &priv->dev; - swdev->alias = dev_name(&priv->mii_bus->dev); - ret = register_switch(swdev, NULL); + ret = ar8xxx_start(priv); 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); - if (ret) - goto err_unregister_switch; + return ret; /* VID fixup only needed on ar8216 */ if (chip_is_ar8216(priv)) { @@ -1911,22 +2285,13 @@ ar8216_config_init(struct phy_device *phydev) 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; @@ -1966,7 +2331,7 @@ ar8216_read_status(struct phy_device *phydev) } static int -ar8216_config_aneg(struct phy_device *phydev) +ar8xxx_phy_config_aneg(struct phy_device *phydev) { if (phydev->addr == 0) return 0; @@ -1976,6 +2341,7 @@ ar8216_config_aneg(struct phy_device *phydev) static const u32 ar8xxx_phy_ids[] = { 0x004dd033, + 0x004dd034, 0x004dd041, 0x004dd042, }; @@ -2013,9 +2379,10 @@ ar8xxx_is_possible(struct mii_bus *bus) } 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 */ @@ -2040,7 +2407,18 @@ ar8216_probe(struct phy_device *phydev) 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 switch registered on %s\n", + swdev->devname, swdev->name, dev_name(&priv->mii_bus->dev)); + found: + priv->use_count++; + if (phydev->addr == 0) { if (ar8xxx_has_gige(priv)) { phydev->supported = SUPPORTED_1000baseT_Full; @@ -2049,6 +2427,14 @@ found: 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; @@ -2057,7 +2443,6 @@ found: } phydev->priv = priv; - priv->use_count++; list_add(&priv->list, &ar8xxx_dev_list); @@ -2065,6 +2450,12 @@ found: return 0; +err_unregister_switch: + if (--priv->use_count) + goto unlock; + + unregister_switch(&priv->dev); + free_priv: ar8xxx_free(priv); unlock: @@ -2073,7 +2464,7 @@ unlock: } static void -ar8216_detach(struct phy_device *phydev) +ar8xxx_phy_detach(struct phy_device *phydev) { struct net_device *dev = phydev->attached_dev; @@ -2087,9 +2478,9 @@ ar8216_detach(struct phy_device *phydev) } 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; @@ -2107,33 +2498,33 @@ ar8216_remove(struct phy_device *phydev) 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");