[PATCH v4-S3 65/65] net/dpaa2: add Tx fast path for no-confirmation case

Prashant Gupta prashant.gupta_3 at nxp.com
Fri Oct 23 15:43:45 CEST 2026


From: Jun Yang <jun.yang at nxp.com>

Split a dedicated Tx fast path out of dpaa2_dev_tx() for the common
no-confirmation configuration, keeping the hot enqueue loop free of the
Tx-conf and timestamp bookkeeping needed only by the slow path.

- Add dpaa2_dev_tx_fast() for the DPAA2_TX_NO_CONF case. dpaa2_dev_tx()
  builds the enqueue descriptor and dispatches straight to it, so the
  common path no longer runs the per-burst Tx-conf drain or the
  per-packet timestamp accounting.
- Factor the retry enqueue loop into dpaa2_dev_tx_enqueue_multiple() and
  the ordered-queue tail into dpaa2_dev_tx_multi_ordered(), shared by
  both the fast and slow paths to remove duplicated code.
- Zero-initialise fd_arr in the slow path and mark the rarely taken
  branches (congestion retry, VLAN insert, ordered, timestamp) unlikely.

This reduces per-packet work on the common Tx path.

Signed-off-by: Jun Yang <jun.yang at nxp.com>
---
 drivers/net/dpaa2/dpaa2_rxtx.c | 158 +++++++++++++++++++++++++--------
 1 file changed, 122 insertions(+), 36 deletions(-)

diff --git a/drivers/net/dpaa2/dpaa2_rxtx.c b/drivers/net/dpaa2/dpaa2_rxtx.c
index 2af5a4745d..312c9bd7d5 100644
--- a/drivers/net/dpaa2/dpaa2_rxtx.c
+++ b/drivers/net/dpaa2/dpaa2_rxtx.c
@@ -1511,6 +1511,114 @@ dpaa2_dev_tx_ordered(void *queue, struct rte_mbuf **bufs,
 	return dpaa2_dev_tx_multi_txq_ordered(mq, bufs, nb_pkts);
 }
 
+static __rte_always_inline uint16_t __rte_hot
+dpaa2_dev_tx_enqueue_multiple(struct qbman_swp *swp,
+	const struct qbman_fd *fd, uint16_t to_send,
+	const struct qbman_eq_desc *eqdesc)
+{
+	uint16_t loop = 0, retry_count = 0;
+	int eq_ret;
+
+	while (loop < to_send) {
+		eq_ret = qbman_swp_enqueue_multiple(swp, eqdesc,
+			&fd[loop], NULL, to_send - loop);
+		if (unlikely(eq_ret < 0)) {
+			retry_count++;
+			if (retry_count > DPAA2_MAX_TX_RETRY_COUNT)
+				break;
+		} else {
+			loop += eq_ret;
+			retry_count = 0;
+		}
+	}
+
+	return loop;
+}
+
+static __rte_noinline uint16_t
+dpaa2_dev_tx_multi_ordered(struct dpaa2_queue *dpaa2_q,
+	struct rte_mbuf **bufs, uint16_t nb_pkts)
+{
+	uint16_t to_send, order_tx = 0, total = 0;
+
+order_tx_again:
+	to_send = (nb_pkts > dpaa2_eqcr_size) ? dpaa2_eqcr_size : nb_pkts;
+	order_tx = dpaa2_dev_tx_ordered(dpaa2_q, bufs, to_send);
+	bufs += order_tx;
+	nb_pkts -= order_tx;
+	total += order_tx;
+	if (nb_pkts && order_tx >= to_send)
+		goto order_tx_again;
+
+	return total;
+}
+
+static __rte_always_inline uint16_t __rte_hot
+dpaa2_dev_tx_fast(struct dpaa2_queue *dpaa2_q, struct rte_mbuf **bufs,
+	uint16_t nb_pkts, struct qbman_swp *swp, struct qbman_fd *fd_arr,
+	const struct qbman_eq_desc *eqdesc, struct rte_mempool *hw_mp)
+{
+	/* Function to transmit the frames to given device and VQ*/
+	uint32_t loop, retry_count, frames_to_send;
+	int32_t ret, order = false;
+	uint16_t num_tx = 0, eq_ret = 0;
+
+tx_again:
+	/*Check if the queue is congested*/
+	retry_count = 0;
+	while (qbman_result_SCN_state(dpaa2_q->cscn)) {
+		retry_count++;
+		/* Retry for some time before giving up */
+		if (retry_count > CONG_RETRY_COUNT)
+			goto skip_tx;
+	}
+
+	frames_to_send = (nb_pkts > dpaa2_eqcr_size) ? dpaa2_eqcr_size : nb_pkts;
+
+	for (loop = 0; loop < frames_to_send; loop++) {
+		if (unlikely(dpaa2_mbuf_seq_is_flag_set((*bufs),
+			(DPAA2_ENQUEUE_FLAG_ORP | QBMAN_ENQUEUE_FLAG_DCA)))) {
+			order = true;
+			break;
+		}
+
+		if (unlikely((*bufs)->ol_flags & RTE_MBUF_F_TX_VLAN)) {
+			ret = rte_vlan_insert(bufs);
+			if (ret)
+				break;
+		}
+		if (likely(RTE_MBUF_DIRECT(*bufs) &&
+			(*bufs)->pool->ops_index == hw_mp->ops_index &&
+			(*bufs)->nb_segs == 1 && rte_mbuf_refcnt_read(*bufs) == 1)) {
+			DPAA2_MBUF_TO_CONTIG_FD((*bufs), &fd_arr[loop],
+				mempool_to_bpid((*bufs)->pool));
+			ret = 0;
+		} else if (unlikely((*bufs)->nb_segs > 1)) {
+			ret = dpaa2_dev_tx_mbuf_to_sg_fd(hw_mp, *bufs, &fd_arr[loop],
+				dpaa2_q, DPAA2_TX_NO_CONF, false);
+		} else {
+			ret = dpaa2_dev_tx_mbuf_to_simple_fd(hw_mp, *bufs, &fd_arr[loop],
+				dpaa2_q, DPAA2_TX_NO_CONF, false);
+		}
+		if (ret)
+			break;
+		bufs++;
+	}
+
+	eq_ret = dpaa2_dev_tx_enqueue_multiple(swp, fd_arr, loop, eqdesc);
+	num_tx += eq_ret;
+	nb_pkts -= eq_ret;
+	if (unlikely(nb_pkts > 0 && !ret && !order))
+		goto tx_again;
+
+skip_tx:
+	dpaa2_q->tx_pkts += num_tx;
+	if (unlikely(order && eq_ret >= loop))
+		num_tx += dpaa2_dev_tx_multi_ordered(dpaa2_q, bufs, nb_pkts);
+
+	return num_tx;
+}
+
 /*
  * Callback to handle sending packets through WRIOP based interface
  */
