[PATCH net] net: bcmgenet: cap the Tx queue threshold at the ring size
From: Nicolai Buchwitz
Date: Fri Nov 06 2026 - 09:13:57 EST
A Tx queue stops when MAX_SKB_FRAGS + 1 or fewer descriptors are free and
wakes once there are more. Queues 1 to 4 hold 32 descriptors, so with
CONFIG_MAX_SKB_FRAGS at 31 they would need 33 to wake. As a result the
first packet stops the queue and it stays stopped:
eth0: NETDEV WATCHDOG: CPU: 0: transmit queue 3 timed out 2004 ms
eth0: NETDEV WATCHDOG: CPU: 1: transmit queue 4 timed out 2004 ms
On a Raspberry Pi CM4 only queue 0 carried traffic afterwards. The other
four counted an error on nearly every packet.
Fix this and cap the threshold at what the ring can free.
Fixes: 3948b05950fd ("net: introduce a config option to tweak MAX_SKB_FRAGS")
Signed-off-by: Nicolai Buchwitz <nb@xxxxxxxxxxx>
---
Found this while fixing the clashiko findings on v6 of my MTU series. After
those fixes this bug would be easier to hit. At the moment it needs a
larger CONFIG_MAX_SKB_FRAGS than the default.
Everything was tested on a Raspberry Pi CM4 (BCM2711, genet v5).
---
drivers/net/ethernet/broadcom/genet/bcmgenet.c | 6 ++++--
drivers/net/ethernet/broadcom/genet/bcmgenet.h | 1 +
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 4d2be2a21ed1b..186d17781b890 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -2030,7 +2030,7 @@ static int bcmgenet_tx_poll(struct napi_struct *napi, int budget)
spin_lock(&ring->lock);
__bcmgenet_tx_reclaim(ring->priv->dev, ring);
- if (ring->free_bds > (MAX_SKB_FRAGS + 1)) {
+ if (ring->free_bds > ring->stop_thld) {
txq = netdev_get_tx_queue(ring->priv->dev, ring->index);
netif_tx_wake_queue(txq);
}
@@ -2235,7 +2235,7 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev)
netdev_tx_sent_queue(txq, GENET_CB(skb)->bytes_sent);
- if (ring->free_bds <= (MAX_SKB_FRAGS + 1))
+ if (ring->free_bds <= ring->stop_thld)
netif_tx_stop_queue(txq);
if (!netdev_xmit_more() || netif_xmit_stopped(txq))
@@ -2742,6 +2742,8 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv,
ring->index = index;
ring->cbs = priv->tx_cbs + start_ptr;
ring->size = size;
+ /* A ring smaller than that would never wake */
+ ring->stop_thld = min_t(unsigned int, MAX_SKB_FRAGS + 1, size - 1);
ring->clean_ptr = start_ptr;
ring->c_index = 0;
ring->free_bds = size;
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
index e48ce39d3e7c8..6ab3f73475550 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
@@ -546,6 +546,7 @@ struct bcmgenet_tx_ring {
unsigned int index; /* ring index */
struct enet_cb *cbs; /* tx ring buffer control block*/
unsigned int size; /* size of each tx ring */
+ unsigned int stop_thld; /* queue stops at this many free bds or fewer */
unsigned int clean_ptr; /* Tx ring clean pointer */
unsigned int c_index; /* last consumer index of each ring*/
unsigned int free_bds; /* # of free bds for each ring */
---
base-commit: 19a227903e65c7a9c179156485660a4e017575fe
change-id: 20261106-nb-genet-txq-thld-net-e0864f235d22
Best regards,
--
Nicolai Buchwitz <nb@xxxxxxxxxxx>