Add support to the ice driver for the API rte_eth_tx_done_cleanup
to force free consumed buffers on Tx ring.

Signed-off-by: Chenxu Di <chenxux...@intel.com>
---
 drivers/net/ice/ice_ethdev.c |   1 +
 drivers/net/ice/ice_rxtx.c   | 123 +++++++++++++++++++++++++++++++++++
 drivers/net/ice/ice_rxtx.h   |   1 +
 3 files changed, 125 insertions(+)

diff --git a/drivers/net/ice/ice_ethdev.c b/drivers/net/ice/ice_ethdev.c
index de189daba..b55cdbf74 100644
--- a/drivers/net/ice/ice_ethdev.c
+++ b/drivers/net/ice/ice_ethdev.c
@@ -220,6 +220,7 @@ static const struct eth_dev_ops ice_eth_dev_ops = {
        .filter_ctrl                  = ice_dev_filter_ctrl,
        .udp_tunnel_port_add          = ice_dev_udp_tunnel_port_add,
        .udp_tunnel_port_del          = ice_dev_udp_tunnel_port_del,
+       .tx_done_cleanup              = ice_tx_done_cleanup,
 };
 
 /* store statistics names and its offset in stats structure */
diff --git a/drivers/net/ice/ice_rxtx.c b/drivers/net/ice/ice_rxtx.c
index 2db174456..4aead98fd 100644
--- a/drivers/net/ice/ice_rxtx.c
+++ b/drivers/net/ice/ice_rxtx.c
@@ -863,6 +863,129 @@ ice_fdir_tx_queue_stop(struct rte_eth_dev *dev, uint16_t 
tx_queue_id)
        return 0;
 }
 
+
+int ice_tx_done_cleanup(void *q, uint32_t free_cnt)
+{
+       struct ice_tx_queue *txq = (struct ice_tx_queue *)q;
+       struct ice_tx_entry *sw_ring;
+       volatile struct ice_tx_desc *txr;
+       uint16_t tx_first; /* First segment analyzed. */
+       uint16_t tx_id;    /* Current segment being processed. */
+       uint16_t tx_last;  /* Last segment in the current packet. */
+       uint16_t tx_next;  /* First segment of the next packet. */
+       int count;
+
+       if (txq == NULL)
+               return -ENODEV;
+
+       count = 0;
+       sw_ring = txq->sw_ring;
+       txr = txq->tx_ring;
+
+       /*
+        * tx_tail is the last sent packet on the sw_ring. Goto the end
+        * of that packet (the last segment in the packet chain) and
+        * then the next segment will be the start of the oldest segment
+        * in the sw_ring. This is the first packet that will be
+        * attempted to be freed.
+        */
+
+       /* Get last segment in most recently added packet. */
+       tx_first = sw_ring[txq->tx_tail].last_id;
+
+       /* Get the next segment, which is the oldest segment in ring. */
+       tx_first = sw_ring[tx_first].next_id;
+
+       /* Set the current index to the first. */
+       tx_id = tx_first;
+
+       /*
+        * Loop through each packet. For each packet, verify that an
+        * mbuf exists and that the last segment is free. If so, free
+        * it and move on.
+        */
+       while (1) {
+               tx_last = sw_ring[tx_id].last_id;
+
+               if (sw_ring[tx_last].mbuf) {
+                       if ((txr[tx_last].cmd_type_offset_bsz &
+                               rte_cpu_to_le_64(ICE_TXD_QW1_DTYPE_M)) !=
+                               rte_cpu_to_le_64(ICE_TX_DESC_DTYPE_DESC_DONE)) {
+                               /*
+                                * Increment the number of packets
+                                * freed.
+                                */
+                               count++;
+
+                               /* Get the start of the next packet. */
+                               tx_next = sw_ring[tx_last].next_id;
+
+                               /*
+                                * Loop through all segments in a
+                                * packet.
+                                */
+                               do {
+                                       
rte_pktmbuf_free_seg(sw_ring[tx_id].mbuf);
+                                       sw_ring[tx_id].mbuf = NULL;
+                                       sw_ring[tx_id].last_id = tx_id;
+
+                                       /* Move to next segemnt. */
+                                       tx_id = sw_ring[tx_id].next_id;
+
+                               } while (tx_id != tx_next);
+
+                               if (unlikely(count == (int)free_cnt))
+                                       break;
+                       } else {
+                               /*
+                                * mbuf still in use, nothing left to
+                                * free.
+                                */
+                               break;
+                       }
+               } else {
+                       /*
+                        * There are multiple reasons to be here:
+                        * 1) All the packets on the ring have been
+                        *    freed - tx_id is equal to tx_first
+                        *    and some packets have been freed.
+                        *    - Done, exit
+                        * 2) Interfaces has not sent a rings worth of
+                        *    packets yet, so the segment after tail is
+                        *    still empty. Or a previous call to this
+                        *    function freed some of the segments but
+                        *    not all so there is a hole in the list.
+                        *    Hopefully this is a rare case.
+                        *    - Walk the list and find the next mbuf. If
+                        *      there isn't one, then done.
+                        */
+                       if (likely(tx_id == tx_first && count != 0))
+                               break;
+
+                       /*
+                        * Walk the list and find the next mbuf, if any.
+                        */
+                       do {
+                               /* Move to next segemnt. */
+                               tx_id = sw_ring[tx_id].next_id;
+
+                               if (sw_ring[tx_id].mbuf)
+                                       break;
+
+                       } while (tx_id != tx_first);
+
+                       /*
+                        * Determine why previous loop bailed. If there
+                        * is not an mbuf, done.
+                        */
+                       if (sw_ring[tx_id].mbuf == NULL)
+                               break;
+               }
+       }
+
+       return count;
+}
+
 int
 ice_rx_queue_setup(struct rte_eth_dev *dev,
                   uint16_t queue_idx,
diff --git a/drivers/net/ice/ice_rxtx.h b/drivers/net/ice/ice_rxtx.h
index 9e3d2cd07..8d4232a61 100644
--- a/drivers/net/ice/ice_rxtx.h
+++ b/drivers/net/ice/ice_rxtx.h
@@ -183,6 +183,7 @@ int ice_rx_descriptor_status(void *rx_queue, uint16_t 
offset);
 int ice_tx_descriptor_status(void *tx_queue, uint16_t offset);
 void ice_set_default_ptype_table(struct rte_eth_dev *dev);
 const uint32_t *ice_dev_supported_ptypes_get(struct rte_eth_dev *dev);
+int ice_tx_done_cleanup(void *txq, uint32_t free_cnt);
 
 int ice_rx_vec_dev_check(struct rte_eth_dev *dev);
 int ice_tx_vec_dev_check(struct rte_eth_dev *dev);
-- 
2.17.1

Reply via email to