ar71xx: add missing ethernet driver fix backport (fixes #10089)
authorFelix Fietkau <nbd@openwrt.org>
Sun, 11 Sep 2011 21:36:33 +0000 (21:36 +0000)
committerFelix Fietkau <nbd@openwrt.org>
Sun, 11 Sep 2011 21:36:33 +0000 (21:36 +0000)
SVN-Revision: 28215

target/linux/ar71xx/files/arch/mips/ar71xx/devices.c
target/linux/ar71xx/files/arch/mips/include/asm/mach-ar71xx/platform.h
target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx.h
target/linux/ar71xx/files/drivers/net/ag71xx/ag71xx_main.c

index 455b2cd03464559e34ac525cbb46a8c525c925f1..1e50dcb19e788c52dd8d7fdeb6207d015131c5ae 100644 (file)
@@ -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;
index cf198d2bfa158c2e74129bf134d14ca15976f5fd..84d4f1aaaf18428b75183b3157ed72ff6d3451ae 100644 (file)
@@ -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;
index 8ca5c8983f072d4601c8d9e63151eb38c5e690db..5ddefe6723342dcaf656dd1838da1af636d13366 100644 (file)
@@ -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 */
index 8e25d4a1f4266891e1a1b0e99da3b9322b8fda37..4a86bb974b8fccd11ec2bf190c328063185fa325 100644 (file)
@@ -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);