patch 'net/bnxt: clear stale Tx descriptor count' has been queued to stable release 25.11.3

Kevin Traynor ktraynor at redhat.com
Tue Jul 28 17:55:57 CEST 2026


Hi,

FYI, your patch has been queued to stable release 25.11.3

Note it hasn't been pushed to http://dpdk.org/browse/dpdk-stable yet.
It will be pushed if I get no objections before 08/01/26. So please
shout if anyone has objections.

Also note that after the patch there's a diff of the upstream commit vs the
patch applied to the branch. This will indicate if there was any rebasing
needed to apply to the stable branch. If there were code changes for rebasing
(ie: not only metadata diffs), please double check that the rebase was
correctly done.

Queued patches are on a temporary branch at:
https://github.com/kevintraynor/dpdk-stable

This queued commit can be viewed at:
https://github.com/kevintraynor/dpdk-stable/commit/f6d863f44bb0d44c2815ba3dd4b23450ad9ac7f5

Thanks.

Kevin

---
>From f6d863f44bb0d44c2815ba3dd4b23450ad9ac7f5 Mon Sep 17 00:00:00 2001
From: Keegan Freyhof <keegan.freyhof at broadcom.com>
Date: Mon, 9 Feb 2026 14:55:07 -0700
Subject: [PATCH] net/bnxt: clear stale Tx descriptor count

[ upstream commit f3d1e83de0f963034aad71f31ad69072b3c5949b ]

Fixed an issue where the stale value held in txr->nr_bds[0]
would get read when the ring loops back around and cause
the tx producer to get behind the tx consumer position.
This then causes the driver to think that there were no
available buffers.

Fixes: 925cd0705836 ("net/bnxt: update PTP support on Thor")

Signed-off-by: Keegan Freyhof <keegan.freyhof at broadcom.com>
Signed-off-by: Mohammad Shuab Siddique <mohammad-shuab.siddique at broadcom.com>
---
 drivers/net/bnxt/bnxt_txr.c | 136 ++++++++++++++++++++++++++++++++++--
 1 file changed, 130 insertions(+), 6 deletions(-)

diff --git a/drivers/net/bnxt/bnxt_txr.c b/drivers/net/bnxt/bnxt_txr.c
index ccfc3bea65..e422a9be81 100644
--- a/drivers/net/bnxt/bnxt_txr.c
+++ b/drivers/net/bnxt/bnxt_txr.c
@@ -511,9 +511,46 @@ ret:
 }
 
+static void bnxt_tx_coal_cmp_fast(struct bnxt_tx_queue *txq, int nr_cons)
+{
+	struct bnxt_tx_ring_info *txr = txq->tx_ring;
+	struct bnxt_ring *ring = txr->tx_ring_struct;
+	struct rte_mbuf **free = txq->free;
+	uint16_t raw_cons = txr->tx_raw_cons;
+	unsigned int blk = 0;
+	int cons, bds;
+
+	for (cons = 0; cons < nr_cons; cons++) {
+		struct rte_mbuf **tx_buf;
+		unsigned short nr_bds;
+
+		tx_buf = &txr->tx_buf_ring[RING_IDX(ring, raw_cons)];
+		nr_bds = (*tx_buf)->nb_segs +
+			 bnxt_xmit_need_long_bd(*tx_buf, txq);
+		for (bds = 0; bds < nr_bds; bds++) {
+			if (*tx_buf) {
+				free[blk++] = *tx_buf;
+				/*
+				 * Each BD also tracks a consumer index.
+				 * Update cons, otherwise it will fall behind.
+				 */
+				cons++;
+				*tx_buf = NULL;
+			}
+			raw_cons = RING_NEXT(raw_cons);
+			tx_buf = &txr->tx_buf_ring[RING_IDX(ring, raw_cons)];
+		}
+	}
+	if (blk)
+		rte_mempool_put_bulk(free[0]->pool, (void *)free, blk);
+
+	txr->tx_raw_cons = raw_cons;
+}
+
 /*
  * Transmit completion function for use when RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE
  * is enabled.
  */
-static void bnxt_tx_cmp_fast(struct bnxt_tx_queue *txq, int nr_pkts)
+static void bnxt_tx_cmp_fast(struct bnxt_tx_queue *txq, int nb_tx,
+			      bool tx_coal_cmp)
 {
 	struct bnxt_tx_ring_info *txr = txq->tx_ring;
@@ -524,5 +561,8 @@ static void bnxt_tx_cmp_fast(struct bnxt_tx_queue *txq, int nr_pkts)
 	int i, j;
 
-	for (i = 0; i < nr_pkts; i++) {
+	if (tx_coal_cmp)
+		return bnxt_tx_coal_cmp_fast(txq, nb_tx);
+
+	for (i = 0; i < nb_tx; i++) {
 		struct rte_mbuf **tx_buf;
 		unsigned short nr_bds;
@@ -547,5 +587,70 @@ static void bnxt_tx_cmp_fast(struct bnxt_tx_queue *txq, int nr_pkts)
 }
 
-static void bnxt_tx_cmp(struct bnxt_tx_queue *txq, int nr_pkts)
+static void bnxt_tx_coal_cmp(struct bnxt_tx_queue *txq, int nr_cons)
+{
+	struct bnxt_tx_ring_info *txr = txq->tx_ring;
+	struct bnxt_ring *ring = txr->tx_ring_struct;
+	struct rte_mempool *pool = NULL;
+	struct rte_mbuf **free = txq->free;
+	uint16_t raw_cons = txr->tx_raw_cons;
+	unsigned int blk = 0;
+	int cons, bds;
+
+	for (cons = 0; cons < nr_cons; cons++) {
+		struct rte_mbuf *mbuf;
+		struct rte_mbuf **tx_buf;
+		unsigned short nr_bds;
+
+		tx_buf = &txr->tx_buf_ring[RING_IDX(ring, raw_cons)];
+		nr_bds = txr->nr_bds[RING_IDX(ring, raw_cons)];
+		/* Clear the now stale number of buffer descriptors */
+		txr->nr_bds[RING_IDX(ring, raw_cons)] = 0;
+
+		for (bds = 0; bds < nr_bds; bds++) {
+			mbuf = *tx_buf;
+			*tx_buf = NULL;
+			raw_cons = RING_NEXT(raw_cons);
+			/*
+			 * Each BD also tracks a consumer index. So update the cons.
+			 * Otherwise the cons will fall behind.
+			 */
+			cons++;
+			tx_buf = &txr->tx_buf_ring[RING_IDX(ring, raw_cons)];
+			if (!mbuf)	/* long_bd's tx_buf ? */
+				continue;
+
+			mbuf = rte_pktmbuf_prefree_seg(mbuf);
+			if (unlikely(!mbuf))
+				continue;
+
+			/* EW - no need to unmap DMA memory? */
+
+			if (likely(mbuf->pool == pool)) {
+				/* Add mbuf to the bulk free array */
+				free[blk++] = mbuf;
+			} else {
+				/* Found an mbuf from a different pool. Free
+				 * mbufs accumulated so far to the previous
+				 * pool
+				 */
+				if (likely(pool != NULL))
+					rte_mempool_put_bulk(pool,
+							     (void *)free,
+							     blk);
+
+				/* Start accumulating mbufs in a new pool */
+				free[0] = mbuf;
+				pool = mbuf->pool;
+				blk = 1;
+			}
+		}
+	}
+	if (blk)
+		rte_mempool_put_bulk(pool, (void *)free, blk);
+
+	txr->tx_raw_cons = raw_cons;
+}
+
+static void bnxt_tx_cmp(struct bnxt_tx_queue *txq, int nb_tx, bool tx_coal_cmp)
 {
 	struct bnxt_tx_ring_info *txr = txq->tx_ring;
@@ -557,5 +662,8 @@ static void bnxt_tx_cmp(struct bnxt_tx_queue *txq, int nr_pkts)
 	int i, j;
 
-	for (i = 0; i < nr_pkts; i++) {
+	if (tx_coal_cmp)
+		return bnxt_tx_coal_cmp(txq, nb_tx);
+
+	for (i = 0; i < nb_tx; i++) {
 		struct rte_mbuf *mbuf;
 		struct rte_mbuf **tx_buf;
@@ -564,4 +672,7 @@ static void bnxt_tx_cmp(struct bnxt_tx_queue *txq, int nr_pkts)
 		tx_buf = &txr->tx_buf_ring[RING_IDX(ring, raw_cons)];
 		nr_bds = txr->nr_bds[RING_IDX(ring, raw_cons)];
+		/* Clear the now stale number of buffer descriptors */
+		txr->nr_bds[RING_IDX(ring, raw_cons)] = 0;
+
 		for (j = 0; j < nr_bds; j++) {
 			mbuf = *tx_buf;
@@ -617,4 +728,6 @@ static int bnxt_handle_tx_cp(struct bnxt_tx_queue *txq)
 	uint32_t raw_cons = cpr->cp_raw_cons;
 	struct bnxt_ring *cp_ring_struct;
+	uint32_t tx_ring_mask;
+	bool tx_coal_cmp = false;
 	struct tx_cmpl *txcmp;
 
@@ -624,4 +737,5 @@ static int bnxt_handle_tx_cp(struct bnxt_tx_queue *txq)
 	cp_ring_struct = cpr->cp_ring_struct;
 	ring_mask = cp_ring_struct->ring_mask;
+	tx_ring_mask = txq->tx_ring->tx_ring_struct->ring_mask;
 
 	do {
@@ -632,4 +746,14 @@ static int bnxt_handle_tx_cp(struct bnxt_tx_queue *txq)
 			break;
 
+		if (CMP_TYPE(txcmp) == CMPL_BASE_TYPE_TX_L2_COAL) {
+			struct tx_cmpl_coal *txcmp_c = (struct tx_cmpl_coal *)txcmp;
+
+			nb_tx_pkts = (rte_le_to_cpu_32(txcmp_c->sq_cons_idx) -
+				      (txq->tx_ring->tx_raw_cons & tx_ring_mask)) & tx_ring_mask;
+			raw_cons = NEXT_RAW_CMP(raw_cons);
+			tx_coal_cmp = true;
+			break;
+		}
+
 		opaque = rte_le_to_cpu_32(txcmp->opaque);
 
@@ -645,7 +769,7 @@ static int bnxt_handle_tx_cp(struct bnxt_tx_queue *txq)
 	if (nb_tx_pkts) {
 		if (txq->offloads & RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE)
-			bnxt_tx_cmp_fast(txq, nb_tx_pkts);
+			bnxt_tx_cmp_fast(txq, nb_tx_pkts, tx_coal_cmp);
 		else
-			bnxt_tx_cmp(txq, nb_tx_pkts);
+			bnxt_tx_cmp(txq, nb_tx_pkts, tx_coal_cmp);
 		cpr->cp_raw_cons = raw_cons;
 		bnxt_db_cq(cpr);
-- 
2.55.0

---
  Diff of the applied patch vs upstream commit (please double-check if non-empty:
---
--- -	2026-07-28 16:54:51.613956329 +0100
+++ 0027-net-bnxt-clear-stale-Tx-descriptor-count.patch	2026-07-28 16:54:50.768728485 +0100
@@ -1 +1 @@
-From f3d1e83de0f963034aad71f31ad69072b3c5949b Mon Sep 17 00:00:00 2001
+From f6d863f44bb0d44c2815ba3dd4b23450ad9ac7f5 Mon Sep 17 00:00:00 2001
@@ -5,0 +6,2 @@
+[ upstream commit f3d1e83de0f963034aad71f31ad69072b3c5949b ]
+
@@ -13 +14,0 @@
-Cc: stable at dpdk.org
@@ -22 +23 @@
-index c6b778bd4e..a9469ca366 100644
+index ccfc3bea65..e422a9be81 100644
@@ -25 +26 @@
-@@ -514,9 +514,46 @@ ret:
+@@ -511,9 +511,46 @@ ret:
@@ -73 +74 @@
-@@ -527,5 +564,8 @@ static void bnxt_tx_cmp_fast(struct bnxt_tx_queue *txq, int nr_pkts)
+@@ -524,5 +561,8 @@ static void bnxt_tx_cmp_fast(struct bnxt_tx_queue *txq, int nr_pkts)
@@ -83 +84 @@
-@@ -550,5 +590,70 @@ static void bnxt_tx_cmp_fast(struct bnxt_tx_queue *txq, int nr_pkts)
+@@ -547,5 +587,70 @@ static void bnxt_tx_cmp_fast(struct bnxt_tx_queue *txq, int nr_pkts)
@@ -155 +156 @@
-@@ -560,5 +665,8 @@ static void bnxt_tx_cmp(struct bnxt_tx_queue *txq, int nr_pkts)
+@@ -557,5 +662,8 @@ static void bnxt_tx_cmp(struct bnxt_tx_queue *txq, int nr_pkts)
@@ -165 +166 @@
-@@ -567,4 +675,7 @@ static void bnxt_tx_cmp(struct bnxt_tx_queue *txq, int nr_pkts)
+@@ -564,4 +672,7 @@ static void bnxt_tx_cmp(struct bnxt_tx_queue *txq, int nr_pkts)
@@ -173 +174 @@
-@@ -634,4 +745,6 @@ static int bnxt_handle_tx_cp(struct bnxt_tx_queue *txq)
+@@ -617,4 +728,6 @@ static int bnxt_handle_tx_cp(struct bnxt_tx_queue *txq)
@@ -180 +181 @@
-@@ -641,4 +754,5 @@ static int bnxt_handle_tx_cp(struct bnxt_tx_queue *txq)
+@@ -624,4 +737,5 @@ static int bnxt_handle_tx_cp(struct bnxt_tx_queue *txq)
@@ -186 +187 @@
-@@ -649,4 +763,14 @@ static int bnxt_handle_tx_cp(struct bnxt_tx_queue *txq)
+@@ -632,4 +746,14 @@ static int bnxt_handle_tx_cp(struct bnxt_tx_queue *txq)
@@ -201 +202 @@
-@@ -664,7 +788,7 @@ static int bnxt_handle_tx_cp(struct bnxt_tx_queue *txq)
+@@ -645,7 +769,7 @@ static int bnxt_handle_tx_cp(struct bnxt_tx_queue *txq)



More information about the stable mailing list