[OpenWrt-Devel,1/4] ar8216: add reading ARL table for AR8216/AR8236/AR8316
diff mbox

Message ID 54CCA024.2050101@gmail.com
State Accepted
Delegated to: Felix Fietkau
Headers show

Commit Message

Heiner Kallweit Jan. 31, 2015, 9:28 a.m. UTC
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>
---
 .../linux/generic/files/drivers/net/phy/ar8216.c   | 81 ++++++++++++++++++++--
 .../linux/generic/files/drivers/net/phy/ar8216.h   | 25 +++++--
 2 files changed, 98 insertions(+), 8 deletions(-)

Comments

Chris Green Jan. 31, 2015, 10:52 a.m. UTC | #1
On Sat, Jan 31, 2015 at 10:28:04AM +0100, Heiner Kallweit wrote:
> 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.
> 
Does this relate to the issues I (and others) had with Mikrotek
Routerboard swithces not working?

I.e. would it be useful if I download and try the latest code?

(in my case I have an RB2011UiAS-2HnD)
Heiner Kallweit Jan. 31, 2015, 11:11 a.m. UTC | #2
Am 31.01.2015 um 11:52 schrieb Chris Green:
> On Sat, Jan 31, 2015 at 10:28:04AM +0100, Heiner Kallweit wrote:
>> 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.
>>
> Does this relate to the issues I (and others) had with Mikrotek
> Routerboard swithces not working?
No. IIRC the Routerboard issues were related to some misconfigured clock
in the SoC. Please check the list archive.
> I.e. would it be useful if I download and try the latest code?
> 
> (in my case I have an RB2011UiAS-2HnD)
>
Chris Green Jan. 31, 2015, 11:57 a.m. UTC | #3
On Sat, Jan 31, 2015 at 12:11:32PM +0100, Heiner Kallweit wrote:
> Am 31.01.2015 um 11:52 schrieb Chris Green:
> > On Sat, Jan 31, 2015 at 10:28:04AM +0100, Heiner Kallweit wrote:
> >> 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.
> >>
> > Does this relate to the issues I (and others) had with Mikrotek
> > Routerboard swithces not working?
> No. IIRC the Routerboard issues were related to some misconfigured clock
> in the SoC. Please check the list archive.

OK, sorry, yes I have still got the discussion about this in my local
E-Mail.  I just wanted to be sure.

I'm also not sure if the fixes for the misconfigured clock got into
the current CC tree, that's really why I asked this question.  It
would be a pity if the fixes for Routerboard got lost.

Patch
diff mbox

diff --git a/target/linux/generic/files/drivers/net/phy/ar8216.c b/target/linux/generic/files/drivers/net/phy/ar8216.c
index e39d540..595f144 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 0f53f23..934a8b5 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)