From: Felix Fietkau Date: Wed, 15 Jul 2015 08:17:23 +0000 (+0000) Subject: ar8216: add reading ARL table for AR8216/AR8236/AR8316 X-Git-Tag: reboot~2474 X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=2666403c3a850088a440d65f1a49004f1e9d926c;p=openwrt%2Fstaging%2Fnoltari.git ar8216: add reading ARL table for AR8216/AR8236/AR8316 Adds the chip-specific part of reading ARL table for AR8216/AR8236/AR8316. It's based on the AR8236 datasheet and compile-tested only as I couldn't find datasheets for AR8216/AR8316 and don't own devices with these chips. The existing ar8216_atu_flush implementation was used for all three chip types, therefore I guess they share a common ATU register layout. More testing would be appreciated. Signed-off-by: Heiner Kallweit SVN-Revision: 46379 --- diff --git a/target/linux/generic/files/drivers/net/phy/ar8216.c b/target/linux/generic/files/drivers/net/phy/ar8216.c index e39d540a25..595f144ddb 100644 --- a/target/linux/generic/files/drivers/net/phy/ar8216.c +++ b/target/linux/generic/files/drivers/net/phy/ar8216.c @@ -598,10 +598,10 @@ ar8216_atu_flush(struct ar8xxx_priv *priv) { int ret; - ret = ar8216_wait_bit(priv, AR8216_REG_ATU, AR8216_ATU_ACTIVE, 0); + ret = ar8216_wait_bit(priv, AR8216_REG_ATU_FUNC0, AR8216_ATU_ACTIVE, 0); if (!ret) - ar8xxx_write(priv, AR8216_REG_ATU, AR8216_ATU_OP_FLUSH | - AR8216_ATU_ACTIVE); + ar8xxx_write(priv, AR8216_REG_ATU_FUNC0, AR8216_ATU_OP_FLUSH | + AR8216_ATU_ACTIVE); return ret; } @@ -701,6 +701,77 @@ ar8216_init_port(struct ar8xxx_priv *priv, int port) } } +static void +ar8216_wait_atu_ready(struct ar8xxx_priv *priv, u16 r2, u16 r1) +{ + int timeout = 20; + + while (ar8xxx_mii_read32(priv, r2, r1) & AR8216_ATU_ACTIVE && --timeout) + udelay(10); + + if (!timeout) + pr_err("ar8216: timeout waiting for atu to become ready\n"); +} + +static void ar8216_get_arl_entry(struct ar8xxx_priv *priv, + struct arl_entry *a, u32 *status, enum arl_op op) +{ + struct mii_bus *bus = priv->mii_bus; + u16 r2, page; + u16 r1_func0, r1_func1, r1_func2; + u32 t, val0, val1, val2; + int i; + + split_addr(AR8216_REG_ATU_FUNC0, &r1_func0, &r2, &page); + r2 |= 0x10; + + r1_func1 = (AR8216_REG_ATU_FUNC1 >> 1) & 0x1e; + r1_func2 = (AR8216_REG_ATU_FUNC2 >> 1) & 0x1e; + + switch (op) { + case AR8XXX_ARL_INITIALIZE: + /* all ATU registers are on the same page + * therefore set page only once + */ + bus->write(bus, 0x18, 0, page); + wait_for_page_switch(); + + ar8216_wait_atu_ready(priv, r2, r1_func0); + + ar8xxx_mii_write32(priv, r2, r1_func0, AR8216_ATU_OP_GET_NEXT); + ar8xxx_mii_write32(priv, r2, r1_func1, 0); + ar8xxx_mii_write32(priv, r2, r1_func2, 0); + break; + case AR8XXX_ARL_GET_NEXT: + t = ar8xxx_mii_read32(priv, r2, r1_func0); + t |= AR8216_ATU_ACTIVE; + ar8xxx_mii_write32(priv, r2, r1_func0, t); + ar8216_wait_atu_ready(priv, r2, r1_func0); + + val0 = ar8xxx_mii_read32(priv, r2, r1_func0); + val1 = ar8xxx_mii_read32(priv, r2, r1_func1); + val2 = ar8xxx_mii_read32(priv, r2, r1_func2); + + *status = (val2 & AR8216_ATU_STATUS) >> AR8216_ATU_STATUS_S; + if (!*status) + break; + + i = 0; + t = AR8216_ATU_PORT0; + while (!(val2 & t) && ++i < priv->dev.ports) + t <<= 1; + + a->port = i; + a->mac[0] = (val0 & AR8216_ATU_ADDR5) >> AR8216_ATU_ADDR5_S; + a->mac[1] = (val0 & AR8216_ATU_ADDR4) >> AR8216_ATU_ADDR4_S; + a->mac[2] = (val1 & AR8216_ATU_ADDR3) >> AR8216_ATU_ADDR3_S; + a->mac[3] = (val1 & AR8216_ATU_ADDR2) >> AR8216_ATU_ADDR2_S; + a->mac[4] = (val1 & AR8216_ATU_ADDR1) >> AR8216_ATU_ADDR1_S; + a->mac[5] = (val1 & AR8216_ATU_ADDR0) >> AR8216_ATU_ADDR0_S; + break; + } +} + static void ar8236_setup_port(struct ar8xxx_priv *priv, int port, u32 members) { @@ -1349,7 +1420,6 @@ ar8xxx_sw_get_arl_table(struct switch_dev *dev, return 0; } - static const struct switch_attr ar8xxx_sw_attr_globals[] = { { .type = SWITCH_TYPE_INT, @@ -1475,6 +1545,7 @@ static const struct ar8xxx_chip ar8216_chip = { .vtu_flush = ar8216_vtu_flush, .vtu_load_vlan = ar8216_vtu_load_vlan, .set_mirror_regs = ar8216_set_mirror_regs, + .get_arl_entry = ar8216_get_arl_entry, .sw_hw_apply = ar8xxx_sw_hw_apply, .num_mibs = ARRAY_SIZE(ar8216_mibs), @@ -1502,6 +1573,7 @@ static const struct ar8xxx_chip ar8236_chip = { .vtu_flush = ar8216_vtu_flush, .vtu_load_vlan = ar8216_vtu_load_vlan, .set_mirror_regs = ar8216_set_mirror_regs, + .get_arl_entry = ar8216_get_arl_entry, .sw_hw_apply = ar8xxx_sw_hw_apply, .num_mibs = ARRAY_SIZE(ar8236_mibs), @@ -1529,6 +1601,7 @@ static const struct ar8xxx_chip ar8316_chip = { .vtu_flush = ar8216_vtu_flush, .vtu_load_vlan = ar8216_vtu_load_vlan, .set_mirror_regs = ar8216_set_mirror_regs, + .get_arl_entry = ar8216_get_arl_entry, .sw_hw_apply = ar8xxx_sw_hw_apply, .num_mibs = ARRAY_SIZE(ar8236_mibs), diff --git a/target/linux/generic/files/drivers/net/phy/ar8216.h b/target/linux/generic/files/drivers/net/phy/ar8216.h index 0f53f23f6e..934a8b5cc1 100644 --- a/target/linux/generic/files/drivers/net/phy/ar8216.h +++ b/target/linux/generic/files/drivers/net/phy/ar8216.h @@ -79,7 +79,7 @@ #define AR8236_VTUDATA_MEMBER BITS(0, 7) #define AR8216_VTUDATA_VALID BIT(11) -#define AR8216_REG_ATU 0x0050 +#define AR8216_REG_ATU_FUNC0 0x0050 #define AR8216_ATU_OP BITS(0, 3) #define AR8216_ATU_OP_NOOP 0x0 #define AR8216_ATU_OP_FLUSH 0x1 @@ -91,14 +91,31 @@ #define AR8216_ATU_ACTIVE BIT(3) #define AR8216_ATU_PORT_NUM BITS(8, 4) #define AR8216_ATU_FULL_VIO BIT(12) -#define AR8216_ATU_ADDR4 BITS(16, 8) -#define AR8216_ATU_ADDR5 BITS(24, 8) +#define AR8216_ATU_ADDR5 BITS(16, 8) +#define AR8216_ATU_ADDR5_S 16 +#define AR8216_ATU_ADDR4 BITS(24, 8) +#define AR8216_ATU_ADDR4_S 24 -#define AR8216_REG_ATU_DATA 0x0054 +#define AR8216_REG_ATU_FUNC1 0x0054 #define AR8216_ATU_ADDR3 BITS(0, 8) +#define AR8216_ATU_ADDR3_S 0 #define AR8216_ATU_ADDR2 BITS(8, 8) +#define AR8216_ATU_ADDR2_S 8 #define AR8216_ATU_ADDR1 BITS(16, 8) +#define AR8216_ATU_ADDR1_S 16 #define AR8216_ATU_ADDR0 BITS(24, 8) +#define AR8216_ATU_ADDR0_S 24 + +#define AR8216_REG_ATU_FUNC2 0x0058 +#define AR8216_ATU_PORTS BITS(0, 6) +#define AR8216_ATU_PORT0 BIT(0) +#define AR8216_ATU_PORT1 BIT(1) +#define AR8216_ATU_PORT2 BIT(2) +#define AR8216_ATU_PORT3 BIT(3) +#define AR8216_ATU_PORT4 BIT(4) +#define AR8216_ATU_PORT5 BIT(5) +#define AR8216_ATU_STATUS BITS(16, 4) +#define AR8216_ATU_STATUS_S 16 #define AR8216_REG_ATU_CTRL 0x005C #define AR8216_ATU_CTRL_AGE_EN BIT(17)