Skip to content

Commit 2b56b3d

Browse files
committed
eth: bnxt: handle invalid Tx completions more gracefully
Invalid Tx completions should never happen (tm) but when they do they crash the host, because driver blindly trusts that there is a valid skb pointer on the ring. The completions I've seen appear to be some form of FW / HW miscalculation or staleness, they have typical (small) values (<100), but they are most often higher than number of queued descriptors. They usually happen after boot. Instead of crashing, print a warning and schedule a reset. Link: https://lore.kernel.org/r/20230720010440.1967136-4-kuba@kernel.org Reviewed-by: Michael Chan <michael.chan@broadcom.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1 parent 9b1a00f commit 2b56b3d

3 files changed

Lines changed: 31 additions & 1 deletion

File tree

drivers/net/ethernet/broadcom/bnxt/bnxt.c

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,22 @@ static void bnxt_sched_reset_rxr(struct bnxt *bp, struct bnxt_rx_ring_info *rxr)
331331
rxr->rx_next_cons = 0xffff;
332332
}
333333

334+
void bnxt_sched_reset_txr(struct bnxt *bp, struct bnxt_tx_ring_info *txr,
335+
int idx)
336+
{
337+
struct bnxt_napi *bnapi = txr->bnapi;
338+
339+
if (bnapi->tx_fault)
340+
return;
341+
342+
netdev_err(bp->dev, "Invalid Tx completion (ring:%d tx_pkts:%d cons:%u prod:%u i:%d)",
343+
txr->txq_index, bnapi->tx_pkts,
344+
txr->tx_cons, txr->tx_prod, idx);
345+
WARN_ON_ONCE(1);
346+
bnapi->tx_fault = 1;
347+
bnxt_queue_sp_work(bp, BNXT_RESET_TASK_SP_EVENT);
348+
}
349+
334350
const u16 bnxt_lhint_arr[] = {
335351
TX_BD_FLAGS_LHINT_512_AND_SMALLER,
336352
TX_BD_FLAGS_LHINT_512_TO_1023,
@@ -690,6 +706,11 @@ static void bnxt_tx_int(struct bnxt *bp, struct bnxt_napi *bnapi, int nr_pkts)
690706
skb = tx_buf->skb;
691707
tx_buf->skb = NULL;
692708

709+
if (unlikely(!skb)) {
710+
bnxt_sched_reset_txr(bp, txr, i);
711+
return;
712+
}
713+
693714
tx_bytes += skb->len;
694715

695716
if (tx_buf->is_push) {
@@ -2576,7 +2597,7 @@ static int __bnxt_poll_work(struct bnxt *bp, struct bnxt_cp_ring_info *cpr,
25762597

25772598
static void __bnxt_poll_work_done(struct bnxt *bp, struct bnxt_napi *bnapi)
25782599
{
2579-
if (bnapi->tx_pkts) {
2600+
if (bnapi->tx_pkts && !bnapi->tx_fault) {
25802601
bnapi->tx_int(bp, bnapi, bnapi->tx_pkts);
25812602
bnapi->tx_pkts = 0;
25822603
}
@@ -9429,6 +9450,8 @@ static void bnxt_enable_napi(struct bnxt *bp)
94299450
struct bnxt_napi *bnapi = bp->bnapi[i];
94309451
struct bnxt_cp_ring_info *cpr;
94319452

9453+
bnapi->tx_fault = 0;
9454+
94329455
cpr = &bnapi->cp_ring;
94339456
if (bnapi->in_reset)
94349457
cpr->sw_stats.rx.rx_resets++;

drivers/net/ethernet/broadcom/bnxt/bnxt.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1008,6 +1008,7 @@ struct bnxt_napi {
10081008
int);
10091009
int tx_pkts;
10101010
u8 events;
1011+
u8 tx_fault:1;
10111012

10121013
u32 flags;
10131014
#define BNXT_NAPI_FLAG_XDP 0x1
@@ -2329,6 +2330,8 @@ int bnxt_get_avail_msix(struct bnxt *bp, int num);
23292330
int bnxt_reserve_rings(struct bnxt *bp, bool irq_re_init);
23302331
void bnxt_tx_disable(struct bnxt *bp);
23312332
void bnxt_tx_enable(struct bnxt *bp);
2333+
void bnxt_sched_reset_txr(struct bnxt *bp, struct bnxt_tx_ring_info *txr,
2334+
int idx);
23322335
void bnxt_report_link(struct bnxt *bp);
23332336
int bnxt_update_link(struct bnxt *bp, bool chng_link_state);
23342337
int bnxt_hwrm_set_pause(struct bnxt *);

drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ void bnxt_tx_int_xdp(struct bnxt *bp, struct bnxt_napi *bnapi, int nr_pkts)
149149
tx_buf->action = 0;
150150
tx_buf->xdpf = NULL;
151151
} else if (tx_buf->action == XDP_TX) {
152+
tx_buf->action = 0;
152153
rx_doorbell_needed = true;
153154
last_tx_cons = tx_cons;
154155

@@ -158,6 +159,9 @@ void bnxt_tx_int_xdp(struct bnxt *bp, struct bnxt_napi *bnapi, int nr_pkts)
158159
tx_buf = &txr->tx_buf_ring[tx_cons];
159160
page_pool_recycle_direct(rxr->page_pool, tx_buf->page);
160161
}
162+
} else {
163+
bnxt_sched_reset_txr(bp, txr, i);
164+
return;
161165
}
162166
tx_cons = NEXT_TX(tx_cons);
163167
}

0 commit comments

Comments
 (0)