[PATCH net-next] net: stmmac: Setup TBS only if HW supports it

From: muhammad . nazim . amirul . nazle . asmade

Date: Thu Sep 17 2026 - 22:46:48 EST


From: Nazim Amirul <muhammad.nazim.amirul.nazle.asmade@xxxxxxxxxx>

stmmac_setup_dma_desc() unconditionally honors the per-queue tbs_en flag
set by platform glue drivers and marks the queue STMMAC_TBS_AVAIL, which
selects enhanced Tx descriptors and enables the EDSE bit in the DMA
channel. However, glue drivers set tbs_en in their setup path, which runs
before dma_cap is populated by stmmac_hw_init(), so they cannot themselves
validate against the TBSSEL hardware capability bit.

If tbs_en is set on a controller whose MAC IP was not synthesized with TBS
(MAC_HW_FEATURE3.TBSSEL == 0), the driver lays out the ring using the
enhanced descriptor stride while the DMA engine stays in basic-descriptor
mode, mismatching the descriptor format.

stmmac_enable_tbs() does read back the EDSE bit and return -EIO when it
does not stick, but that happens after stmmac_setup_dma_desc() has already
allocated the ring with the enhanced descriptor stride, and its return
value is discarded by the caller. Gating on dma_cap.tbssel in
stmmac_setup_dma_desc() prevents the enhanced descriptor allocation at the
earliest point, which is the only place the mismatch can be avoided
cleanly.

Only set STMMAC_TBS_AVAIL when the core has read TBSSEL from the HW
capability register.

Signed-off-by: Nazim Amirul <muhammad.nazim.amirul.nazle.asmade@xxxxxxxxxx>
---
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 07a6fab6460e..f604ac848f77 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -4094,12 +4094,14 @@ stmmac_setup_dma_desc(struct stmmac_priv *priv, unsigned int mtu)
dma_conf->dma_rx_size = DMA_DEFAULT_RX_SIZE;

/* Earlier check for TBS */
- for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) {
- struct stmmac_tx_queue *tx_q = &dma_conf->tx_queue[chan];
- int tbs_en = priv->plat->tx_queues_cfg[chan].tbs_en;
+ if (priv->dma_cap.tbssel) {
+ for (chan = 0; chan < priv->plat->tx_queues_to_use; chan++) {
+ struct stmmac_tx_queue *tx_q = &dma_conf->tx_queue[chan];
+ int tbs_en = priv->plat->tx_queues_cfg[chan].tbs_en;

- /* Setup per-TXQ tbs flag before TX descriptor alloc */
- tx_q->tbs |= tbs_en ? STMMAC_TBS_AVAIL : 0;
+ /* Setup per-TXQ tbs flag before TX descriptor alloc */
+ tx_q->tbs |= tbs_en ? STMMAC_TBS_AVAIL : 0;
+ }
}

ret = alloc_dma_desc_resources(priv, dma_conf);
--
2.43.7