patch 'net/txgbe: fix Tx descriptor free' has been queued to stable release 25.11.3

Kevin Traynor ktraynor at redhat.com
Thu Jul 30 11:15:46 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/04/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/1ec913a0433bc3c2fb101572548be8d351106bde

Thanks.

Kevin

---
>From 1ec913a0433bc3c2fb101572548be8d351106bde Mon Sep 17 00:00:00 2001
From: Zaiyu Wang <zaiyuwang at trustnetic.com>
Date: Wed, 24 Jun 2026 19:52:39 +0800
Subject: [PATCH] net/txgbe: fix Tx descriptor free

[ upstream commit b2b02993bcdfbafdf446a25720aaca5594456bba ]

On some server environments, this driver caused TDM non-fatal errors
or PCIe request errors during Tx operation

In Amber-Lite NIC's Tx head write-back mode, the hardware periodically
writes back a head index pointing to the next descriptor it is adout
to process in Tx ring. All descriptors before the head are considered
processed by hardware and can be safely freed by the driver.

The root cause is that the driver can safely free a batch of descriptors
only when the hardware's write-back head pointer has advanced beyond all
descriptors in that batch, meaning they have all been processed by the
hardware. If the driver frees a descriptor before the hardware has
finished processing it, invalid memory access may occur, leading to the
observed bug.

To fix the issue, correct the boundary check in all three Tx cleanup
functions, each of which was missing the proper condition to prevent
freeing unprocessed descriptors.

Fixes: 8ada71d0bb7f ("net/txgbe: add Tx head write-back mode for Amber-Lite")

Signed-off-by: Zaiyu Wang <zaiyuwang at trustnetic.com>
---
 drivers/net/txgbe/txgbe_rxtx.c            | 18 +++++------
 drivers/net/txgbe/txgbe_rxtx.h            | 37 ++++++++++++++++++++++-
 drivers/net/txgbe/txgbe_rxtx_vec_common.h | 10 +++---
 3 files changed, 50 insertions(+), 15 deletions(-)

diff --git a/drivers/net/txgbe/txgbe_rxtx.c b/drivers/net/txgbe/txgbe_rxtx.c
index e2cd9b8841..d5dcec3a2c 100644
--- a/drivers/net/txgbe/txgbe_rxtx.c
+++ b/drivers/net/txgbe/txgbe_rxtx.c
@@ -99,10 +99,9 @@ txgbe_tx_free_bufs(struct txgbe_tx_queue *txq)
 			tx_last_dd -= txq->nb_tx_desc;
 
-		volatile uint16_t head = (uint16_t)*txq->headwb_mem;
+		uint32_t h = rte_atomic_load_explicit(txq->headwb_mem,
+						      rte_memory_order_acquire);
+		const uint16_t head = (uint16_t)h;
 
-		if (txq->tx_next_dd > head && head > tx_last_dd)
-			return 0;
-		else if (tx_last_dd > txq->tx_next_dd &&
-				(head > tx_last_dd || head < txq->tx_next_dd))
+		if (!txgbe_tx_headwb_desc_done(head, tx_last_dd, txq->tx_next_dd))
 			return 0;
 	} else {
@@ -646,10 +645,11 @@ txgbe_xmit_cleanup(struct txgbe_tx_queue *txq)
 
 	if (txq->headwb_mem) {
-		u32 head = *txq->headwb_mem;
+		uint32_t h = rte_atomic_load_explicit(txq->headwb_mem,
+						      rte_memory_order_acquire);
+		const uint16_t head = (uint16_t)h;
 
 		PMD_TX_FREE_LOG(DEBUG, "queue[%02d]: headwb_mem = %03d, desc_to_clean_to = %03d",
 				txq->reg_idx, head, desc_to_clean_to);
-		/* we have caught up to head, no work left to do */
-		if (desc_to_clean_to == head)
+		if (!txgbe_tx_headwb_desc_done(head, last_desc_cleaned, desc_to_clean_to))
 			return -(1);
 	} else {
@@ -2441,5 +2441,5 @@ txgbe_setup_headwb_resources(struct rte_eth_dev *dev,
 	txq->headwb = headwb;
 	txq->headwb_dma = TMZ_PADDR(headwb);
-	txq->headwb_mem = (uint32_t *)TMZ_VADDR(headwb);
+	txq->headwb_mem = (RTE_ATOMIC(uint32_t) *)TMZ_VADDR(headwb);
 
 	/* Zero out headwb_mem memory */
diff --git a/drivers/net/txgbe/txgbe_rxtx.h b/drivers/net/txgbe/txgbe_rxtx.h
index 02e2617cce..9b0fffae8e 100644
--- a/drivers/net/txgbe/txgbe_rxtx.h
+++ b/drivers/net/txgbe/txgbe_rxtx.h
@@ -418,5 +418,5 @@ struct txgbe_tx_queue {
 	const struct rte_memzone *headwb;
 	uint64_t             headwb_dma;
-	volatile uint32_t    *headwb_mem;
+	RTE_ATOMIC(uint32_t) *headwb_mem;
 };
 
@@ -427,4 +427,39 @@ struct txgbe_txq_ops {
 };
 
+/**
+ * Check whether Tx descriptors in the range (last, next]  are done
+ * in Tx head write-back mode.
+ *
+ * In head write-back mode, the hardware periodically updates *headwb_mem
+ * with the index of the next descriptor it will process.
+ * All descriptors before the head are considered processed by hardware and can
+ * be safely freed. The descriptor pointed to by head itself is not yet processed.
+ *
+ * @param head
+ *   Current hardware head index read from headwb_mem.
+ * @param last
+ *   The highest-index descriptor cleaned in the previous round
+ *   (exclusive: descriptors at or before this index are already freed).
+ * @param next
+ *   The highest-index descriptor to be cleaned in this round
+ *   (inclusive: this descriptor is the target of the current cleanup).
+ * @return
+ *   true if all descriptors in the range (last, next] have been completed
+ *   by hardware and can be freed, false otherwise.
+ */
+static inline bool
+txgbe_tx_headwb_desc_done(uint16_t head, uint16_t last, uint16_t next)
+{
+	if (next == head)
+		return false;
+	else if (next > head && head > last)
+		return false;
+	/* wrap case */
+	else if (last > next && (head > last || head < next))
+		return false;
+
+	return true;
+}
+
 /* Takes an ethdev and a queue and sets up the tx function to be used based on
  * the queue parameters. Used in tx_queue_setup by primary process and then
diff --git a/drivers/net/txgbe/txgbe_rxtx_vec_common.h b/drivers/net/txgbe/txgbe_rxtx_vec_common.h
index 00847d087b..77d7ff785b 100644
--- a/drivers/net/txgbe/txgbe_rxtx_vec_common.h
+++ b/drivers/net/txgbe/txgbe_rxtx_vec_common.h
@@ -95,9 +95,9 @@ txgbe_tx_free_bufs(struct txgbe_tx_queue *txq)
 		if (tx_last_dd >= txq->nb_tx_desc)
 			tx_last_dd -= txq->nb_tx_desc;
-				volatile uint16_t head = (uint16_t)*txq->headwb_mem;
-		if (txq->tx_next_dd > head && head > tx_last_dd)
-			return 0;
-		else if (tx_last_dd > txq->tx_next_dd &&
-				(head > tx_last_dd || head < txq->tx_next_dd))
+		uint32_t h = rte_atomic_load_explicit(txq->headwb_mem,
+						      rte_memory_order_acquire);
+		const uint16_t head = (uint16_t)h;
+
+		if (!txgbe_tx_headwb_desc_done(head, tx_last_dd, txq->tx_next_dd))
 			return 0;
 	} else {
-- 
2.55.0

---
  Diff of the applied patch vs upstream commit (please double-check if non-empty:
---
--- -	2026-07-30 10:16:01.716419942 +0100
+++ 0007-net-txgbe-fix-Tx-descriptor-free.patch	2026-07-30 10:16:01.426990815 +0100
@@ -1 +1 @@
-From b2b02993bcdfbafdf446a25720aaca5594456bba Mon Sep 17 00:00:00 2001
+From 1ec913a0433bc3c2fb101572548be8d351106bde Mon Sep 17 00:00:00 2001
@@ -5,0 +6,2 @@
+[ upstream commit b2b02993bcdfbafdf446a25720aaca5594456bba ]
+
@@ -26 +27,0 @@
-Cc: stable at dpdk.org



More information about the stable mailing list