[PATCH v2 07/20] net/txgbe: fix Tx desc free logic
Zaiyu Wang
zaiyuwang at trustnetic.com
Wed Apr 29 12:25:01 CEST 2026
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")
Cc: stable at dpdk.org
Signed-off-by: Zaiyu Wang <zaiyuwang at trustnetic.com>
---
drivers/net/txgbe/txgbe_rxtx.c | 9 ++++++++-
drivers/net/txgbe/txgbe_rxtx_vec_common.h | 7 +++++--
2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/drivers/net/txgbe/txgbe_rxtx.c b/drivers/net/txgbe/txgbe_rxtx.c
index e2cd9b8841..72a4965693 100644
--- a/drivers/net/txgbe/txgbe_rxtx.c
+++ b/drivers/net/txgbe/txgbe_rxtx.c
@@ -100,7 +100,9 @@ txgbe_tx_free_bufs(struct txgbe_tx_queue *txq)
volatile uint16_t head = (uint16_t)*txq->headwb_mem;
- if (txq->tx_next_dd > head && head > tx_last_dd)
+ if (txq->tx_next_dd == head)
+ return 0;
+ else 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))
@@ -652,6 +654,11 @@ txgbe_xmit_cleanup(struct txgbe_tx_queue *txq)
/* we have caught up to head, no work left to do */
if (desc_to_clean_to == head)
return -(1);
+ else if (desc_to_clean_to > head && head > last_desc_cleaned)
+ return -(1);
+ else if (last_desc_cleaned > desc_to_clean_to &&
+ (head > last_desc_cleaned || head < desc_to_clean_to))
+ return -(1);
} else {
if (!(status & rte_cpu_to_le_32(TXGBE_TXD_DD))) {
PMD_TX_FREE_LOG(DEBUG,
diff --git a/drivers/net/txgbe/txgbe_rxtx_vec_common.h b/drivers/net/txgbe/txgbe_rxtx_vec_common.h
index 00847d087b..edf3586b77 100644
--- a/drivers/net/txgbe/txgbe_rxtx_vec_common.h
+++ b/drivers/net/txgbe/txgbe_rxtx_vec_common.h
@@ -94,8 +94,11 @@ txgbe_tx_free_bufs(struct txgbe_tx_queue *txq)
txq->tx_next_dd - txq->tx_free_thresh;
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)
+
+ volatile uint16_t head = (uint16_t)*txq->headwb_mem;
+ if (txq->tx_next_dd == head)
+ return 0;
+ else 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))
--
2.21.0.windows.1
More information about the stable
mailing list