[PATCH net v2] net: bnxt: ring the doorbell when SW USO exits early
From: Joe Damato
Date: Wed Aug 19 2026 - 19:32:37 EST
When a burst of packets is handed down to the driver, the driver defers
the doorbell to the end by setting txr->kick_pending = 1. The normal TX
path handles this, but the SW USO path can miss it if it returns
early.
If bnxt_sw_udp_gso_xmit runs but returns early with NETDEV_TX_BUSY and
txr->kick_pending was previously set to 1, then the TX queue can
stall because the driver wrote some BDs but never wrote the doorbell.
The device won't know to do the TX which would generate the completion
that would wake the queue back up.
Simplify bnxt_sw_udp_gso_xmit to set txr->kick_pending in its success
case and check the flag on return. The added check after
bnxt_sw_udp_gso_xmit returns ensures that any pending doorbells are
written handling both successful USO and any early returns, which
prevents the TX queue stall mentioned above.
This TX queue stall was observed on a production system with a netdev TX
watchdog informing about the queue stall.
Fixes: cc5d90667db8 ("net: bnxt: Implement software USO")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Joe Damato <joe@xxxxxxx>
Reviewed-by: Michael Chan <michael.chan@xxxxxxxxxxxx>
---
v2:
- Simplfy the patch as Michael suggested, setting txr->kick_pending in the
USO code instead of exporting and calling bnxt_txr_db_kick.
- Update commit message and remove stale comment.
v1: https://lore.kernel.org/netdev/20260818211540.2991183-1-joe@xxxxxxx/
drivers/net/ethernet/broadcom/bnxt/bnxt.c | 10 ++++++++--
drivers/net/ethernet/broadcom/bnxt/bnxt_gso.c | 4 +---
2 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index 9377bf675981..d3cb25abb632 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
@@ -485,6 +485,7 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct bnxt_sw_tx_bd *tx_buf;
__le32 lflags = 0;
skb_frag_t *frag;
+ netdev_tx_t ret;
i = skb_get_queue_mapping(skb);
if (unlikely(i >= bp->tx_nr_rings)) {
@@ -510,8 +511,13 @@ static netdev_tx_t bnxt_start_xmit(struct sk_buff *skb, struct net_device *dev)
#endif
if (skb_is_gso(skb) &&
(skb_shinfo(skb)->gso_type & SKB_GSO_UDP_L4) &&
- !(bp->flags & BNXT_FLAG_UDP_GSO_CAP))
- return bnxt_sw_udp_gso_xmit(bp, txr, txq, skb);
+ !(bp->flags & BNXT_FLAG_UDP_GSO_CAP)) {
+ ret = bnxt_sw_udp_gso_xmit(bp, txr, txq, skb);
+ if (txr->kick_pending)
+ bnxt_txr_db_kick(bp, txr, txr->tx_prod);
+
+ return ret;
+ }
free_size = bnxt_tx_avail(bp, txr);
if (unlikely(free_size < skb_shinfo(skb)->nr_frags + 2)) {
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt_gso.c b/drivers/net/ethernet/broadcom/bnxt/bnxt_gso.c
index f317f60414e8..f7e18bea0fb8 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt_gso.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt_gso.c
@@ -223,9 +223,7 @@ netdev_tx_t bnxt_sw_udp_gso_xmit(struct bnxt *bp,
netdev_tx_sent_queue(txq, skb->len);
WRITE_ONCE(txr->tx_prod, prod);
- /* Sync BDs before doorbell */
- wmb();
- bnxt_db_write(bp, &txr->tx_db, prod);
+ txr->kick_pending = 1;
if (unlikely(bnxt_tx_avail(bp, txr) <= bp->tx_wake_thresh))
netif_txq_try_stop(txq, bnxt_tx_avail(bp, txr),
base-commit: 61eb236c41c2a4717015dff18016a75a5eb90052
--
2.53.0-Meta