]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
i40e: Reorder logic for coalescing RS bits
authorAlexander Duyck <alexander.h.duyck@intel.com>
Tue, 11 Oct 2016 22:26:54 +0000 (15:26 -0700)
committerDhaval Giani <dhaval.giani@oracle.com>
Wed, 8 Mar 2017 00:40:57 +0000 (19:40 -0500)
Orabug: 24568124

This patch reorders the logic at the end of i40e_tx_map to address the
fact that the logic was rather convoluted and much larger than it needed
to be.

In order to try and coalesce the code paths I have updated some of the
comments and repurposed some of the variables in order to reduce
unnecessary overhead.

This patch does the following:
1.  Quit tracking skb->xmit_more with a flag, just max out packet_stride
2.  Drop tail_bump and do_rs and instead just use desc_count and td_cmd
3.  Pull comments from ixgbe that make need for wmb() more explicit.

Change-ID: Ic7da85ec75043c634e87fef958109789bcc6317c
Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Tested-by: Andrew Bowers <andrewx.bowers@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
(cherry picked from commit 1dc8b538795fcf92161cc056ceebb852cf375b17)
Signed-off-by: Brian Maly <brian.maly@oracle.com>
Conflicts:
drivers/net/ethernet/intel/i40e/i40e_txrx.c
drivers/net/ethernet/intel/i40evf/i40e_txrx.c

Signed-off-by: Dhaval Giani <dhaval.giani@oracle.com>
drivers/net/ethernet/intel/i40e/i40e_txrx.c
drivers/net/ethernet/intel/i40e/i40e_txrx.h
drivers/net/ethernet/intel/i40evf/i40e_txrx.c
drivers/net/ethernet/intel/i40evf/i40e_txrx.h

index 45de7583563439ad1889d26fc8208968dfe77571..8f9c27af49967058f04462f726342e7bca9edecd 100644 (file)
@@ -617,7 +617,7 @@ u32 i40e_get_tx_pending(struct i40e_ring *ring, bool in_sw)
        return 0;
 }
 
-#define WB_STRIDE 0x3
+#define WB_STRIDE 4
 
 /**
  * i40e_clean_tx_irq - Reclaim resources after transmit completes
@@ -731,7 +731,7 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
                unsigned int j = i40e_get_tx_pending(tx_ring, false);
 
                if (budget &&
-                   ((j / (WB_STRIDE + 1)) == 0) && (j != 0) &&
+                       ((j / WB_STRIDE) == 0) && (j > 0) &&
                    !test_bit(__I40E_DOWN, &tx_ring->vsi->state) &&
                    (I40E_DESC_UNUSED(tx_ring) != tx_ring->count))
                        tx_ring->arm_wb = true;
@@ -2689,9 +2689,7 @@ static inline void i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
        u32 td_tag = 0;
        dma_addr_t dma;
        u16 gso_segs;
-       u16 desc_count = 0;
-       bool tail_bump = true;
-       bool do_rs = false;
+       u16 desc_count = 1;
 
        if (tx_flags & I40E_TX_FLAGS_HW_VLAN) {
                td_cmd |= I40E_TX_DESC_CMD_IL2TAG1;
@@ -2774,8 +2772,7 @@ static inline void i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
                tx_bi = &tx_ring->tx_bi[i];
        }
 
-       /* set next_to_watch value indicating a packet is present */
-       first->next_to_watch = tx_desc;
+       netdev_tx_sent_queue(txring_txq(tx_ring), first->bytecount);
 
        i++;
        if (i == tx_ring->count)
@@ -2783,66 +2780,72 @@ static inline void i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
 
        tx_ring->next_to_use = i;
 
-       netdev_tx_sent_queue(txring_txq(tx_ring), first->bytecount);
        i40e_maybe_stop_tx(tx_ring, DESC_NEEDED);
 
