From: Joe Ayers <ae...@arrl.net> Fixes openwrt 19085 nanostation m5 loco xw loses interface
Signed-off-by: Joe Ayers <ae...@arrl.net> Signed-off-by: Trevor Paskett <k7...@aredn.org> Signed-off-by: Darryl Quinn <k5...@aredn.org> Signed-off-by: Conrad Lara <kg6...@aredn.org> --- I'm not entirely sure of the visibility to openwrt remaining group, but I also sent this to the openwrt dev list. This was produced from the aredn.org team. Feedback appreciated. Test results: [ 0.000000] Linux version 4.4.14 (joe@AE6XE-PE) (gcc version 5.3.0 (OpenWrt GCC 5.3.0 49994) ) #1 Mon Nov 21 16:47:41 UTC 2016 [ 0.000000] MyLoader: sysp=9f65a088, boardp=810d1261, parts=61618340 [ 0.000000] bootconsole [early0] enabled [ 0.000000] CPU0 revision is: 0001974c (MIPS 74Kc) [ 0.000000] SoC: Atheros AR9342 rev 2 ... [ 0.000000] Kernel command line: board=UBNT-LOCO-XW mtdparts=spi0.0:256k(u-boot)ro,64k(u-boot-env)ro,7552k(firmware),256k(cfg)ro,64k(EEPROM)ro console=ttyS0,115200 rootfstype=squashfs,jffs2 noinitrd ... [ 0.648684] libphy: ag71xx_mdio: probed [ 1.239012] ag71xx ag71xx.0: connected to PHY at ag71xx-mdio.0:01 [uid=004dd023, driver=Generic PHY] [ 1.249098] eth0: Atheros AG71xx at 0xb9000000, irq 4, mode:MII ... [56312.947419] ag71xx_check_reset: expected: 004d, got: 0000 [56312.952909] ag71xx_gpio_reset triggered [56312.961952] eth0: link down [56312.965631] br-lan: port 1(eth0) entered disabled state [56314.958602] eth0: link up (100Mbps/Full duplex) [56314.963297] br-lan: port 1(eth0) entered forwarding state [56314.968879] br-lan: port 1(eth0) entered forwarding state [56316.967075] br-lan: port 1(eth0) entered forwarding state 741-MIPS-ath79-ag71xx-ar803x-lockup-fix.patch --- a/drivers/net/ethernet/atheros/ag71xx/ag71xx.h +++ b/drivers/net/ethernet/atheros/ag71xx/ag71xx.h @@ -36,9 +36,10 @@ #include <asm/mach-ath79/ar71xx_regs.h> #include <asm/mach-ath79/ath79.h> #include <asm/mach-ath79/ag71xx_platform.h> +#include <asm/addrspace.h> #define AG71XX_DRV_NAME "ag71xx" -#define AG71XX_DRV_VERSION "0.5.35" +#define AG71XX_DRV_VERSION "0.5.36" #define AG71XX_NAPI_WEIGHT 64 #define AG71XX_OOM_REFILL (1 + HZ/10) @@ -370,6 +371,31 @@ ag71xx_ring_size_order(int size) #define RX_STATUS_OF BIT(2) /* Rx Overflow */ #define RX_STATUS_BE BIT(3) /* Bus Error */ +/* GPIO phy reset registers */ +#define AR934X_REG_GPIO_OE_ADDRESS 0x18040000 +#define AR934X_REG_GPIO_OUT 0x18040008 +#define AR934X_REG_GPIO_SET 0x1804000C +#define AR934X_REG_GPIO_CLEAR 0x18040010 +#define AR934X_EXPECTED_ID1 0x4d +#define AR934X_PHY_ID1 2 + +typedef unsigned int ath_reg_t; + +#define ath_reg_rd(_phys) (*(volatile ath_reg_t *)KSEG1ADDR(_phys)) + +#define ath_reg_wr_nf(_phys, _val) \ + ((*(volatile ath_reg_t *)KSEG1ADDR(_phys)) = (_val)) + +#define ath_reg_wr(_phys, _val) do { \ + ath_reg_wr_nf(_phys, _val); \ + ath_reg_rd(_phys); \ +} while(0) + +#define ath_reg_rmw_set(_reg, _mask) do { \ + ath_reg_wr((_reg), (ath_reg_rd((_reg)) | (_mask))); \ + ath_reg_rd((_reg)); \ +} while(0) + +#define ath_reg_rmw_clear(_reg, _mask) do { \ + ath_reg_wr((_reg), (ath_reg_rd((_reg)) | (_mask))); \ + ath_reg_rd((_reg)); \ +} while(0) + static inline void ag71xx_check_reg_offset(struct ag71xx *ag, unsigned reg) { switch (reg) { @@ -490,4 +516,6 @@ u16 ar7240sw_phy_read(struct mii_bus *mi int ar7240sw_phy_write(struct mii_bus *mii, unsigned phy_addr, unsigned reg_addr, u16 reg_val); +void ag71xx_check_reset(struct ag71xx *ag, bool reset); + #endif /* _AG71XX_H */ --- a/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c +++ b/drivers/net/ethernet/atheros/ag71xx/ag71xx_main.c @@ -511,6 +511,86 @@ static void ag71xx_hw_init(struct ag71xx ag71xx_dma_reset(ag); } +static void ag71xx_gpio_reset(struct ag71xx *ag) { + pr_info("ag71xx_gpio_reset triggered\n"); + + if ((ath_reg_rd(AR934X_REG_GPIO_OUT) & BIT(0)) == 0) { + // Set GPIO0 to 1 (not in reset) + ath_reg_wr(AR934X_REG_GPIO_SET, BIT(0)); + } + + if (ath_reg_rd(AR934X_REG_GPIO_OE_ADDRESS) & BIT(0)) { + // Set GPIO0 as output + ath_reg_rmw_clear(AR934X_REG_GPIO_OE_ADDRESS, BIT(0)); + } + + ath_reg_wr(AR934X_REG_GPIO_CLEAR, BIT(0)); + mdelay(2); + ath_reg_wr(AR934X_REG_GPIO_SET, BIT(0)); + mdelay(2); +} + +void ag71xx_check_reset(struct ag71xx *ag, bool reset) +{ + int retries; + struct phy_device *phydev = ag->phy_dev; + struct net_device *dev = ag->dev; + uint16_t phy_id; + u32 rx_ds; + u32 mii_reg; + + if (!soc_is_ar934x()) return; + + phy_id = phy_read(phydev, AR934X_PHY_ID1); + + if (!reset && phy_id == AR934X_EXPECTED_ID1) { + //No PHY hang detected + return; + } + + pr_info("ag71xx_check_reset: expected: %04x, got: %04x\n", AR934X_EXPECTED_ID1, phy_id); + + ag71xx_hw_stop(ag); + wmb(); + + mii_reg = ag71xx_rr(ag, AG71XX_REG_MII_CFG); + rx_ds = ag71xx_rr(ag, AG71XX_REG_RX_DESC); + + ag71xx_gpio_reset(ag); + + phy_id = phy_read(phydev, AR934X_PHY_ID1); + + retries = 102; //To be sure last try > 10ms after reset + + while (phy_id != AR934X_EXPECTED_ID1 && --retries) { + phy_id = phy_read(phydev, AR934X_PHY_ID1); + udelay(100); + } + + phy_id = phy_read(phydev, AR934X_PHY_ID1); + + if (phy_id != AR934X_EXPECTED_ID1) return; + + ag71xx_dma_reset(ag); + ag71xx_hw_setup(ag); + ag71xx_tx_packets(ag, true); + ag->tx_ring.curr = 0; + ag->tx_ring.dirty = 0; + netdev_reset_queue(ag->dev); + + /* setup max frame length */ + ag71xx_wr(ag, AG71XX_REG_MAC_MFL, + ag71xx_max_frame_len(ag->dev->mtu)); + + ag71xx_wr(ag, AG71XX_REG_RX_DESC, rx_ds); + ag71xx_wr(ag, AG71XX_REG_TX_DESC, ag->tx_ring.descs_dma); + ag71xx_wr(ag, AG71XX_REG_MII_CFG, mii_reg); + + ag71xx_hw_set_macaddr(ag, dev->dev_addr); + + return; +} + static void ag71xx_fast_reset(struct ag71xx *ag) { struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag); @@ -570,6 +650,8 @@ __ag71xx_link_adjust(struct ag71xx *ag, u32 fifo5; u32 fifo3; + ag71xx_check_reset(ag, false); + if (!ag->link && update) { ag71xx_hw_stop(ag); netif_carrier_off(ag->dev); _______________________________________________ Lede-dev mailing list Lede-dev@lists.infradead.org http://lists.infradead.org/mailman/listinfo/lede-dev