tg3: Fix 5906 transmit hangs
authorMatt Carlson <mcarlson@broadcom.com>
Mon, 2 Nov 2009 14:23:27 +0000 (14:23 +0000)
committerDavid S. Miller <davem@davemloft.net>
Tue, 3 Nov 2009 07:39:00 +0000 (23:39 -0800)
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: Matt Carlson <mcarlson@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/tg3.c
drivers/net/tg3.h

index da808250c866b261c38624dc51fa055f24984e08..a7a582e374699f57c7d61797b2984261eaf7628c 100644 (file)
@@ -5393,7 +5393,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)) {
@@ -5424,8 +5424,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;
 
@@ -5460,6 +5462,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_4G_DMA_BNDRY_BUG) &&
            tg3_4g_overflow_test(mapping, len))
                would_hit_hwbug = 1;
@@ -5489,6 +5494,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 ((tp->tg3_flags3 & TG3_FLG3_4G_DMA_BNDRY_BUG) &&
                            tg3_4g_overflow_test(mapping, len))
                                would_hit_hwbug = 1;
@@ -12625,8 +12634,12 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
        }
 
        if (!(tp->tg3_flags3 & TG3_FLG3_5755_PLUS)) {
-               tp->tg3_flags3 |= TG3_FLG3_4G_DMA_BNDRY_BUG;
-               tp->tg3_flags3 |= TG3_FLG3_40BIT_DMA_LIMIT_BUG;
+               if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+                       tp->tg3_flags3 |= TG3_FLG3_SHORT_DMA_BUG;
+               else {
+                       tp->tg3_flags3 |= TG3_FLG3_4G_DMA_BNDRY_BUG;
+                       tp->tg3_flags3 |= TG3_FLG3_40BIT_DMA_LIMIT_BUG;
+               }
        }
 
        if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) ||
@@ -13987,8 +14000,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 b603810b4e9b08576165173be866c2d3cd57d849..a5568a14974870623adceec3e7cd5c2f6b669b76 100644 (file)
@@ -2761,6 +2761,7 @@ struct tg3 {
 #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;