mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 14:04:27 -04:00
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:
committed by
Jakub Kicinski
parent
746fc0787f
commit
4e15e89faa
@@ -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)) {
|
||||
|
||||
@@ -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),
|
||||
|
||||
Reference in New Issue
Block a user