[LEDE-DEV] [PATCH v2] ar8327: Add workarounds for AR8337 switch.

2017-03-26 Thread Vittorio Gambaletta (VittGam)
RGMII RX delay setting needs to be always specified for AR8337 to
avoid port 5 RX hang on high traffic / flood conditions.

Also, the HOL registers that set per-port and per-packet-priority
buffer sizes are updated with the reduced values suggested by the
QCA switch team.

Finally, AR8327 reserved register fixups are disabled for the AR8337.

This patch is adapted from the Code Aurora QSDK, but with magic
values mapped to proper defines.

Signed-off-by: Vittorio Gambaletta 

---
 .../linux/generic/files/drivers/net/phy/ar8327.c   |   43 +++-
 .../linux/generic/files/drivers/net/phy/ar8327.h   |   21 ++
 2 files changed, 63 insertions(+), 1 deletion(-)

diff --git a/target/linux/generic/files/drivers/net/phy/ar8327.c 
b/target/linux/generic/files/drivers/net/phy/ar8327.c
index 8e67f4b..97cee29 100644
--- a/target/linux/generic/files/drivers/net/phy/ar8327.c
+++ b/target/linux/generic/files/drivers/net/phy/ar8327.c
@@ -506,6 +506,14 @@ ar8327_hw_config_pdata(struct ar8xxx_priv *priv,
ar8xxx_write(priv, AR8327_REG_PAD0_MODE, t);
 
t = ar8327_get_pad_cfg(pdata->pad5_cfg);
+   if (chip_is_ar8337(priv)) {
+   /*
+* Workaround: RGMII RX delay setting needs to be
+* always specified for AR8337 to avoid port 5
+* RX hang on high traffic / flood conditions
+*/
+   t |= AR8327_PAD_RGMII_RXCLK_DELAY_EN;
+   }
ar8xxx_write(priv, AR8327_REG_PAD5_MODE, t);
t = ar8327_get_pad_cfg(pdata->pad6_cfg);
ar8xxx_write(priv, AR8327_REG_PAD6_MODE, t);
@@ -670,6 +678,39 @@ ar8327_init_globals(struct ar8xxx_priv *priv)
/* Disable EEE on all phy's due to stability issues */
for (i = 0; i < AR8XXX_NUM_PHYS; i++)
data->eee[i] = false;
+
+   if (chip_is_ar8337(priv)) {
+   /* Update HOL registers with values suggested by QCA switch 
team */
+   for (i = 0; i < AR8327_NUM_PORTS; i++) {
+   if (i == AR8216_PORT_CPU || i == 5 || i == 6) {
+   t = 0x3 << AR8327_PORT_HOL_CTRL0_EG_PRI0_BUF_S;
+   t |= 0x4 << AR8327_PORT_HOL_CTRL0_EG_PRI1_BUF_S;
+   t |= 0x4 << AR8327_PORT_HOL_CTRL0_EG_PRI2_BUF_S;
+   t |= 0x4 << AR8327_PORT_HOL_CTRL0_EG_PRI3_BUF_S;
+   t |= 0x6 << AR8327_PORT_HOL_CTRL0_EG_PRI4_BUF_S;
+   t |= 0x8 << AR8327_PORT_HOL_CTRL0_EG_PRI5_BUF_S;
+   t |= 0x1e << 
AR8327_PORT_HOL_CTRL0_EG_PORT_BUF_S;
+   } else {
+   t = 0x3 << AR8327_PORT_HOL_CTRL0_EG_PRI0_BUF_S;
+   t |= 0x4 << AR8327_PORT_HOL_CTRL0_EG_PRI1_BUF_S;
+   t |= 0x6 << AR8327_PORT_HOL_CTRL0_EG_PRI2_BUF_S;
+   t |= 0x8 << AR8327_PORT_HOL_CTRL0_EG_PRI3_BUF_S;
+   t |= 0x19 << 
AR8327_PORT_HOL_CTRL0_EG_PORT_BUF_S;
+   }
+   ar8xxx_write(priv, AR8327_REG_PORT_HOL_CTRL0(i), t);
+
+   t = 0x6 << AR8327_PORT_HOL_CTRL1_ING_BUF_S;
+   t |= AR8327_PORT_HOL_CTRL1_EG_PRI_BUF_EN;
+   t |= AR8327_PORT_HOL_CTRL1_EG_PORT_BUF_EN;
+   t |= AR8327_PORT_HOL_CTRL1_WRED_EN;
+   ar8xxx_rmw(priv, AR8327_REG_PORT_HOL_CTRL1(i),
+  AR8327_PORT_HOL_CTRL1_ING_BUF |
+  AR8327_PORT_HOL_CTRL1_EG_PRI_BUF_EN |
+  AR8327_PORT_HOL_CTRL1_EG_PORT_BUF_EN |
+  AR8327_PORT_HOL_CTRL1_WRED_EN,
+  t);
+   }
+   }
 }
 
 static void
@@ -1397,7 +1438,7 @@ const struct ar8xxx_chip ar8327_chip = {
.atu_flush_port = ar8327_atu_flush_port,
.vtu_flush = ar8327_vtu_flush,
.vtu_load_vlan = ar8327_vtu_load_vlan,
-   .phy_fixup = ar8327_phy_fixup,
+   //.phy_fixup = ar8337_phy_fixup, // not needed at the moment
.set_mirror_regs = ar8327_set_mirror_regs,
.get_arl_entry = ar8327_get_arl_entry,
.sw_hw_apply = ar8327_sw_hw_apply,
diff --git a/target/linux/generic/files/drivers/net/phy/ar8327.h 
b/target/linux/generic/files/drivers/net/phy/ar8327.h
index 7bce18b..828dd28 100644
--- a/target/linux/generic/files/drivers/net/phy/ar8327.h
+++ b/target/linux/generic/files/drivers/net/phy/ar8327.h
@@ -272,7 +272,28 @@
 
 #define AR8327_REG_PORT_PRIO(_i)   (0x664 + (_i) * 0xc)
 
+#define AR8327_REG_PORT_HOL_CTRL0(_i)  (0x970 + (_i) * 0x8)
+#define   AR8327_PORT_HOL_CTRL0_EG_PRI0_BUFBITS(0, 4)
+#define   AR8327_PORT_HOL_CTRL0_EG_PRI0_BUF_S  0
+#define   AR8327_PORT_HOL_CTRL0_EG_PRI1_BUFBITS(4, 4)
+#define   AR8327_PORT_HOL_CTRL0_EG_PRI1_BUF_S  

[LEDE-DEV] [PATCH v2] ar71xx: Add TP-LINK TL-WR841N v12 support.

2017-03-26 Thread Vittorio Gambaletta (VittGam)
This router has the same hardware of TP-LINK TL-WR841N v11 (same
FCC ID, same TFTP image name...).

The stock firmware web interface does not seem to accept the LEDE
factory image, but it can be flashed via the u-boot TFTP recovery
by long-pressing the reset button after power on.

The TFTP image name is wr841nv11_tp_recovery.bin (yes, v11, not v12).

Signed-off-by: Vittorio Gambaletta 

---

diff --git a/target/linux/ar71xx/image/tp-link.mk 
b/target/linux/ar71xx/image/tp-link.mk
index cf2e5e7..cea039d 100644
--- a/target/linux/ar71xx/image/tp-link.mk
+++ b/target/linux/ar71xx/image/tp-link.mk
@@ -736,6 +736,12 @@ define Device/tl-wr841-v11
   IMAGE/factory-eu.bin := append-rootfs | mktplinkfw factory -C EU
 endef
 
+define Device/tl-wr841-v12
+  $(Device/tl-wr841-v11)
+  DEVICE_TITLE := TP-LINK TL-WR841N/ND v12
+  TPLINK_HWID := 0x08410012
+endef
+
 define Device/tl-wr842n-v1
   $(Device/tplink-8m)
   DEVICE_TITLE := TP-LINK TL-WR842N/ND v1
@@ -778,7 +784,7 @@ define Device/tl-wr847n-v8
   DEVICE_PROFILE := TLWR841
   TPLINK_HWID := 0x08470008
 endef
-TARGET_DEVICES += tl-wr840n-v2 tl-wr840n-v3 tl-wr841-v1.5 tl-wr841-v3 
tl-wr841-v5 tl-wr841-v7 tl-wr841-v8 tl-wr841-v9 tl-wr841-v10 tl-wr841-v11 
tl-wr842n-v1 tl-wr842n-v2 tl-wr842n-v3 tl-wr843nd-v1 tl-wr847n-v8
+TARGET_DEVICES += tl-wr840n-v2 tl-wr840n-v3 tl-wr841-v1.5 tl-wr841-v3 
tl-wr841-v5 tl-wr841-v7 tl-wr841-v8 tl-wr841-v9 tl-wr841-v10 tl-wr841-v11 
tl-wr841-v12 tl-wr842n-v1 tl-wr842n-v2 tl-wr842n-v3 tl-wr843nd-v1 tl-wr847n-v8
 
 define Device/tl-wr941nd-v2
   $(Device/tplink-4m)

___
Lede-dev mailing list
Lede-dev@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/lede-dev


[LEDE-DEV] [PATCH] ar71xx: Add TP-LINK TL-WR841N v12 support.

2017-03-25 Thread Vittorio Gambaletta (VittGam)
This router has the same hardware of TP-LINK TL-WR841N v11 (same
FCC ID, same TFTP image name...).

The stock firmware web interface does not seem to accept the LEDE
factory image, but it can be flashed via the u-boot TFTP recovery
by long-pressing the reset button after power on.

The TFTP image name is wr841nv11_tp_recovery.bin (yes, v11, not v12).

Signed-off-by: Vittorio Gambaletta 
---
 target/linux/ar71xx/image/tp-link.mk |   13 -
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/target/linux/ar71xx/image/tp-link.mk 
b/target/linux/ar71xx/image/tp-link.mk
index cf2e5e7..705e400 100644
--- a/target/linux/ar71xx/image/tp-link.mk
+++ b/target/linux/ar71xx/image/tp-link.mk
@@ -736,6 +736,17 @@ define Device/tl-wr841-v11
   IMAGE/factory-eu.bin := append-rootfs | mktplinkfw factory -C EU
 endef
 
+define Device/tl-wr841-v12
+  $(Device/tplink-4mlzma)
+  DEVICE_TITLE := TP-LINK TL-WR841N/ND v12
+  BOARDNAME := TL-WR841N-v11
+  DEVICE_PROFILE := TLWR841
+  TPLINK_HWID := 0x08410012
+  IMAGES += factory-us.bin factory-eu.bin
+  IMAGE/factory-us.bin := append-rootfs | mktplinkfw factory -C US
+  IMAGE/factory-eu.bin := append-rootfs | mktplinkfw factory -C EU
+endef
+
 define Device/tl-wr842n-v1
   $(Device/tplink-8m)
   DEVICE_TITLE := TP-LINK TL-WR842N/ND v1
@@ -778,7 +789,7 @@ define Device/tl-wr847n-v8
   DEVICE_PROFILE := TLWR841
   TPLINK_HWID := 0x08470008
 endef
-TARGET_DEVICES += tl-wr840n-v2 tl-wr840n-v3 tl-wr841-v1.5 tl-wr841-v3 
tl-wr841-v5 tl-wr841-v7 tl-wr841-v8 tl-wr841-v9 tl-wr841-v10 tl-wr841-v11 
tl-wr842n-v1 tl-wr842n-v2 tl-wr842n-v3 tl-wr843nd-v1 tl-wr847n-v8
+TARGET_DEVICES += tl-wr840n-v2 tl-wr840n-v3 tl-wr841-v1.5 tl-wr841-v3 
tl-wr841-v5 tl-wr841-v7 tl-wr841-v8 tl-wr841-v9 tl-wr841-v10 tl-wr841-v11 
tl-wr841-v12 tl-wr842n-v1 tl-wr842n-v2 tl-wr842n-v3 tl-wr843nd-v1 tl-wr847n-v8
 
 define Device/tl-wr941nd-v2
   $(Device/tplink-4m)

___
Lede-dev mailing list
Lede-dev@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/lede-dev


[LEDE-DEV] [PATCH] ag71xx: Fix rx ring buffer stall on small packets flood on qca956x and qca953x.

2017-03-25 Thread Vittorio Gambaletta (VittGam)
Backported from Code Aurora QSDK

Signed-off-by: Vittorio Gambaletta 
---
 .../linux/ar71xx/files/arch/mips/ath79/dev-eth.c   |5 +
 .../mips/include/asm/mach-ath79/ag71xx_platform.h  |2 +-
 .../net/ethernet/atheros/ag71xx/ag71xx_main.c  |   16 
 3 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/target/linux/ar71xx/files/arch/mips/ath79/dev-eth.c 
b/target/linux/ar71xx/files/arch/mips/ath79/dev-eth.c
index a8b19b6..427de6a 100644
--- a/target/linux/ar71xx/files/arch/mips/ath79/dev-eth.c
+++ b/target/linux/ar71xx/files/arch/mips/ath79/dev-eth.c
@@ -996,6 +996,9 @@ void __init ath79_register_eth(unsigned int id)
pdata->reset_bit = AR934X_RESET_GE0_MAC |
   AR934X_RESET_GE0_MDIO;
pdata->set_speed = ar934x_set_speed_ge0;
+
+   if (ath79_soc == ATH79_SOC_QCA9533)
+   pdata->disable_inline_checksum_engine = 1;
} else {
pdata->reset_bit = AR934X_RESET_GE1_MAC |
   AR934X_RESET_GE1_MDIO;
@@ -1097,6 +1100,8 @@ void __init ath79_register_eth(unsigned int id)
pdata->set_speed = qca956x_set_speed_sgmii;
else
pdata->set_speed = ar934x_set_speed_ge0;
+
+   pdata->disable_inline_checksum_engine = 1;
} else {
pdata->reset_bit = QCA955X_RESET_GE1_MAC |
   QCA955X_RESET_GE1_MDIO;
diff --git 
a/target/linux/ar71xx/files/arch/mips/include/asm/mach-ath79/ag71xx_platform.h 
b/target/linux/ar71xx/files/arch/mips/include/asm/mach-ath79/ag71xx_platform.h
index 078fa15..5fdc59c 100644
--- 
a/target/linux/ar71xx/files/arch/mips/include/asm/mach-ath79/ag71xx_platform.h
+++ 
b/target/linux/ar71xx/files/arch/mips/include/asm/mach-ath79/ag71xx_platform.h
@@ -37,7 +37,7 @@ struct ag71xx_platform_data {
u8  is_ar724x:1;
u8  has_ar8216:1;
u8  use_flow_control:1;
-   u8  is_qca956x:1;
+   u8  disable_inline_checksum_engine:1;
 
struct ag71xx_switch_platform_data *switch_data;
 
diff --git 
a/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c 
b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c
index 566e951..72dd654 100644
--- 
a/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c
+++ 
b/target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c
@@ -629,6 +629,22 @@ __ag71xx_link_adjust(struct ag71xx *ag, bool update)
ag71xx_wr(ag, AG71XX_REG_MAC_CFG2, cfg2);
ag71xx_wr(ag, AG71XX_REG_FIFO_CFG5, fifo5);
ag71xx_wr(ag, AG71XX_REG_MAC_IFCTL, ifctl);
+
+   if (pdata->disable_inline_checksum_engine) {
+   /*
+* The rx ring buffer can stall on small packets on QCA953x and
+* QCA956x. Disabling the inline checksum engine fixes the 
stall.
+* The wr, rr functions cannot be used since this hidden 
register
+* is outside of the normal ag71xx register block.
+*/
+   void __iomem *dam = ioremap_nocache(0xb90001bc, 0x4);
+   if (dam) {
+   __raw_writel(__raw_readl(dam) & ~BIT(27), dam);
+   (void)__raw_readl(dam);
+   iounmap(dam);
+   }
+   }
+
ag71xx_hw_start(ag);
 
netif_carrier_on(ag->dev);

___
Lede-dev mailing list
Lede-dev@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/lede-dev


[LEDE-DEV] [PATCH] ar8327: Add workarounds for AR8337 switch.

2017-03-25 Thread Vittorio Gambaletta (VittGam)
Backported from Code Aurora QSDK

Signed-off-by: Vittorio Gambaletta 
---
 .../linux/generic/files/drivers/net/phy/ar8327.c   |   43 +++-
 .../linux/generic/files/drivers/net/phy/ar8327.h   |   21 ++
 2 files changed, 63 insertions(+), 1 deletion(-)

diff --git a/target/linux/generic/files/drivers/net/phy/ar8327.c 
b/target/linux/generic/files/drivers/net/phy/ar8327.c
index 8e67f4b..97cee29 100644
--- a/target/linux/generic/files/drivers/net/phy/ar8327.c
+++ b/target/linux/generic/files/drivers/net/phy/ar8327.c
@@ -506,6 +506,14 @@ ar8327_hw_config_pdata(struct ar8xxx_priv *priv,
ar8xxx_write(priv, AR8327_REG_PAD0_MODE, t);
 
t = ar8327_get_pad_cfg(pdata->pad5_cfg);
+   if (chip_is_ar8337(priv)) {
+   /*
+* Workaround: RGMII RX delay setting needs to be
+* always specified for AR8337 to avoid port 5
+* RX hang on high traffic / flood conditions
+*/
+   t |= AR8327_PAD_RGMII_RXCLK_DELAY_EN;
+   }
ar8xxx_write(priv, AR8327_REG_PAD5_MODE, t);
t = ar8327_get_pad_cfg(pdata->pad6_cfg);
ar8xxx_write(priv, AR8327_REG_PAD6_MODE, t);
@@ -670,6 +678,39 @@ ar8327_init_globals(struct ar8xxx_priv *priv)
/* Disable EEE on all phy's due to stability issues */
for (i = 0; i < AR8XXX_NUM_PHYS; i++)
data->eee[i] = false;
+
+   if (chip_is_ar8337(priv)) {
+   /* Update HOL registers with values suggested by QCA switch 
team */
+   for (i = 0; i < AR8327_NUM_PORTS; i++) {
+   if (i == AR8216_PORT_CPU || i == 5 || i == 6) {
+   t = 0x3 << AR8327_PORT_HOL_CTRL0_EG_PRI0_BUF_S;
+   t |= 0x4 << AR8327_PORT_HOL_CTRL0_EG_PRI1_BUF_S;
+   t |= 0x4 << AR8327_PORT_HOL_CTRL0_EG_PRI2_BUF_S;
+   t |= 0x4 << AR8327_PORT_HOL_CTRL0_EG_PRI3_BUF_S;
+   t |= 0x6 << AR8327_PORT_HOL_CTRL0_EG_PRI4_BUF_S;
+   t |= 0x8 << AR8327_PORT_HOL_CTRL0_EG_PRI5_BUF_S;
+   t |= 0x1e << 
AR8327_PORT_HOL_CTRL0_EG_PORT_BUF_S;
+   } else {
+   t = 0x3 << AR8327_PORT_HOL_CTRL0_EG_PRI0_BUF_S;
+   t |= 0x4 << AR8327_PORT_HOL_CTRL0_EG_PRI1_BUF_S;
+   t |= 0x6 << AR8327_PORT_HOL_CTRL0_EG_PRI2_BUF_S;
+   t |= 0x8 << AR8327_PORT_HOL_CTRL0_EG_PRI3_BUF_S;
+   t |= 0x19 << 
AR8327_PORT_HOL_CTRL0_EG_PORT_BUF_S;
+   }
+   ar8xxx_write(priv, AR8327_REG_PORT_HOL_CTRL0(i), t);
+
+   t = 0x6 << AR8327_PORT_HOL_CTRL1_ING_BUF_S;
+   t |= AR8327_PORT_HOL_CTRL1_EG_PRI_BUF_EN;
+   t |= AR8327_PORT_HOL_CTRL1_EG_PORT_BUF_EN;
+   t |= AR8327_PORT_HOL_CTRL1_WRED_EN;
+   ar8xxx_rmw(priv, AR8327_REG_PORT_HOL_CTRL1(i),
+  AR8327_PORT_HOL_CTRL1_ING_BUF |
+  AR8327_PORT_HOL_CTRL1_EG_PRI_BUF_EN |
+  AR8327_PORT_HOL_CTRL1_EG_PORT_BUF_EN |
+  AR8327_PORT_HOL_CTRL1_WRED_EN,
+  t);
+   }
+   }
 }
 
 static void
@@ -1397,7 +1438,7 @@ const struct ar8xxx_chip ar8327_chip = {
.atu_flush_port = ar8327_atu_flush_port,
.vtu_flush = ar8327_vtu_flush,
.vtu_load_vlan = ar8327_vtu_load_vlan,
-   .phy_fixup = ar8327_phy_fixup,
+   //.phy_fixup = ar8337_phy_fixup, // not needed at the moment
.set_mirror_regs = ar8327_set_mirror_regs,
.get_arl_entry = ar8327_get_arl_entry,
.sw_hw_apply = ar8327_sw_hw_apply,
diff --git a/target/linux/generic/files/drivers/net/phy/ar8327.h 
b/target/linux/generic/files/drivers/net/phy/ar8327.h
index 7bce18b..828dd28 100644
--- a/target/linux/generic/files/drivers/net/phy/ar8327.h
+++ b/target/linux/generic/files/drivers/net/phy/ar8327.h
@@ -272,7 +272,28 @@
 
 #define AR8327_REG_PORT_PRIO(_i)   (0x664 + (_i) * 0xc)
 
+#define AR8327_REG_PORT_HOL_CTRL0(_i)  (0x970 + (_i) * 0x8)
+#define   AR8327_PORT_HOL_CTRL0_EG_PRI0_BUFBITS(0, 4)
+#define   AR8327_PORT_HOL_CTRL0_EG_PRI0_BUF_S  0
+#define   AR8327_PORT_HOL_CTRL0_EG_PRI1_BUFBITS(4, 4)
+#define   AR8327_PORT_HOL_CTRL0_EG_PRI1_BUF_S  4
+#define   AR8327_PORT_HOL_CTRL0_EG_PRI2_BUFBITS(8, 4)
+#define   AR8327_PORT_HOL_CTRL0_EG_PRI2_BUF_S  8
+#define   AR8327_PORT_HOL_CTRL0_EG_PRI3_BUFBITS(12, 4)
+#define   AR8327_PORT_HOL_CTRL0_EG_PRI3_BUF_S  12
+#define   AR8327_PORT_HOL_CTRL0_EG_PRI4_BUFBITS(16, 4)
+#define   AR8327_PORT_HOL_CTRL0_EG_PRI4_BUF_S  16
+#define   AR8327_PORT_HOL_CTRL0_EG_PRI5_BUFBITS(20, 4)
+#define   

[LEDE-DEV] [PATCH RFC] ar8216: (try to) implement get_port_stats

2017-03-21 Thread Vittorio Gambaletta (VittGam)
Hello,

TP-LINK, in their new TL-WR1043ND v4, for some reason wired the
ethernet LEDs not to the AR8337, but to the QCA956x SoC instead.

This means that the switch LED trigger needs to be used for all
of the ethernet LEDs (4 x LAN and 1 x WAN), like on the AR9341
when its internal switch is used.

But the ar8216/8327/8337 switch driver does not implement the
get_port_stats function, so the LEDs are lit but do not blink
when traffic passes through the ports.

(By the way, if I remember well, the stock firmware of this router
does not make those LEDs blink either...)

I've tried to write the needed function, as you can see in the
patch below.

The problem is that now a kworker kernel thread is constantly
consuming 12-15% of CPU. It stops when I change the trigger on
the LEDs to something else via sysfs. So, there is clearly
something wrong with it. But what?

The implementation for the AR9341 internal switch (in
target/linux/ar71xx/files/drivers/net/ethernet/atheros/ag71xx/ag71xx_ar7240.c)
does it in a quite similar way (it actually polls ALL the switch
ports every time data for a single port is requested...), but
it uses 0% CPU instead.

What do you think?

Thank you!

Best regards,
Vittorio G

---

diff --git a/target/linux/generic/files/drivers/net/phy/ar8216.c 
b/target/linux/generic/files/drivers/net/phy/ar8216.c
index 37877d5..6b3246d 100644
--- a/target/linux/generic/files/drivers/net/phy/ar8216.c
+++ b/target/linux/generic/files/drivers/net/phy/ar8216.c
@@ -49,6 +49,13 @@ extern const struct ar8xxx_chip ar8337_chip;
.name = (_n),   \
}
 
+enum {
+   AR8216_MIB_TX_OFFSET = 29,
+   AR8216_MIB_RX_OFFSET = 14,
+   AR8236_MIB_TX_OFFSET = 31,
+   AR8236_MIB_RX_OFFSET = 15,
+};
+
 static const struct ar8xxx_mib_desc ar8216_mibs[] = {
MIB_DESC(1, AR8216_STATS_RXBROAD, "RxBroad"),
MIB_DESC(1, AR8216_STATS_RXPAUSE, "RxPause"),
@@ -394,6 +401,24 @@ ar8xxx_mib_flush(struct ar8xxx_priv *priv)
return ar8xxx_mib_op(priv, AR8216_MIB_FUNC_FLUSH);
 }
 
+static u64
+ar8xxx_mib_fetch_single_port_stat(struct ar8xxx_priv *priv,
+  const unsigned int base,
+  const struct ar8xxx_mib_desc *mib)
+{
+   u64 t;
+
+   t = ar8xxx_read(priv, base + mib->offset);
+   if (mib->size == 2) {
+   u64 hi;
+
+   hi = ar8xxx_read(priv, base + mib->offset + 4);
+   t |= hi << 32;
+   }
+
+   return t;
+}
+
 static void
 ar8xxx_mib_fetch_port_stat(struct ar8xxx_priv *priv, int port, bool flush)
 {
@@ -410,17 +435,7 @@ ar8xxx_mib_fetch_port_stat(struct ar8xxx_priv *priv, int 
port, bool flush)
 
mib_stats = >mib_stats[port * priv->chip->num_mibs];
for (i = 0; i < priv->chip->num_mibs; i++) {
-   const struct ar8xxx_mib_desc *mib;
-   u64 t;
-
-   mib = >chip->mib_decs[i];
-   t = ar8xxx_read(priv, base + mib->offset);
-   if (mib->size == 2) {
-   u64 hi;
-
-   hi = ar8xxx_read(priv, base + mib->offset + 4);
-   t |= hi << 32;
-   }
+   u64 t = ar8xxx_mib_fetch_single_port_stat(priv, base, 
>chip->mib_decs[i]);
 
if (flush)
mib_stats[i] = 0;
@@ -1001,6 +1016,45 @@ ar8xxx_sw_get_port_link(struct switch_dev *dev, int port,
return 0;
 }
 
+int
+ar8xxx_sw_get_port_stats(struct switch_dev *dev, int port,
+  struct switch_port_stats *stats)
+{
+   struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+   const struct ar8xxx_chip *chip = priv->chip;
+   unsigned int base, tx_offset, rx_offset;
+   u64 *mib_stats;
+
+   if (!ar8xxx_has_mib_counters(priv))
+   return -EOPNOTSUPP;
+
+   if (port >= dev->ports)
+   return -EINVAL;
+
+   mutex_lock(>mib_lock);
+
+   base = chip->reg_port_stats_start + chip->reg_port_stats_length * port;
+   mib_stats = >mib_stats[port * chip->num_mibs];
+
+   if (chip_is_ar8216(priv)) {
+   tx_offset = AR8216_MIB_TX_OFFSET;
+   rx_offset = AR8216_MIB_RX_OFFSET;
+   } else {
+   tx_offset = AR8236_MIB_TX_OFFSET;
+   rx_offset = AR8236_MIB_RX_OFFSET;
+   }
+
+   mib_stats[tx_offset] += ar8xxx_mib_fetch_single_port_stat(priv, base, 
>chip->mib_decs[tx_offset]);
+   mib_stats[rx_offset] += ar8xxx_mib_fetch_single_port_stat(priv, base, 
>chip->mib_decs[rx_offset]);
+
+   stats->tx_bytes = mib_stats[tx_offset];
+   stats->rx_bytes = mib_stats[rx_offset];
+
+   mutex_unlock(>mib_lock);
+
+   return 0;
+}
+
 static int
 ar8xxx_sw_get_ports(struct switch_dev *dev, struct switch_val *val)
 {
@@ -1696,6 +1750,7 @@ static const struct switch_dev_ops ar8xxx_sw_ops = {
.apply_config = ar8xxx_sw_hw_apply,
.reset_switch = ar8xxx_sw_reset_switch,
.get_port_link = 

[LEDE-DEV] [PATCH v2] mac80211: Fix race condition leading to wifi interfaces not coming up at boot sometimes.

2017-03-14 Thread Vittorio Gambaletta (VittGam)
In the drv_mac80211_setup function, mac80211_interface_cleanup
is called to ask the kernel to delete all existing interfaces
for the phy that is being configured via netlink.

Later in the first function, mac80211_prepare_vif is called to
set up the new interfaces as required.

But sometimes, when mac80211_prepare_vif (and so the relevant
`iw phy x interface add y` command) runs, the kernel might still
be cleaning up the old interface with the same ifname. It usually
takes very few time to do that; possibly a few milliseconds of
sleep in the script after detecting this error condition could be
enough, but the busybox sh does not support sub-second sleep
intervals.

When this happens, iw obviously fails to create the new interface;
and the following message is printed in the system log, followed by
subsequent failure messages from hostapd in case this would have been
an AP interface.

Tue Mar 14 04:21:57 2017 daemon.notice netifd: radio1 (2767): command failed: 
Too many open files in system (-23)

This was a long-standing issue existing since at least OpenWrt Backfire,
and today I finally managed to debug and (hopefully) solve it.
It was happening very few times on most devices; but it was happening
a lot more frequently on fast platforms with multiple radios, such as
the powerpc-based dual-ath9k-radio tl-wdr4900-v1.

Signed-off-by: Vittorio Gambaletta 

---
 .../mac80211/files/lib/netifd/wireless/mac80211.sh |   32 +---
 1 file changed, 27 insertions(+), 5 deletions(-)

diff --git a/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh 
b/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh
index baa023e..9ebd76b 100644
--- a/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh
+++ b/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh
@@ -411,6 +411,28 @@ mac80211_check_ap() {
has_ap=1
 }
 
+mac80211_iw_interface_add() {
+   local phy="$1"
+   local ifname="$2"
+   local type="$3"
+   local wdsflag="$4"
+   local rc
+
+   iw phy "$phy" interface add "$ifname" type "$type" $wdsflag
+   rc="$?"
+
+   [ "$rc" = 233 ] && {
+   # Device might have just been deleted, give the kernel some 
time to finish cleaning it up
+   sleep 1
+
+   iw phy "$phy" interface add "$ifname" type "$type" $wdsflag
+   rc="$?"
+   }
+
+   [ "$rc" != 0 ] && wireless_setup_failed INTERFACE_CREATION_FAILED
+   return $rc
+}
+
 mac80211_prepare_vif() {
json_select config
 
@@ -437,7 +459,7 @@ mac80211_prepare_vif() {
# It is far easier to delete and create the desired interface
case "$mode" in
adhoc)
-   iw phy "$phy" interface add "$ifname" type adhoc
+   mac80211_iw_interface_add "$phy" "$ifname" adhoc || 
return
;;
ap)
# Hostapd will handle recreating the interface and
@@ -451,21 +473,21 @@ mac80211_prepare_vif() {
mac80211_hostapd_setup_bss "$phy" "$ifname" "$macaddr" 
"$type" || return
 
[ -n "$hostapd_ctrl" ] || {
-   iw phy "$phy" interface add "$ifname" type __ap
+   mac80211_iw_interface_add "$phy" "$ifname" __ap 
|| return

hostapd_ctrl="${hostapd_ctrl:-/var/run/hostapd/$ifname}"
}
;;
mesh)
-   iw phy "$phy" interface add "$ifname" type mp
+   mac80211_iw_interface_add "$phy" "$ifname" mp || return
;;
monitor)
-   iw phy "$phy" interface add "$ifname" type monitor
+   mac80211_iw_interface_add "$phy" "$ifname" monitor || 
return
;;
sta)
local wdsflag=
staidx="$(($staidx + 1))"
[ "$wds" -gt 0 ] && wdsflag="4addr on"
-   iw phy "$phy" interface add "$ifname" type managed 
$wdsflag
+   mac80211_iw_interface_add "$phy" "$ifname" managed 
"$wdsflag" || return
[ "$powersave" -gt 0 ] && powersave="on" || 
powersave="off"
iw "$ifname" set power_save "$powersave"
;;


___
Lede-dev mailing list
Lede-dev@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/lede-dev


[LEDE-DEV] [PATCH] mac80211: Fix race condition leading to wifi interfaces not coming up at boot sometimes.

2017-03-13 Thread Vittorio Gambaletta (VittGam)
In the drv_mac80211_setup function, mac80211_interface_cleanup
is called to ask the kernel to delete all existing interfaces
for the phy that is being configured via netlink.

Later in the first function, mac80211_prepare_vif is called to
set up the new interfaces as required.

But sometimes, when mac80211_prepare_vif (and so the relevant
`iw phy x interface add y` command) runs, the kernel might still
be cleaning up the old interface with the same ifname. It usually
takes very few time to do that; possibly a few milliseconds of
sleep in the script after detecting this error condition could be
enough, but the busybox sh does not support sub-second sleep
intervals.

When this happens, iw obviously fails to create the new interface;
and the following message is printed in the system log, followed by
subsequent failure messages from hostapd in case this would have been
an AP interface.

Tue Mar 14 04:21:57 2017 daemon.notice netifd: radio1 (2767): command failed: 
Too many open files in system (-23)

This was a long-standing issue existing since at least OpenWrt Backfire,
and today I finally managed to debug and (hopefully) solve it.
It was happening very few times on most devices; but it was happening
a lot more frequently on fast platforms with multiple radios, such as
the powerpc-based dual-ath9k-radio tl-wdr4900-v1.

Signed-off-by: Vittorio Gambaletta 

---
 .../mac80211/files/lib/netifd/wireless/mac80211.sh |   35 +---
 1 file changed, 30 insertions(+), 5 deletions(-)

diff --git a/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh 
b/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh
index baa023e..5058b01 100644
--- a/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh
+++ b/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh
@@ -411,6 +411,31 @@ mac80211_check_ap() {
has_ap=1
 }
 
+mac80211_iw_interface_add() {
+   local phy="$1"
+   local ifname="$2"
+   local type="$3"
+   local wdsflag="$4"
+
+   iw phy "$phy" interface add "$ifname" type "$type" $wdsflag
+   ret="$?"
+
+   [ "$ret" = 233 ] && {
+   # Device might have just been deleted, give the kernel some 
time to finish cleaning it up
+   sleep 1
+
+   iw phy "$phy" interface add "$ifname" type "$type" $wdsflag
+   ret="$?"
+   }
+
+   [ "$ret" != 0 ] && {
+   wireless_setup_failed INTERFACE_CREATION_FAILED
+   return 1
+   }
+
+   return 0
+}
+
 mac80211_prepare_vif() {
json_select config
 
@@ -437,7 +462,7 @@ mac80211_prepare_vif() {
# It is far easier to delete and create the desired interface
case "$mode" in
adhoc)
-   iw phy "$phy" interface add "$ifname" type adhoc
+   mac80211_iw_interface_add "$phy" "$ifname" adhoc || 
return
;;
ap)
# Hostapd will handle recreating the interface and
@@ -451,21 +476,21 @@ mac80211_prepare_vif() {
mac80211_hostapd_setup_bss "$phy" "$ifname" "$macaddr" 
"$type" || return
 
[ -n "$hostapd_ctrl" ] || {
-   iw phy "$phy" interface add "$ifname" type __ap
+   mac80211_iw_interface_add "$phy" "$ifname" __ap 
|| return

hostapd_ctrl="${hostapd_ctrl:-/var/run/hostapd/$ifname}"
}
;;
mesh)
-   iw phy "$phy" interface add "$ifname" type mp
+   mac80211_iw_interface_add "$phy" "$ifname" mp || return
;;
monitor)
-   iw phy "$phy" interface add "$ifname" type monitor
+   mac80211_iw_interface_add "$phy" "$ifname" monitor || 
return
;;
sta)
local wdsflag=
staidx="$(($staidx + 1))"
[ "$wds" -gt 0 ] && wdsflag="4addr on"
-   iw phy "$phy" interface add "$ifname" type managed 
$wdsflag
+   mac80211_iw_interface_add "$phy" "$ifname" managed 
"$wdsflag" || return
[ "$powersave" -gt 0 ] && powersave="on" || 
powersave="off"
iw "$ifname" set power_save "$powersave"
;;


___
Lede-dev mailing list
Lede-dev@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/lede-dev