aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/generic
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2015-07-15 08:17:23 +0000
committerFelix Fietkau <nbd@openwrt.org>2015-07-15 08:17:23 +0000
commit2666403c3a850088a440d65f1a49004f1e9d926c (patch)
treedaf9fd32309fd2492ca71df4839b96ea56cb80eb /target/linux/generic
parent52ea491bdf6c57fdd60c5ffc268af3bd67c35103 (diff)
downloadupstream-2666403c3a850088a440d65f1a49004f1e9d926c.tar.gz
upstream-2666403c3a850088a440d65f1a49004f1e9d926c.tar.bz2
upstream-2666403c3a850088a440d65f1a49004f1e9d926c.zip
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 <hkallweit1@gmail.com> SVN-Revision: 46379
Diffstat (limited to 'target/linux/generic')
-rw-r--r--target/linux/generic/files/drivers/net/phy/ar8216.c81
-rw-r--r--target/linux/generic/files/drivers/net/phy/ar8216.h25
2 files changed, 98 insertions, 8 deletions
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;
}
@@ -702,6 +702,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)
{
u32 egress, ingress;
@@ -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)