tg3: Fix 5906 transmit hangs
authorMatt Carlson <mcarlson@broadcom.com>
Fri, 12 Mar 2010 23:12:13 +0000 (18:12 -0500)
committerGreg Kroah-Hartman <gregkh@suse.de>
Thu, 1 Apr 2010 22:58:05 +0000 (15:58 -0700)
This is a resubmit backport of commit 92c6b8d16a36df3f28b2537bed2a56491fb08f11
to kernel version 2.6.32. The gentoo bug report can be found at
https://bugs.gentoo.org/show_bug.cgi?id=301091. Thanks to Matt Carlson for his
assistance and working me to fix a regression caused by the initial patch.  The
original description is as follows:

The 5906 has trouble with fragments that are less than 8 bytes in size.  This
patch works around the problem by pivoting the 5906's transmit routine to
tg3_start_xmit_dma_bug() and introducing a new SHORT_DMA_BUG flag that enables
code to detect and react to the problematic condition.

Signed-off-by: Mike Pagano <mpagano@gentoo.org>
Signed-off-by: Matt Carlson <mcarlson@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/net/tg3.c
drivers/net/tg3.h

index eea1e08fa450fdfb1fd533b18ffacd6a81cd3c86..dcc1c23aab81b889b6a8bc24be0f829a2f856651 100644 (file)
@@ -5392,7 +5392,7 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb,
        mss = 0;
        if ((mss = skb_shinfo(skb)->gso_size) != 0) {
                struct iphdr *iph;
-               int tcp_opt_len, ip_tcp_len, hdr_len;
+               u32 tcp_opt_len, ip_tcp_len, hdr_len;
 
                if (skb_header_cloned(skb) &&
                    pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
@@ -5423,8 +5423,10 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb,
                                                                 IPPROTO_TCP,
                                                                 0);
 
-               if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO) ||
-                   (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705)) {
+               if (tp->tg3_flags2 & TG3_FLG2_HW_TSO_2)
+                       mss |= hdr_len << 9;
+               else if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_1) ||
+                       GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) {
                        if (tcp_opt_len || iph->ihl > 5) {
                                int tsflags;
 
@@ -5459,6 +5461,9 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb,
 
        would_hit_hwbug = 0;
 
+       if ((tp->tg3_flags3 & TG3_FLG3_SHORT_DMA_BUG) && len <= 8)
+               would_hit_hwbug = 1;
+
        if (tp->tg3_flags3 & TG3_FLG3_5701_DMA_BUG)
                would_hit_hwbug = 1;
        else if (tg3_4g_overflow_test(mapping, len))
@@ -5482,6 +5487,10 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb,
 
                        tnapi->tx_buffers[entry].skb = NULL;
 
+                       if ((tp->tg3_flags3 & TG3_FLG3_SHORT_DMA_BUG) &&
+                               len <= 8)
+                                       would_hit_hwbug = 1;
+
                        if (tg3_4g_overflow_test(mapping, len))
                                would_hit_hwbug = 1;
 
@@ -12608,6 +12617,9 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
                }
        }
 
+       if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+               tp->tg3_flags3 |= TG3_FLG3_SHORT_DMA_BUG;
+
        tp->irq_max = 1;
 
 #ifdef TG3_NAPI
@@ -13975,8 +13987,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
                goto err_out_iounmap;
        }
 
-       if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) ||
-           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+       if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS)
                dev->netdev_ops = &tg3_netdev_ops;
        else
                dev->netdev_ops = &tg3_netdev_ops_dma_bug;
index bab7940158e65d208ca734f22d12e432620f69bb..529f55ad16dbb8de49d1559f80f9b9ea23eb843e 100644 (file)
@@ -2759,6 +2759,9 @@ struct tg3 {
 #define TG3_FLG3_TOGGLE_10_100_L1PLLPD 0x00008000
 #define TG3_FLG3_PHY_IS_FET            0x00010000
 #define TG3_FLG3_ENABLE_RSS            0x00020000
+#define TG3_FLG3_4G_DMA_BNDRY_BUG      0x00080000
+#define TG3_FLG3_40BIT_DMA_LIMIT_BUG   0x00100000
+#define TG3_FLG3_SHORT_DMA_BUG  0x00200000
 
        struct timer_list               timer;
        u16                             timer_counter;