ixgbe: flush when in xmit_more mode and under descriptor pressure
authorDaniel Borkmann <dborkman@redhat.com>
Tue, 26 Aug 2014 17:34:18 +0000 (19:34 +0200)
committerDavid S. Miller <davem@davemloft.net>
Thu, 28 Aug 2014 06:17:41 +0000 (23:17 -0700)
When xmit_more mode is being used and the ring is about to
become full or the stack has stopped the ring, enforce a tail
pointer write to the hw. Otherwise, we could risk a TX hang.

Code suggested by Alexander Duyck.

Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c

index ba9ceaa824f84d34aa7c6b7dbf50d8c8562ab3f9..53fbf0641533a69b214a50cc3e24ecc09542c3be 100644 (file)
@@ -6837,6 +6837,36 @@ static void ixgbe_tx_olinfo_status(union ixgbe_adv_tx_desc *tx_desc,
        tx_desc->read.olinfo_status = cpu_to_le32(olinfo_status);
 }
 
+static int __ixgbe_maybe_stop_tx(struct ixgbe_ring *tx_ring, u16 size)
+{
+       netif_stop_subqueue(tx_ring->netdev, tx_ring->queue_index);
+
+       /* Herbert's original patch had:
+        *  smp_mb__after_netif_stop_queue();
+        * but since that doesn't exist yet, just open code it.
+        */
+       smp_mb();
+
+       /* We need to check again in a case another CPU has just
+        * made room available.
+        */
+       if (likely(ixgbe_desc_unused(tx_ring) < size))
+               return -EBUSY;
+
+       /* A reprieve! - use start_queue because it doesn't call schedule */
+       netif_start_subqueue(tx_ring->netdev, tx_ring->queue_index);
+       ++tx_ring->tx_stats.restart_queue;
+       return 0;
+}
+
+static inline int ixgbe_maybe_stop_tx(struct ixgbe_ring *tx_ring, u16 size)
+{
+       if (likely(ixgbe_desc_unused(tx_ring) >= size))
+               return 0;
+
+       return __ixgbe_maybe_stop_tx(tx_ring, size);
+}
+
 #define IXGBE_TXD_CMD (IXGBE_TXD_CMD_EOP | \
                       IXGBE_TXD_CMD_RS)
 
@@ -6958,10 +6988,13 @@ static void ixgbe_tx_map(struct ixgbe_ring *tx_ring,
 
        tx_ring->next_to_use = i;
 
-       if (!skb->xmit_more) {
+       ixgbe_maybe_stop_tx(tx_ring, DESC_NEEDED);
+
+       if (netif_xmit_stopped(txring_txq(tx_ring)) || !skb->xmit_more) {
                /* notify HW of packet */
                ixgbe_write_tail(tx_ring, i);
        }
+
        return;
 dma_error:
        dev_err(tx_ring->dev, "TX DMA map failed\n");
@@ -7068,32 +7101,6 @@ static void ixgbe_atr(struct ixgbe_ring *ring,
                                              input, common, ring->queue_index);
 }
 
-static int __ixgbe_maybe_stop_tx(struct ixgbe_ring *tx_ring, u16 size)
-{
-       netif_stop_subqueue(tx_ring->netdev, tx_ring->queue_index);
-       /* Herbert's original patch had:
-        *  smp_mb__after_netif_stop_queue();
-        * but since that doesn't exist yet, just open code it. */
-       smp_mb();
-
-       /* We need to check again in a case another CPU has just
-        * made room available. */
-       if (likely(ixgbe_desc_unused(tx_ring) < size))
-               return -EBUSY;
-
-       /* A reprieve! - use start_queue because it doesn't call schedule */
-       netif_start_subqueue(tx_ring->netdev, tx_ring->queue_index);
-       ++tx_ring->tx_stats.restart_queue;
-       return 0;
-}
-
-static inline int ixgbe_maybe_stop_tx(struct ixgbe_ring *tx_ring, u16 size)
-{
-       if (likely(ixgbe_desc_unused(tx_ring) >= size))
-               return 0;
-       return __ixgbe_maybe_stop_tx(tx_ring, size);
-}
-
 static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb,
                              void *accel_priv, select_queue_fallback_t fallback)
 {
@@ -7262,8 +7269,6 @@ xmit_fcoe:
 #endif /* IXGBE_FCOE */
        ixgbe_tx_map(tx_ring, first, hdr_len);
 
-       ixgbe_maybe_stop_tx(tx_ring, DESC_NEEDED);
-
        return NETDEV_TX_OK;
 
 out_drop: