[LEDE-DEV] [PATCH v2] ar8327: Add workarounds for AR8337 switch.
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.
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.
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.
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.
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
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.
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.
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