@@ -1519,12 +1627,12 @@ dpaa2_dev_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 {
 	/* Function to transmit the frames to given device and VQ*/
 	uint32_t loop, retry_count, i, ptp_n, frames_to_send;
-	int32_t ret, tstamp[MAX_TX_RING_SLOTS], ptp_set, order = false, eq_ret = 0;
-	struct qbman_fd fd_arr[MAX_TX_RING_SLOTS];
+	int32_t ret, tstamp[MAX_TX_RING_SLOTS], ptp_set, order = false;
+	struct qbman_fd fd_arr[MAX_TX_RING_SLOTS] = {0};
 	struct qbman_eq_desc eqdesc;
 	struct dpaa2_queue *dpaa2_q = queue;
 	struct qbman_swp *swp;
-	uint16_t num_tx = 0, order_tx;
+	uint16_t num_tx = 0, eq_ret = 0;
 	struct rte_eth_dev_data *eth_data = dpaa2_q->eth_data;
 	struct dpaa2_dev_priv *priv = eth_data->dev_private;
 	struct rte_mempool *hw_mp;
@@ -1549,15 +1657,15 @@ dpaa2_dev_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 	}
 	hw_mp = priv->bp_list->mp;
 
-	if (dpaa2_q->tx_conf_queue)
-		dpaa2_dev_tx_conf(dpaa2_q->tx_conf_queue, false);
-
 	/*Prepare enqueue descriptor*/
 	qbman_eq_desc_clear(&eqdesc);
 	qbman_eq_desc_set_no_orp(&eqdesc, DPAA2_EQ_RESP_ERR_FQ);
 	qbman_eq_desc_set_fq(&eqdesc, dpaa2_q->fqid);
+	if (likely(priv->tx_conf_type == DPAA2_TX_NO_CONF))
+		return dpaa2_dev_tx_fast(dpaa2_q, bufs, nb_pkts, swp, fd_arr, &eqdesc, hw_mp);
 
-	/*Clear the unused FD fields before sending*/
+	if (dpaa2_q->tx_conf_queue)
+		dpaa2_dev_tx_conf(dpaa2_q->tx_conf_queue, false);
 
 tx_again:
 	/*Check if the queue is congested*/
@@ -1617,27 +1725,13 @@ dpaa2_dev_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 		bufs++;
 	}
 
-	frames_to_send = loop;
-	loop = 0;
-	retry_count = 0;
-	while (loop < frames_to_send) {
-		eq_ret = qbman_swp_enqueue_multiple(swp, &eqdesc,
-			&fd_arr[loop], NULL, frames_to_send - loop);
-		if (unlikely(eq_ret < 0)) {
-			retry_count++;
-			if (retry_count > DPAA2_MAX_TX_RETRY_COUNT)
-				break;
-		} else {
-			loop += eq_ret;
-			retry_count = 0;
-		}
-	}
+	eq_ret = dpaa2_dev_tx_enqueue_multiple(swp, fd_arr, loop, &eqdesc);
+	num_tx += eq_ret;
+	nb_pkts -= eq_ret;
 
-	num_tx += loop;
-	nb_pkts -= loop;
 	if (priv->tx_conf_type != DPAA2_TX_NO_CONF) {
-		for (i = 0; i < loop; i++) {
-			if (tstamp[i]) {
+		for (i = 0; i < eq_ret; i++) {
+			if (unlikely(tstamp[i])) {
 				rte_atomic_fetch_add_explicit(&dpaa2_q->tx_conf_queue->ts_to_cnfd,
 					1, rte_memory_order_relaxed);
 			}
@@ -1648,16 +1742,8 @@ dpaa2_dev_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 
 skip_tx:
 	dpaa2_q->tx_pkts += num_tx;
-	if (order && eq_ret >= 0) {
-order_tx_again:
-		frames_to_send = (nb_pkts > dpaa2_eqcr_size) ? dpaa2_eqcr_size : nb_pkts;
-		nb_pkts -= frames_to_send;
-		order_tx = dpaa2_dev_tx_ordered(queue, bufs, frames_to_send);
-		num_tx += order_tx;
-		bufs += frames_to_send;
-		if (nb_pkts && order_tx >= frames_to_send)
-			goto order_tx_again;
-	}
+	if (unlikely(order && eq_ret >= loop))
+		num_tx += dpaa2_dev_tx_multi_ordered(dpaa2_q, bufs, nb_pkts);
 
 	return num_tx;
 }
-- 
2.43.0



More information about the dev mailing list