[PATCH v4-S3 38/65] net/dpaa2: add multi-port Tx API

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


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

Add a public API to transmit an array of packets whose destination
port and Tx queue are given per packet, and clean up the ordered Tx
helpers it builds on.

- New API rte_dpaa2_dev_tx_multi_ports():
  takes per-packet port_id[] and txq_id[] arrays (txq_id NULL means
  queue 0 of each port), resolves each dpaa2_queue, and forwards to
  dpaa2_dev_tx_multi_txq_ordered(). This allows a single burst to span
  multiple ports.

- dpaa2_dev_tx_multi_txq_ordered() takes struct dpaa2_queue ** instead
  of void ** and no longer loops with tx_again or accumulates a running
  "sent" count; it enqueues one batch and returns the number sent. Tx
  confirmation is now done after enqueue only for queues that have a
  tx_conf_queue, and the buffer-pool lookup is deferred to the slow
  path.

- The dy_conf out-parameter is dropped from the mbuf-to-fd helpers
  (dpaa2_dev_tx_mbuf_to_sg_fd, dpaa2_dev_tx_mbuf_to_simple_fd,
  dpaa2_dev_tx_fast_mbuf_to_fd); it was written but never consumed.
  dpaa2_dev_tx_fast_mbuf_to_fd() now takes the private structure
  directly and reads tx_conf_type from it.

Signed-off-by: Jun Yang <jun.yang at nxp.com>
---
 drivers/event/dpaa2/dpaa2_eventdev.c |   2 +-
 drivers/net/dpaa2/dpaa2_ethdev.h     |   4 +-
 drivers/net/dpaa2/dpaa2_rxtx.c       | 127 ++++++++++++---------------
 drivers/net/dpaa2/rte_pmd_dpaa2.h    |   5 ++
 4 files changed, 66 insertions(+), 72 deletions(-)

diff --git a/drivers/event/dpaa2/dpaa2_eventdev.c b/drivers/event/dpaa2/dpaa2_eventdev.c
index 476decbbdc..be6d8bc3da 100644
--- a/drivers/event/dpaa2/dpaa2_eventdev.c
+++ b/drivers/event/dpaa2/dpaa2_eventdev.c
@@ -1095,7 +1095,7 @@ static uint16_t
 dpaa2_eventdev_txa_enqueue(void *port,
 	struct rte_event ev[], uint16_t nb_events)
 {
-	void *txq[MAX_TX_RING_SLOTS];
+	struct dpaa2_queue *txq[MAX_TX_RING_SLOTS];
 	struct rte_mbuf *m[MAX_TX_RING_SLOTS];
 	uint16_t sent = 0, burst, i, port_id, qid;
 
diff --git a/drivers/net/dpaa2/dpaa2_ethdev.h b/drivers/net/dpaa2/dpaa2_ethdev.h
index 8c0be81c95..e4dc7b7e4f 100644
--- a/drivers/net/dpaa2/dpaa2_ethdev.h
+++ b/drivers/net/dpaa2/dpaa2_ethdev.h
@@ -975,8 +975,8 @@ uint16_t dpaa2_dev_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts);
 uint16_t dpaa2_dev_tx_ordered(void *queue, struct rte_mbuf **bufs,
 			      uint16_t nb_pkts);
 __rte_internal
-uint16_t dpaa2_dev_tx_multi_txq_ordered(void **queue,
-		struct rte_mbuf **bufs, uint16_t nb_pkts);
+uint16_t dpaa2_dev_tx_multi_txq_ordered(struct dpaa2_queue **dpaa2_q,
+	struct rte_mbuf **bufs, uint16_t nb_pkts);
 
 void dpaa2_dev_free_eqresp_buf(uint16_t eqresp_ci, struct dpaa2_queue *dpaa2_q);
 void dpaa2_flow_clean(struct rte_eth_dev *dev, uint8_t tc_id,
diff --git a/drivers/net/dpaa2/dpaa2_rxtx.c b/drivers/net/dpaa2/dpaa2_rxtx.c
index 0d4fc18455..a44b991d1b 100644
--- a/drivers/net/dpaa2/dpaa2_rxtx.c
+++ b/drivers/net/dpaa2/dpaa2_rxtx.c
@@ -738,8 +738,7 @@ dpaa2_dev_tx_conf_mbuf_to_sge(struct qbman_sge *sgt,
 static int __rte_noinline __rte_hot
 dpaa2_dev_tx_mbuf_to_sg_fd(struct rte_mempool *hw_mp,
 	struct rte_mbuf *mbuf, struct qbman_fd *fd,
-	struct dpaa2_queue *txq, enum dpaa2_tx_conf_type conf,
-	uint8_t *dy_conf, int tstamp)
+	struct dpaa2_queue *txq, enum dpaa2_tx_conf_type conf, int tstamp)
 {
 	struct rte_mbuf *cur_seg = mbuf, *sg_mbuf;
 	struct qbman_sge *sgt;
@@ -841,8 +840,6 @@ dpaa2_dev_tx_mbuf_to_sg_fd(struct rte_mempool *hw_mp,
 		if (ret)
 			return ret;
 	}
-	if (dy_conf && need_dyconf)
-		*dy_conf = true;
 
 	return 0;
 }
@@ -867,8 +864,7 @@ dpaa2_dev_prefetch_next_psr(const struct qbman_result *dq)
 static int __rte_noinline __rte_hot
 dpaa2_dev_tx_mbuf_to_simple_fd(struct rte_mempool *hw_mp,
 	struct rte_mbuf *mbuf, struct qbman_fd *fd,
-	struct dpaa2_queue *txq, enum dpaa2_tx_conf_type conf,
-	uint8_t *dy_conf, int tstamp)
+	struct dpaa2_queue *txq, enum dpaa2_tx_conf_type conf, int tstamp)
 {
 	int need_dyconf = false, need_conf = false;
 	struct rte_mbuf *mi;
@@ -905,13 +901,10 @@ dpaa2_dev_tx_mbuf_to_simple_fd(struct rte_mempool *hw_mp,
 		rte_pktmbuf_free(mbuf);
 	}
 
-	if (need_dyconf) {
+	if (need_dyconf)
 		dpaa2_dev_tx_config_dynamic_confirm(fd, txq, true, tstamp);
-		if (dy_conf)
-			*dy_conf = true;
-	} else if (tstamp) {
+	else if (tstamp)
 		dpaa2_dev_tx_enable_tstamp(fd);
-	}
 
 	return ret;
 }
@@ -1613,12 +1606,10 @@ uint16_t dpaa2_dev_tx_conf(void *txq, int drain)
 }
 
 static inline int
-dpaa2_dev_tx_fast_mbuf_to_fd(struct rte_eth_dev_data *dev,
-	struct rte_mbuf *buf, struct qbman_fd *fd,
-	enum dpaa2_tx_conf_type conf)
+dpaa2_dev_tx_fast_mbuf_to_fd(struct dpaa2_dev_priv *priv,
+	struct rte_mbuf *buf, struct qbman_fd *fd)
 {
 	struct rte_mempool *mp = buf->pool;
-	struct dpaa2_dev_priv *priv = dev->dev_private;
 
 	if (likely(RTE_MBUF_DIRECT(buf) &&
 		mp && mp->ops_index ==
@@ -1629,7 +1620,7 @@ dpaa2_dev_tx_fast_mbuf_to_fd(struct rte_eth_dev_data *dev,
 			DPAA2_PMD_WARN("Single mbuf has next segment(%p)",
 				buf->next);
 		}
-		if (unlikely(conf == DPAA2_TX_ABSOLUTE_CONF))
+		if (unlikely(priv->tx_conf_type == DPAA2_TX_ABSOLUTE_CONF))
 			dpaa2_mbuf_to_conf_contig_fd(buf, fd);
 		else
 			DPAA2_MBUF_TO_CONTIG_FD(buf, fd, mempool_to_bpid(mp));
@@ -1662,7 +1653,6 @@ dpaa2_dev_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 	struct dpaa2_dev_priv *priv = eth_data->dev_private;
 	struct rte_mempool *hw_mp;
 	uint32_t flags[MAX_TX_RING_SLOTS] = {0};
-	uint8_t dy_conf[MAX_TX_RING_SLOTS];
 
 	if (unlikely(!DPAA2_PER_LCORE_DPIO)) {
 		ret = dpaa2_affine_qbman_swp();
@@ -1709,7 +1699,6 @@ dpaa2_dev_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 		dpaa2_eqcr_size : nb_pkts;
 
 	for (loop = 0; loop < frames_to_send; loop++) {
-		dy_conf[loop] = false;
 		if (*dpaa2_seqn(*bufs)) {
 			uint8_t dqrr_index = *dpaa2_seqn(*bufs) - 1;
 
@@ -1739,8 +1728,7 @@ dpaa2_dev_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 			goto skip_fast_mbuf2fd;
 		}
 
-		ret = dpaa2_dev_tx_fast_mbuf_to_fd(eth_data,
-			*bufs, &fd_arr[loop], priv->tx_conf_type);
+		ret = dpaa2_dev_tx_fast_mbuf_to_fd(priv, *bufs, &fd_arr[loop]);
 		if (likely(!ret)) {
 			bufs++;
 			continue;
@@ -1749,10 +1737,10 @@ dpaa2_dev_tx(void *queue, struct rte_mbuf **bufs, uint16_t nb_pkts)
 skip_fast_mbuf2fd:
 		if (unlikely((*bufs)->nb_segs > 1)) {
 			ret = dpaa2_dev_tx_mbuf_to_sg_fd(hw_mp, *bufs, &fd_arr[loop],
-				dpaa2_q, priv->tx_conf_type, &dy_conf[loop], tstamp[loop]);
+				dpaa2_q, priv->tx_conf_type, tstamp[loop]);
 		} else {
 			ret = dpaa2_dev_tx_mbuf_to_simple_fd(hw_mp, *bufs, &fd_arr[loop],
-				dpaa2_q, priv->tx_conf_type, &dy_conf[loop], tstamp[loop]);
+				dpaa2_q, priv->tx_conf_type, tstamp[loop]);
 		}
 		if (ret)
 			goto send_n_return;
@@ -1849,11 +1837,9 @@ dpaa2_dev_free_eqresp_buf(uint16_t eqresp_ci,
 
 static void
 dpaa2_set_enqueue_descriptor(struct dpaa2_queue *dpaa2_q,
-			     struct rte_mbuf *m,
-			     struct qbman_eq_desc *eqdesc)
+	struct rte_mbuf *m, struct qbman_eq_desc *eqdesc)
 {
-	struct rte_eth_dev_data *eth_data = dpaa2_q->eth_data;
-	struct dpaa2_dev_priv *priv = eth_data->dev_private;
+	struct dpaa2_dev_priv *priv = dpaa2_q->eth_data->dev_private;
 	struct dpaa2_dpio_dev *dpio_dev = DPAA2_PER_LCORE_DPIO;
 	struct eqresp_metadata *eqresp_meta;
 	uint16_t orpid, seqnum;
@@ -1896,22 +1882,20 @@ dpaa2_set_enqueue_descriptor(struct dpaa2_queue *dpaa2_q,
 
 RTE_EXPORT_INTERNAL_SYMBOL(dpaa2_dev_tx_multi_txq_ordered)
 uint16_t
-dpaa2_dev_tx_multi_txq_ordered(void **queue,
+dpaa2_dev_tx_multi_txq_ordered(struct dpaa2_queue **dpaa2_q,
 	struct rte_mbuf **bufs, uint16_t nb_pkts)
 {
 	/* Function to transmit the frames to multiple queues respectively.*/
-	uint32_t loop, retry_count, sent = 0, i;
+	uint32_t loop, retry_count, i;
 	int32_t ret = 0, tstamp[MAX_TX_RING_SLOTS], ptp_set_count, ptp_set;
 	struct qbman_fd fd_arr[MAX_TX_RING_SLOTS];
 	uint32_t frames_to_send, num_free_eq_desc = 0;
 	struct rte_mempool *hw_mp;
 	struct qbman_eq_desc eqdesc[MAX_TX_RING_SLOTS];
-	struct dpaa2_queue *dpaa2_q[MAX_TX_RING_SLOTS];
 	struct qbman_swp *swp;
-	struct rte_eth_dev_data *eth_data;
 	struct dpaa2_dev_priv *priv;
 	struct dpaa2_queue *order_sendq;
-	uint8_t dy_conf[MAX_TX_RING_SLOTS];
+	struct dpaa2_queue *cnf_q;
 
 	if (unlikely(!DPAA2_PER_LCORE_DPIO)) {
 		ret = dpaa2_affine_qbman_swp();
@@ -1923,25 +1907,12 @@ dpaa2_dev_tx_multi_txq_ordered(void **queue,
 	}
 	swp = DPAA2_PER_LCORE_PORTAL;
 
-tx_again:
 	ptp_set_count = 0;
 	frames_to_send = (nb_pkts > dpaa2_eqcr_size) ?
 		dpaa2_eqcr_size : nb_pkts;
 
 	for (loop = 0; loop < frames_to_send; loop++) {
-		dpaa2_q[loop] = queue[loop];
-		if (dpaa2_q[loop]->tx_conf_queue)
-			dpaa2_dev_tx_conf(dpaa2_q[loop], false);
-		eth_data = dpaa2_q[loop]->eth_data;
-		priv = eth_data->dev_private;
-		dy_conf[loop] = false;
-		if (unlikely(!priv->bp_list)) {
-			DPAA2_PMD_ERR("%s's buffer pool not initialized!",
-				eth_data->name);
-			ret = -ENOMEM;
-			goto send_frames;
-		}
-		hw_mp = priv->bp_list->mp;
+		priv = dpaa2_q[loop]->eth_data->dev_private;
 		if (!priv->en_loose_ordered &&
 			(*dpaa2_seqn(*bufs) & DPAA2_ENQUEUE_FLAG_ORP)) {
 			if (!num_free_eq_desc) {
@@ -1954,9 +1925,6 @@ dpaa2_dev_tx_multi_txq_ordered(void **queue,
 			num_free_eq_desc--;
 		}
 
-		DPAA2_PMD_DP_DEBUG("===> eth_data =%p, fqid =%d",
-			eth_data, dpaa2_q[loop]->fqid);
-
 		/* Check if the queue is congested */
 		retry_count = 0;
 		while (qbman_result_SCN_state(dpaa2_q[loop]->cscn)) {
@@ -1973,8 +1941,7 @@ dpaa2_dev_tx_multi_txq_ordered(void **queue,
 
 		if (*dpaa2_seqn(*bufs) && priv->en_ordered) {
 			order_sendq = priv->tx_vq[0];
-			dpaa2_set_enqueue_descriptor(order_sendq, *bufs,
-				&eqdesc[loop]);
+			dpaa2_set_enqueue_descriptor(order_sendq, *bufs, &eqdesc[loop]);
 		} else {
 			qbman_eq_desc_set_no_orp(&eqdesc[loop], DPAA2_EQ_RESP_ERR_FQ);
 			qbman_eq_desc_set_fq(&eqdesc[loop], dpaa2_q[loop]->fqid);
@@ -1993,27 +1960,27 @@ dpaa2_dev_tx_multi_txq_ordered(void **queue,
 			goto skip_fast_mbuf2fd;
 		}
 
-		ret = dpaa2_dev_tx_fast_mbuf_to_fd(eth_data,
-				*bufs, &fd_arr[loop], priv->tx_conf_type);
+		ret = dpaa2_dev_tx_fast_mbuf_to_fd(priv, *bufs, &fd_arr[loop]);
 		if (likely(!ret)) {
-			if (priv->tx_conf_type == DPAA2_TX_ABSOLUTE_CONF)
-				dy_conf[loop] = true;
 			bufs++;
 			continue;
 		}
 
 skip_fast_mbuf2fd:
+		if (unlikely(!priv->bp_list)) {
+			ret = -ENOMEM;
+			goto send_frames;
+		}
+		hw_mp = priv->bp_list->mp;
 		if (unlikely((*bufs)->nb_segs > 1)) {
 			ret = dpaa2_dev_tx_mbuf_to_sg_fd(hw_mp, *bufs, &fd_arr[loop],
-				dpaa2_q[loop], priv->tx_conf_type, &dy_conf[loop], tstamp[loop]);
+				dpaa2_q[loop], priv->tx_conf_type, tstamp[loop]);
 		} else {
 			ret = dpaa2_dev_tx_mbuf_to_simple_fd(hw_mp, *bufs, &fd_arr[loop],
-				dpaa2_q[loop], priv->tx_conf_type, &dy_conf[loop], tstamp[loop]);
+				dpaa2_q[loop], priv->tx_conf_type, tstamp[loop]);
 		}
 		if (ret)
 			goto send_frames;
-		if (priv->tx_conf_type == DPAA2_TX_ABSOLUTE_CONF)
-			dy_conf[loop] = true;
 		bufs++;
 	}
 
@@ -2023,8 +1990,7 @@ dpaa2_dev_tx_multi_txq_ordered(void **queue,
 	retry_count = 0;
 	while (loop < frames_to_send) {
 		ret = qbman_swp_enqueue_multiple_desc(swp, &eqdesc[loop],
-				&fd_arr[loop],
-				frames_to_send - loop);
+				&fd_arr[loop], frames_to_send - loop);
 		if (likely(ret > 0)) {
 			loop += ret;
 			retry_count = 0;
@@ -2034,18 +2000,41 @@ dpaa2_dev_tx_multi_txq_ordered(void **queue,
 				break;
 		}
 	}
-	nb_pkts -= loop;
-	sent += loop;
 	for (i = 0; i < loop; i++) {
-		if (tstamp[i] && dpaa2_q[i]->tx_conf_queue) {
-			rte_atomic_fetch_add_explicit(&dpaa2_q[i]->tx_conf_queue->ts_to_cnfd,
-				1, rte_memory_order_relaxed);
+		if (unlikely(dpaa2_q[i]->tx_conf_queue)) {
+			dpaa2_dev_tx_conf(dpaa2_q[i], false);
+			if (tstamp[i]) {
+				cnf_q = dpaa2_q[i]->tx_conf_queue;
+				rte_atomic_fetch_add_explicit(&cnf_q->ts_to_cnfd,
+					1, rte_memory_order_relaxed);
+			}
 		}
 	}
-	if (nb_pkts > 0 && !ret)
-		goto tx_again;
 
-	return sent;
+	return loop;
+}
+
+RTE_EXPORT_EXPERIMENTAL_SYMBOL(rte_dpaa2_dev_tx_multi_ports, 26.11)
+uint16_t
+rte_dpaa2_dev_tx_multi_ports(uint16_t port_id[],
+	uint16_t txq_id[], struct rte_mbuf **bufs, uint16_t nb_pkts)
+{
+	uint16_t i;
+	struct dpaa2_queue *txq[nb_pkts];
+	struct rte_eth_dev_data *data;
+
+	if (txq_id) {
+		for (i = 0; i < nb_pkts; i++) {
+			data = rte_eth_devices[port_id[i]].data;
+			txq[i] = data->tx_queues[txq_id[i]];
+		}
+	} else {
+		for (i = 0; i < nb_pkts; i++) {
+			data = rte_eth_devices[port_id[i]].data;
+			txq[i] = data->tx_queues[0];
+		}
+	}
+	return dpaa2_dev_tx_multi_txq_ordered(txq, bufs, nb_pkts);
 }
 
 /* Callback to handle sending ordered packets through WRIOP based interface */
@@ -2054,7 +2043,7 @@ dpaa2_dev_tx_ordered(void *queue, struct rte_mbuf **bufs,
 	uint16_t nb_pkts)
 {
 	uint16_t i;
-	void *mq[nb_pkts];
+	struct dpaa2_queue *mq[nb_pkts];
 
 	for (i = 0; i < nb_pkts; i++)
 		mq[i] = queue;
diff --git a/drivers/net/dpaa2/rte_pmd_dpaa2.h b/drivers/net/dpaa2/rte_pmd_dpaa2.h
index 5125ec5bf7..74b7e63c54 100644
--- a/drivers/net/dpaa2/rte_pmd_dpaa2.h
+++ b/drivers/net/dpaa2/rte_pmd_dpaa2.h
@@ -162,6 +162,11 @@ uint16_t
 rte_dpaa2_scheduler_rx(void *scheduler_handle, struct rte_mbuf **mbuf,
 	uint16_t nb_pkts);
 
+__rte_experimental
+uint16_t
+rte_dpaa2_dev_tx_multi_ports(uint16_t port_id[],
+	uint16_t txq_id[], struct rte_mbuf **bufs, uint16_t nb_pkts);
+
 #define RTE_DPAA2_EVENT_PORT_CFG_ATOMIC RTE_BIT32(31)
 
 /** RTE_DPAA2_MIX_GROUP_FLOW has same behavio as RTE_DPAA2_FLAT_GROUP_FLOW*/
-- 
2.43.0



More information about the dev mailing list