net: bnxt: ring the doorbell when SW USO exits early

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: cc5d90667d ("net: bnxt: Implement software USO")
Cc: stable@vger.kernel.org
Signed-off-by: Joe Damato <joe@dama.to>
Reviewed-by: Michael Chan <michael.chan@broadcom.com>
Link: https://patch.msgid.link/20260819233213.3673149-1-joe@dama.to
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Joe Damato
2026-08-19 16:32:11 -07:00
committed by Jakub Kicinski
parent 746fc0787f
commit 4e15e89faa
2 changed files with 9 additions and 5 deletions

View File

@@ -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)) {

View File

@@ -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),