+       /* write last descriptor with EOP bit */
+       td_cmd |= I40E_TX_DESC_CMD_EOP;
+
+       /* We can OR these values together as they both are checked against
+        * 4 below and at this point desc_count will be used as a boolean value
+        * after this if/else block.
+        */
+       desc_count |= ++tx_ring->packet_stride;
+
        /* Algorithm to optimize tail and RS bit setting:
-        * if xmit_more is supported
-        *      if xmit_more is true
-        *              do not update tail and do not mark RS bit.
-        *      if xmit_more is false and last xmit_more was false
-        *              if every packet spanned less than 4 desc
-        *                      then set RS bit on 4th packet and update tail
-        *                      on every packet
-        *              else
-        *                      update tail and set RS bit on every packet.
-        *      if xmit_more is false and last_xmit_more was true
-        *              update tail and set RS bit.
+        * if queue is stopped
+        *      mark RS bit
+        *      reset packet counter
+        * else if xmit_more is supported and is true
+        *      advance packet counter to 4
+        *      reset desc_count to 0
         *
-        * Optimization: wmb to be issued only in case of tail update.
-        * Also optimize the Descriptor WB path for RS bit with the same
-        * algorithm.
+        * if desc_count >= 4
+        *      mark RS bit
+        *      reset packet counter
+        * if desc_count > 0
+        *      update tail
         *
-        * Note: If there are less than 4 packets
+        * Note: If there are less than 4 descriptors
         * pending and interrupts were disabled the service task will
         * trigger a force WB.
         */
-       if (skb->xmit_more  &&
-           !netif_xmit_stopped(txring_txq(tx_ring))) {
-               tx_ring->flags |= I40E_TXR_FLAGS_LAST_XMIT_MORE_SET;
-               tail_bump = false;
-       } else if (!skb->xmit_more &&
-                  !netif_xmit_stopped(txring_txq(tx_ring)) &&
-                  (!(tx_ring->flags & I40E_TXR_FLAGS_LAST_XMIT_MORE_SET)) &&
-                  (tx_ring->packet_stride < WB_STRIDE) &&
-                  (desc_count < WB_STRIDE)) {
-               tx_ring->packet_stride++;
-       } else {
+       if (netif_xmit_stopped(txring_txq(tx_ring))) {
+               goto do_rs;
+       } else if (skb->xmit_more) {
+               /* set stride to arm on next packet and reset desc_count */
+               tx_ring->packet_stride = WB_STRIDE;
+               desc_count = 0;
+       } else if (desc_count >= WB_STRIDE) {
+do_rs:
+               /* write last descriptor with RS bit set */
+               td_cmd |= I40E_TX_DESC_CMD_RS;
                tx_ring->packet_stride = 0;
-               tx_ring->flags &= ~I40E_TXR_FLAGS_LAST_XMIT_MORE_SET;
-               do_rs = true;
        }
-       if (do_rs)
-               tx_ring->packet_stride = 0;
 
        tx_desc->cmd_type_offset_bsz =
-                       build_ctob(td_cmd, td_offset, size, td_tag) |
-                       cpu_to_le64((u64)(do_rs ? I40E_TXD_CMD :
-                                                 I40E_TX_DESC_CMD_EOP) <<
-                                                 I40E_TXD_QW1_CMD_SHIFT);
+                       build_ctob(td_cmd, td_offset, size, td_tag);
+
+       /* Force memory writes to complete before letting h/w know there
+        * are new descriptors to fetch.
+        *
+        * We also use this memory barrier to make certain all of the
+        * status bits have been updated before next_to_watch is written.
+        */
+       wmb();
+
+       /* set next_to_watch value indicating a packet is present */
+       first->next_to_watch = tx_desc;
 
        /* notify HW of packet */
-       if (!tail_bump) {
-               prefetchw(tx_desc + 1);
-       } else {
-               /* Force memory writes to complete before letting h/w
-                * know there are new descriptors to fetch.  (Only
-                * applicable for weak-ordered memory model archs,
-                * such as IA-64).
-                */
-               wmb();
+       if (desc_count) {
                writel(i, tx_ring->tail);
+
+               /* we need this if more than one processor can write to our tail
+                * at a time, it synchronizes IO on IA64/Altix systems
+                */
+               mmiowb();
        }
+
        return;
 
 dma_error:
index 42f04d69c4d19c6083868b97f0daae30c5b4d34f..de8550f4e3a4dd8d53a0ab9e37b0c4f1a8b19caa 100644 (file)
@@ -313,7 +313,6 @@ struct i40e_ring {
 
        u16 flags;
 #define I40E_TXR_FLAGS_WB_ON_ITR       BIT(0)
-#define I40E_TXR_FLAGS_LAST_XMIT_MORE_SET BIT(2)
 
        /* stats structs */
        struct i40e_queue_stats stats;
index 51d8d969f3dc52c7f6a69f219d298b4b6a1e8c6e..5d56898e76bb594fc7cd2303f714dead6242fb1f 100644 (file)
@@ -151,7 +151,7 @@ u32 i40evf_get_tx_pending(struct i40e_ring *ring, bool in_sw)
        return 0;
 }
 
-#define WB_STRIDE 0x3
+#define WB_STRIDE 4
 
 /**
  * i40e_clean_tx_irq - Reclaim resources after transmit completes
@@ -265,7 +265,7 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
                unsigned int j = i40evf_get_tx_pending(tx_ring, false);
 
                if (budget &&
-                   ((j / (WB_STRIDE + 1)) == 0) && (j > 0) &&
+                       ((j / WB_STRIDE) == 0) && (j > 0) &&
                    !test_bit(__I40E_DOWN, &tx_ring->vsi->state) &&
                    (I40E_DESC_UNUSED(tx_ring) != tx_ring->count))
                        tx_ring->arm_wb = true;
@@ -1942,9 +1942,7 @@ static inline void i40evf_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
        u32 td_tag = 0;
        dma_addr_t dma;
        u16 gso_segs;
-       u16 desc_count = 0;
-       bool tail_bump = true;
-       bool do_rs = false;
+       u16 desc_count = 1;
 
        if (tx_flags & I40E_TX_FLAGS_HW_VLAN) {
                td_cmd |= I40E_TX_DESC_CMD_IL2TAG1;
@@ -2027,8 +2025,7 @@ static inline void i40evf_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
                tx_bi = &tx_ring->tx_bi[i];
        }
 
-       /* set next_to_watch value indicating a packet is present */
-       first->next_to_watch = tx_desc;
+       netdev_tx_sent_queue(txring_txq(tx_ring), first->bytecount);
 
        i++;
        if (i == tx_ring->count)
@@ -2036,66 +2033,72 @@ static inline void i40evf_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb,
 
        tx_ring->next_to_use = i;
 
-       netdev_tx_sent_queue(txring_txq(tx_ring), first->bytecount);
        i40e_maybe_stop_tx(tx_ring, DESC_NEEDED);
 
+       /* write last descriptor with EOP bit */
+       td_cmd |= I40E_TX_DESC_CMD_EOP;
+
+       /* We can OR these values together as they both are checked against
+        * 4 below and at this point desc_count will be used as a boolean value
+        * after this if/else block.
+        */
+       desc_count |= ++tx_ring->packet_stride;
+
        /* Algorithm to optimize tail and RS bit setting:
-        * if xmit_more is supported
-        *      if xmit_more is true
-        *              do not update tail and do not mark RS bit.
-        *      if xmit_more is false and last xmit_more was false
-        *              if every packet spanned less than 4 desc
-        *                      then set RS bit on 4th packet and update tail
-        *                      on every packet
-        *              else
-        *                      update tail and set RS bit on every packet.
-        *      if xmit_more is false and last_xmit_more was true
-        *              update tail and set RS bit.
+        * if queue is stopped
+        *      mark RS bit
+        *      reset packet counter
+        * else if xmit_more is supported and is true
+        *      advance packet counter to 4
+        *      reset desc_count to 0
         *
-        * Optimization: wmb to be issued only in case of tail update.
-        * Also optimize the Descriptor WB path for RS bit with the same
-        * algorithm.
+        * if desc_count >= 4
+        *      mark RS bit
+        *      reset packet counter
+        * if desc_count > 0
+        *      update tail
         *
-        * Note: If there are less than 4 packets
+        * Note: If there are less than 4 descriptors
         * pending and interrupts were disabled the service task will
         * trigger a force WB.
         */
-       if (skb->xmit_more  &&
-           !netif_xmit_stopped(txring_txq(tx_ring))) {
-               tx_ring->flags |= I40E_TXR_FLAGS_LAST_XMIT_MORE_SET;
-               tail_bump = false;
-       } else if (!skb->xmit_more &&
-                  !netif_xmit_stopped(txring_txq(tx_ring)) &&
-                  (!(tx_ring->flags & I40E_TXR_FLAGS_LAST_XMIT_MORE_SET)) &&
-                  (tx_ring->packet_stride < WB_STRIDE) &&
-                  (desc_count < WB_STRIDE)) {
-               tx_ring->packet_stride++;
-       } else {
+       if (netif_xmit_stopped(txring_txq(tx_ring))) {
+               goto do_rs;
+       } else if (skb->xmit_more) {
+               /* set stride to arm on next packet and reset desc_count */
+               tx_ring->packet_stride = WB_STRIDE;
+               desc_count = 0;
+       } else if (desc_count >= WB_STRIDE) {
+do_rs:
+               /* write last descriptor with RS bit set */
+               td_cmd |= I40E_TX_DESC_CMD_RS;
                tx_ring->packet_stride = 0;
-               tx_ring->flags &= ~I40E_TXR_FLAGS_LAST_XMIT_MORE_SET;
-               do_rs = true;
        }
-       if (do_rs)
-               tx_ring->packet_stride = 0;
 
        tx_desc->cmd_type_offset_bsz =
-                       build_ctob(td_cmd, td_offset, size, td_tag) |
-                       cpu_to_le64((u64)(do_rs ? I40E_TXD_CMD :
-                                                 I40E_TX_DESC_CMD_EOP) <<
-                                                 I40E_TXD_QW1_CMD_SHIFT);
+                       build_ctob(td_cmd, td_offset, size, td_tag);
+
+       /* Force memory writes to complete before letting h/w know there
+        * are new descriptors to fetch.
+        *
+        * We also use this memory barrier to make certain all of the
+        * status bits have been updated before next_to_watch is written.
+        */
+       wmb();
+
+       /* set next_to_watch value indicating a packet is present */
+       first->next_to_watch = tx_desc;
 
        /* notify HW of packet */
-       if (!tail_bump) {
-               prefetchw(tx_desc + 1);
-       } else {
-               /* Force memory writes to complete before letting h/w
-                * know there are new descriptors to fetch.  (Only
-                * applicable for weak-ordered memory model archs,
-                * such as IA-64).
-                */
-               wmb();
+       if (desc_count) {
                writel(i, tx_ring->tail);
+
+               /* we need this if more than one processor can write to our tail
+                * at a time, it synchronizes IO on IA64/Altix systems
+                */
+               mmiowb();
        }
+
        return;
 
 dma_error:
index abcdecabbc560b471ad857d9f96840d1c7248b54..a586e19cfd1d77b0e7ad25d167760a95d61110c4 100644 (file)
@@ -309,7 +309,6 @@ struct i40e_ring {
        bool ring_active;               /* is ring online or not */
        bool arm_wb;            /* do something to arm write back */
        u8 packet_stride;
-#define I40E_TXR_FLAGS_LAST_XMIT_MORE_SET BIT(2)
 
        u16 flags;
 #define I40E_TXR_FLAGS_WB_ON_ITR       BIT(0)