From 8c252c022d47bb218a812e03b659618e2364bd8f Mon Sep 17 00:00:00 2001 From: nbd Date: Sun, 11 Sep 2011 21:36:33 +0000 Subject: [PATCH] ar71xx: add missing ethernet driver fix backport (fixes #10089) git-svn-id: svn://svn.openwrt.org/openwrt/branches/backfire@28215 3c298f89-4303-0410-b956-a3cf2f4a3e73 --- .../ar71xx/files/arch/mips/ar71xx/devices.c | 2 ++ .../mips/include/asm/mach-ar71xx/platform.h | 1 + .../ar71xx/files/drivers/net/ag71xx/ag71xx.h | 4 +++ .../files/drivers/net/ag71xx/ag71xx_main.c | 30 ++++++++++++++++++- 4 files changed, 36 insertions(+), 1 deletion(-) diff --git a/target/linux/ar71xx/files/arch/mips/ar71xx/devices.c b/target/linux/ar71xx/files/arch/mips/ar71xx/devices.c index 455b2cd03..1e50dcb19 100644 --- a/target/linux/ar71xx/files/arch/mips/ar71xx/devices.c +++ b/target/linux/ar71xx/files/arch/mips/ar71xx/devices.c @@ -493,6 +493,8 @@ void __init ar71xx_add_device_eth(unsigned int id) pdata->set_pll = id ? ar724x_set_pll_ge1 : ar724x_set_pll_ge0; pdata->is_ar724x = 1; + if (ar71xx_soc == AR71XX_SOC_AR7240) + pdata->is_ar7240 = 1; if (!pdata->fifo_cfg1) pdata->fifo_cfg1 = 0x0010ffff; diff --git a/target/linux/ar71xx/files/arch/mips/include/asm/mach-ar71xx/platform.h b/target/linux/ar71xx/files/arch/mips/include/asm/mach-ar71xx/platform.h index cf198d2bf..84d4f1aaa 100644 --- a/target/linux/ar71xx/files/arch/mips/include/asm/mach-ar71xx/platform.h +++ b/target/linux/ar71xx/files/arch/mips/include/asm/mach-ar71xx/platform.h @@ -29,6 +29,7 @@ struct ag71xx_platform_data { u8 has_gbit:1; u8 is_ar91xx:1; + u8 is_ar7240:1; u8 is_ar724x:1; u8 has_ar8216:1; u8 has_ar7240_switch:1; diff --git a/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx.h b/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx.h index 8ca5c8983..5ddefe672 100644 --- a/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx.h +++ b/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx.h @@ -238,6 +238,10 @@ static inline int ag71xx_desc_pktlen(struct ag71xx_desc *desc) #define AG71XX_REG_INT_ENABLE 0x0198 #define AG71XX_REG_INT_STATUS 0x019c +#define AG71XX_REG_FIFO_DEPTH 0x01a8 +#define AG71XX_REG_RX_SM 0x01b0 +#define AG71XX_REG_TX_SM 0x01b4 + #define MAC_CFG1_TXE BIT(0) /* Tx Enable */ #define MAC_CFG1_STX BIT(1) /* Synchronize Tx Enable */ #define MAC_CFG1_RXE BIT(2) /* Rx Enable */ diff --git a/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_main.c b/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_main.c index 8e25d4a1f..4a86bb974 100644 --- a/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_main.c +++ b/target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_main.c @@ -806,9 +806,33 @@ static void ag71xx_restart_work_func(struct work_struct *work) ag71xx_open(ag->dev); } +static bool ag71xx_check_dma_stuck(struct ag71xx *ag, unsigned long timestamp) +{ + u32 rx_sm, tx_sm, rx_fd; + + if (likely(time_before(jiffies, timestamp + HZ/10))) + return false; + + if (!netif_carrier_ok(ag->dev)) + return false; + + rx_sm = ag71xx_rr(ag, AG71XX_REG_RX_SM); + if ((rx_sm & 0x7) == 0x3 && ((rx_sm >> 4) & 0x7) == 0x6) + return true; + + tx_sm = ag71xx_rr(ag, AG71XX_REG_TX_SM); + rx_fd = ag71xx_rr(ag, AG71XX_REG_FIFO_DEPTH); + if (((tx_sm >> 4) & 0x7) == 0 && ((rx_sm & 0x7) == 0) && + ((rx_sm >> 4) & 0x7) == 0 && rx_fd == 0) + return true; + + return false; +} + static int ag71xx_tx_packets(struct ag71xx *ag) { struct ag71xx_ring *ring = &ag->tx_ring; + struct ag71xx_platform_data *pdata = ag71xx_get_pdata(ag); int sent; DBG("%s: processing TX ring\n", ag->dev->name); @@ -819,8 +843,12 @@ static int ag71xx_tx_packets(struct ag71xx *ag) struct ag71xx_desc *desc = ring->buf[i].desc; struct sk_buff *skb = ring->buf[i].skb; - if (!ag71xx_desc_empty(desc)) + if (!ag71xx_desc_empty(desc)) { + if (pdata->is_ar7240 && + ag71xx_check_dma_stuck(ag, ring->buf[i].timestamp)) + schedule_work(&ag->restart_work); break; + } ag71xx_wr(ag, AG71XX_REG_TX_STATUS, TX_STATUS_PS); -- 2.35.1