ixgb: Fix early TSO completion
authorJesse Brandeburg <jesse.brandeburg@intel.com>
Sat, 6 Jan 2007 17:51:23 +0000 (09:51 -0800)
committerAuke Kok <juke-jan.h.kok@intel.com>
Sat, 6 Jan 2007 17:51:23 +0000 (09:51 -0800)
This fix was already merged in commit 96f9c2e277768099479fbed7c3b69c294b1fadef
but reverted in commit 989316ddfeafd0e8fb51a4d811383769ad62637a. After
stresstesting we found that the fix does not add new regressions and
works around a TX hang spotted by several users.

Signed-off-by: Jesse Brandeburg <jesse.brandeburg@intel.com>
Signed-off-by: Auke Kok <auke-jan.h.kok@intel.com>
drivers/net/ixgb/ixgb_main.c

index e628126..70ac9d4 100644 (file)
@@ -1287,6 +1287,7 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb,
        struct ixgb_buffer *buffer_info;
        int len = skb->len;
        unsigned int offset = 0, size, count = 0, i;
+       unsigned int mss = skb_shinfo(skb)->gso_size;
 
        unsigned int nr_frags = skb_shinfo(skb)->nr_frags;
        unsigned int f;
@@ -1298,6 +1299,11 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb,
        while(len) {
                buffer_info = &tx_ring->buffer_info[i];
                size = min(len, IXGB_MAX_DATA_PER_TXD);
+               /* Workaround for premature desc write-backs
+                * in TSO mode.  Append 4-byte sentinel desc */
+               if (unlikely(mss && !nr_frags && size == len && size > 8))
+                       size -= 4;
+
                buffer_info->length = size;
                WARN_ON(buffer_info->dma != 0);
                buffer_info->dma =
@@ -1324,6 +1330,13 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb,
                while(len) {
                        buffer_info = &tx_ring->buffer_info[i];
                        size = min(len, IXGB_MAX_DATA_PER_TXD);
+
+                       /* Workaround for premature desc write-backs
+                        * in TSO mode.  Append 4-byte sentinel desc */
+                       if (unlikely(mss && !nr_frags && size == len
+                                    && size > 8))
+                               size -= 4;
+
                        buffer_info->length = size;
                        buffer_info->dma =
                                pci_map_page(adapter->pdev,
@@ -1401,8 +1414,9 @@ ixgb_tx_queue(struct ixgb_adapter *adapter, int count, int vlan_id,int tx_flags)
 /* Tx Descriptors needed, worst case */
 #define TXD_USE_COUNT(S) (((S) >> IXGB_MAX_TXD_PWR) + \
                         (((S) & (IXGB_MAX_DATA_PER_TXD - 1)) ? 1 : 0))
-#define DESC_NEEDED TXD_USE_COUNT(IXGB_MAX_DATA_PER_TXD) + \
-       MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1
+#define DESC_NEEDED TXD_USE_COUNT(IXGB_MAX_DATA_PER_TXD) /* skb->date */ + \
+       MAX_SKB_FRAGS * TXD_USE_COUNT(PAGE_SIZE) + 1 /* for context */ \
+       + 1 /* one more needed for sentinel TSO workaround */
 
 static int
 ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev)