Due to significant differences in the ixgbe transmit descriptors, the
ixgbe driver does not use the common scalar Tx functionality. Update the
driver directly so its use of the rs_last_id array matches that of the
common Tx code.

Signed-off-by: Bruce Richardson <[email protected]>
---
 drivers/net/intel/ixgbe/ixgbe_rxtx.c | 86 +++++++++++++++-------------
 1 file changed, 47 insertions(+), 39 deletions(-)

diff --git a/drivers/net/intel/ixgbe/ixgbe_rxtx.c 
b/drivers/net/intel/ixgbe/ixgbe_rxtx.c
index a7583c178a..3eeec220fd 100644
--- a/drivers/net/intel/ixgbe/ixgbe_rxtx.c
+++ b/drivers/net/intel/ixgbe/ixgbe_rxtx.c
@@ -43,6 +43,7 @@
 #include <rte_ip.h>
 #include <rte_net.h>
 #include <rte_vect.h>
+#include <rte_bitops.h>
 
 #include "ixgbe_logs.h"
 #include "base/ixgbe_api.h"
@@ -571,57 +572,35 @@ tx_desc_ol_flags_to_cmdtype(uint64_t ol_flags)
 static inline int
 ixgbe_xmit_cleanup(struct ci_tx_queue *txq)
 {
-       struct ci_tx_entry *sw_ring = txq->sw_ring;
        volatile union ixgbe_adv_tx_desc *txr = txq->ixgbe_tx_ring;
-       uint16_t last_desc_cleaned = txq->last_desc_cleaned;
-       uint16_t nb_tx_desc = txq->nb_tx_desc;
-       uint16_t desc_to_clean_to;
-       uint16_t nb_tx_to_clean;
-       uint32_t status;
+       const uint16_t last_desc_cleaned = txq->last_desc_cleaned;
+       const uint16_t nb_tx_desc = txq->nb_tx_desc;
 
-       /* Determine the last descriptor needing to be cleaned */
-       desc_to_clean_to = (uint16_t)(last_desc_cleaned + txq->tx_rs_thresh);
-       if (desc_to_clean_to >= nb_tx_desc)
-               desc_to_clean_to = (uint16_t)(desc_to_clean_to - nb_tx_desc);
+       const uint16_t rs_idx = (last_desc_cleaned == nb_tx_desc - 1) ?
+                       0 :
+                       (last_desc_cleaned + 1) >> txq->log2_rs_thresh;
+       uint16_t desc_to_clean_to = (rs_idx << txq->log2_rs_thresh) + 
(txq->tx_rs_thresh - 1);
 
-       /* Check to make sure the last descriptor to clean is done */
-       desc_to_clean_to = sw_ring[desc_to_clean_to].last_id;
-       status = txr[desc_to_clean_to].wb.status;
+       uint32_t status = txr[txq->rs_last_id[rs_idx]].wb.status;
        if (!(status & rte_cpu_to_le_32(IXGBE_TXD_STAT_DD))) {
                PMD_TX_LOG(DEBUG,
                           "TX descriptor %4u is not done"
                           "(port=%d queue=%d)",
-                          desc_to_clean_to,
+                          txq->rs_last_id[rs_idx],
                           txq->port_id, txq->queue_id);
                /* Failed to clean any descriptors, better luck next time */
                return -(1);
        }
 
-       /* Figure out how many descriptors will be cleaned */
-       if (last_desc_cleaned > desc_to_clean_to)
-               nb_tx_to_clean = (uint16_t)((nb_tx_desc - last_desc_cleaned) +
-                                                       desc_to_clean_to);
-       else
-               nb_tx_to_clean = (uint16_t)(desc_to_clean_to -
-                                               last_desc_cleaned);
-
        PMD_TX_LOG(DEBUG,
                   "Cleaning %4u TX descriptors: %4u to %4u "
                   "(port=%d queue=%d)",
-                  nb_tx_to_clean, last_desc_cleaned, desc_to_clean_to,
+                  txq->tx_rs_thresh, last_desc_cleaned, desc_to_clean_to,
                   txq->port_id, txq->queue_id);
 
-       /*
-        * The last descriptor to clean is done, so that means all the
-        * descriptors from the last descriptor that was cleaned
-        * up to the last descriptor with the RS bit set
-        * are done. Only reset the threshold descriptor.
-        */
-       txr[desc_to_clean_to].wb.status = 0;
-
        /* Update the txq to reflect the last descriptor that was cleaned */
        txq->last_desc_cleaned = desc_to_clean_to;
-       txq->nb_tx_free = (uint16_t)(txq->nb_tx_free + nb_tx_to_clean);
+       txq->nb_tx_free = (uint16_t)(txq->nb_tx_free + txq->tx_rs_thresh);
 
        /* No Error */
        return 0;
@@ -749,6 +728,9 @@ ixgbe_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
                if (tx_last >= txq->nb_tx_desc)
                        tx_last = (uint16_t) (tx_last - txq->nb_tx_desc);
 
+               /* Track the RS threshold bucket at packet start */
+               uint16_t pkt_rs_idx = (uint16_t)(tx_id >> txq->log2_rs_thresh);
+
                PMD_TX_LOG(DEBUG, "port_id=%u queue_id=%u pktlen=%u"
                           " tx_first=%u tx_last=%u",
                           (unsigned) txq->port_id,
@@ -876,7 +858,6 @@ ixgbe_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
                                        tx_offload,
                                        rte_security_dynfield(tx_pkt));
 
-                               txe->last_id = tx_last;
                                tx_id = txe->next_id;
                                txe = txn;
                        }
@@ -922,7 +903,6 @@ ixgbe_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
                                rte_cpu_to_le_32(cmd_type_len | slen);
                        txd->read.olinfo_status =
                                rte_cpu_to_le_32(olinfo_status);
-                       txe->last_id = tx_last;
                        tx_id = txe->next_id;
                        txe = txn;
                        m_seg = m_seg->next;
@@ -935,8 +915,18 @@ ixgbe_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
                txq->nb_tx_used = (uint16_t)(txq->nb_tx_used + nb_used);
                txq->nb_tx_free = (uint16_t)(txq->nb_tx_free - nb_used);
 
-               /* Set RS bit only on threshold packets' last descriptor */
-               if (txq->nb_tx_used >= txq->tx_rs_thresh) {
+               /*
+                * Check if packet crosses into a new RS threshold bucket.
+                * The RS bit is set on the last descriptor when we move from 
one bucket to another.
+                * For example, with tx_rs_thresh=32 and a 5-descriptor packet 
using slots 30-34:
+                *   - pkt_rs_idx = 30 >> 5 = 0 (started in bucket 0)
+                *   - tx_last = 34, so 35 >> 5 = 1 (next packet is in bucket 1)
+                *   - Since 0 != 1, set RS bit on descriptor 34, and record 
rs_last_id[0] = 34
+                */
+               uint16_t next_rs_idx = ((tx_last + 1) >> txq->log2_rs_thresh);
+
+               if (next_rs_idx != pkt_rs_idx) {
+                       /* Packet crossed into a new bucket - set RS bit on 
last descriptor */
                        PMD_TX_LOG(DEBUG,
                                   "Setting RS bit on TXD id="
                                   "%4u (port=%d queue=%d)",
@@ -944,9 +934,8 @@ ixgbe_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
 
                        cmd_type_len |= IXGBE_TXD_CMD_RS;
 
-                       /* Update txq RS bit counters */
-                       txq->nb_tx_used = 0;
-                       txp = NULL;
+                       /* Record the last descriptor ID for the bucket we're 
leaving */
+                       txq->rs_last_id[pkt_rs_idx] = tx_last;
                } else
                        txp = txd;
 
@@ -2521,6 +2510,7 @@ ixgbe_tx_queue_release(struct ci_tx_queue *txq)
        if (txq != NULL && txq->ops != NULL) {
                ci_txq_release_all_mbufs(txq, false);
                txq->ops->free_swring(txq);
+               rte_free(txq->rs_last_id);
                rte_memzone_free(txq->mz);
                rte_free(txq);
        }
@@ -2825,6 +2815,13 @@ ixgbe_dev_tx_queue_setup(struct rte_eth_dev *dev,
                             (int)dev->data->port_id, (int)queue_idx);
                return -(EINVAL);
        }
+       if (!rte_is_power_of_2(tx_rs_thresh)) {
+               PMD_INIT_LOG(ERR, "tx_rs_thresh must be a power of 2. 
(tx_rs_thresh=%u port=%d queue=%d)",
+                            (unsigned int)tx_rs_thresh,
+                            (int)dev->data->port_id,
+                            (int)queue_idx);
+               return -(EINVAL);
+       }
 
        /*
         * If rs_bit_thresh is greater than 1, then TX WTHRESH should be
@@ -2870,6 +2867,7 @@ ixgbe_dev_tx_queue_setup(struct rte_eth_dev *dev,
        txq->mz = tz;
        txq->nb_tx_desc = nb_desc;
        txq->tx_rs_thresh = tx_rs_thresh;
+       txq->log2_rs_thresh = rte_log2_u32(tx_rs_thresh);
        txq->tx_free_thresh = tx_free_thresh;
        txq->pthresh = tx_conf->tx_thresh.pthresh;
        txq->hthresh = tx_conf->tx_thresh.hthresh;
@@ -2911,6 +2909,16 @@ ixgbe_dev_tx_queue_setup(struct rte_eth_dev *dev,
        PMD_INIT_LOG(DEBUG, "sw_ring=%p hw_ring=%p dma_addr=0x%"PRIx64,
                     txq->sw_ring, txq->ixgbe_tx_ring, txq->tx_ring_dma);
 
+       /* Allocate RS last_id tracking array */
+       uint16_t num_rs_buckets = nb_desc / tx_rs_thresh;
+       txq->rs_last_id = rte_zmalloc_socket(NULL, sizeof(txq->rs_last_id[0]) * 
num_rs_buckets,
+                       RTE_CACHE_LINE_SIZE, socket_id);
+       if (txq->rs_last_id == NULL) {
+               ixgbe_tx_queue_release(txq);
+               PMD_DRV_LOG(ERR, "Failed to allocate memory for RS last_id 
array");
+               return -ENOMEM;
+       }
+
        /* set up vector or scalar TX function as appropriate */
        ixgbe_set_tx_function(dev, txq);
 
-- 
2.51.0

Reply via email to