* [PATCH net 0/4] bnxt_en: Bug fixes
@ 2026-08-31 2:43 Michael Chan
2026-08-31 2:43 ` [PATCH net 1/4] bnxt_en: Fix ring accounting underflow when rings are constrained Michael Chan
` (3 more replies)
0 siblings, 4 replies; 11+ messages in thread
From: Michael Chan @ 2026-08-31 2:43 UTC (permalink / raw)
To: davem
Cc: netdev, edumazet, kuba, pabeni, andrew+netdev, pavan.chebbi,
andrew.gospodarek
This patchset includes 4 fixes. The first one fixes the ring
accounting logic when FW is unable to reserve all the rings
requested by the driver. The 2nd one is a refactoring patch to
add a bnxt_clear_bars() helper needed by the 3rd and 4th patch.
The 3rd patch fixes a possible error during driver init. in the
kdump kernel by rewriting the BARs after FLR. The 4th patch is a
similar fix in the PCIe AER code path for non-fatal errors.
Michael Chan (3):
bnxt_en: Fix ring accounting underflow when rings are constrained
bnxt_en: Add bnxt_clear_bars() helper
bnxt_en: Fix driver init in kdump kernel
Pavan Chebbi (1):
bnxt_en: Re-write the BARs following any type of PCIe errors
drivers/net/ethernet/broadcom/bnxt/bnxt.c | 70 +++++++++++++----------
1 file changed, 39 insertions(+), 31 deletions(-)
--
2.51.0
^ permalink raw reply [flat|nested] 11+ messages in thread* [PATCH net 1/4] bnxt_en: Fix ring accounting underflow when rings are constrained 2026-08-31 2:43 [PATCH net 0/4] bnxt_en: Bug fixes Michael Chan @ 2026-08-31 2:43 ` Michael Chan 2026-09-02 5:46 ` [net,1/4] " netdev-bot+sashiko 2026-08-31 2:43 ` [PATCH net 2/4] bnxt_en: Add bnxt_clear_bars() helper Michael Chan ` (2 subsequent siblings) 3 siblings, 1 reply; 11+ messages in thread From: Michael Chan @ 2026-08-31 2:43 UTC (permalink / raw) To: davem Cc: netdev, edumazet, kuba, pabeni, andrew+netdev, pavan.chebbi, andrew.gospodarek When __bnxt_reserve_rings() reserves fewer TX rings than requested, and an XDP program is attached, bnxt_adj_tx_rings() blindly subtracts bp->tx_nr_rings_xdp from bp->tx_nr_rings, potentially causing the result to be negative (large value). The large value will propagate and cause unpredictable failures. bnxt_adj_tx_rings() should scale down the TX rings for XDP and TCs evenly when there is a shortage of TX rings to be correct. Because XDP requires a 1:1 mapping with RX rings in combined channel mode, bp->tx_nr_rings_xdp must be equal to bp->tx_nr_rings_per_tc. Any leftover rings after integer division is intentionally left unused. This will fix the underflow resulting in a negative (large) value. Additionally, update bnxt_rings_ok() to require a minimum number of TX rings based on the active configuration (at least 1 ring per TC, plus 1 XDP ring if XDP is enabled). This guarantees that bnxt_adj_tx_rings() always has enough rings to satisfy the minimum viable configuration, gracefully failing the reservation otherwise. The bnxt_rings_ok() check in __bnxt_reserve_rings() is moved earlier to return -ENOMEM if we don't have the bare minimum resources before we commit and update the software state. Also add a check for bnxt_trim_rings() failure earlier in the same function for the same purpose. Now that we have the proper bnxt_rings_ok() check for the bare minimum and a more robust bnxt_adj_tx_rings() to handle fewer rings than requested, we can remove the error path at the end of bnxt_reserve_rings() that would abort if the rings could not satisfy the TC requirements. This existing issue was detetced by Sashiko when reviewing the new kTLS patchset (patch #3 of 15): https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260810051358.1244418-7-michael.chan@broadcom.com Fixes: 1ee581c24dfd ("bnxt_en: Adjust TX rings if reservation is less than requested") Signed-off-by: Michael Chan <michael.chan@broadcom.com> --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 45 ++++++++++++----------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index d59bcca73a2b..219a6f551f1d 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -8135,8 +8135,14 @@ static void bnxt_copy_reserved_rings(struct bnxt *bp, struct bnxt_hw_rings *hwr) static bool bnxt_rings_ok(struct bnxt *bp, struct bnxt_hw_rings *hwr) { - return hwr->tx && hwr->rx && hwr->cp && hwr->grp && hwr->vnic && - hwr->stat && (hwr->cp_p5 || !(bp->flags & BNXT_FLAG_CHIP_P5_PLUS)); + int min_tx = bp->num_tc ? bp->num_tc : 1; + + if (bp->tx_nr_rings_xdp) + min_tx++; + + return hwr->tx >= min_tx && hwr->rx && hwr->cp && hwr->grp && + hwr->vnic && hwr->stat && + (hwr->cp_p5 || !(bp->flags & BNXT_FLAG_CHIP_P5_PLUS)); } static int bnxt_get_avail_msix(struct bnxt *bp, int num); @@ -8211,10 +8217,16 @@ static int __bnxt_reserve_rings(struct bnxt *bp) hwr.stat -= bnxt_get_ulp_stat_ctxs(bp); hwr.cp = min_t(int, hwr.cp, hwr.stat); rc = bnxt_trim_rings(bp, &rx_rings, &hwr.tx, hwr.cp, sh); + if (rc) + return rc; if (bp->flags & BNXT_FLAG_AGG_RINGS) hwr.rx = rx_rings << 1; tx_cp = bnxt_num_tx_to_cp(bp, hwr.tx); hwr.cp = sh ? max_t(int, tx_cp, rx_rings) : tx_cp + rx_rings; + + if (!bnxt_rings_ok(bp, &hwr)) + return -ENOMEM; + if (hwr.tx != bp->tx_nr_rings) { netdev_warn(bp->dev, "Able to reserve only %d out of %d requested TX rings\n", @@ -8243,9 +8255,6 @@ static int __bnxt_reserve_rings(struct bnxt *bp) hwr.rss_ctx < bnxt_get_total_rss_ctxs(bp, &hwr)) bp->rss_cap &= ~BNXT_RSS_CAP_LARGE_RSS_CTX; - if (!bnxt_rings_ok(bp, &hwr)) - return -ENOMEM; - if (old_rx_rings != bp->hw_resc.resv_rx_rings && !netif_is_rxfh_configured(bp->dev)) bnxt_set_dflt_rss_indir_tbl(bp, NULL); @@ -11663,7 +11672,6 @@ int bnxt_reserve_rings(struct bnxt *bp, bool irq_re_init) struct bnxt_en_dev *edev = bp->edev[BNXT_AUXDEV_RDMA]; bool irq_cleared = false; bool irq_change = false; - int tcs = bp->num_tc; int irqs_required; int rc; @@ -11701,17 +11709,6 @@ int bnxt_reserve_rings(struct bnxt *bp, bool irq_re_init) netdev_err(bp->dev, "ring reservation/IRQ init failure rc: %d\n", rc); return rc; } - if (tcs && (bp->tx_nr_rings_per_tc * tcs != - bp->tx_nr_rings - bp->tx_nr_rings_xdp)) { - netdev_err(bp->dev, "tx ring reservation failure\n"); - netdev_reset_tc(bp->dev); - bp->num_tc = 0; - if (bp->tx_nr_rings_xdp) - bp->tx_nr_rings_per_tc = bp->tx_nr_rings_xdp; - else - bp->tx_nr_rings_per_tc = bp->tx_nr_rings; - return -ENOMEM; - } return 0; } @@ -13216,11 +13213,17 @@ static void bnxt_set_xdp_tx_rings(struct bnxt *bp) static void bnxt_adj_tx_rings(struct bnxt *bp) { + int tcs = bp->num_tc ? bp->num_tc : 1; + /* Make adjustments if reserved TX rings are less than requested */ - bp->tx_nr_rings -= bp->tx_nr_rings_xdp; - bp->tx_nr_rings_per_tc = bnxt_tx_nr_rings_per_tc(bp); - if (bp->tx_nr_rings_xdp) - bnxt_set_xdp_tx_rings(bp); + if (bp->tx_nr_rings_xdp) { + tcs++; + bp->tx_nr_rings_per_tc = bp->tx_nr_rings / tcs; + bp->tx_nr_rings_xdp = bp->tx_nr_rings_per_tc; + } else { + bp->tx_nr_rings_per_tc = bnxt_tx_nr_rings_per_tc(bp); + } + bp->tx_nr_rings = bp->tx_nr_rings_per_tc * tcs; } static int __bnxt_open_nic(struct bnxt *bp, bool irq_re_init, bool link_re_init) -- 2.51.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [net,1/4] bnxt_en: Fix ring accounting underflow when rings are constrained 2026-08-31 2:43 ` [PATCH net 1/4] bnxt_en: Fix ring accounting underflow when rings are constrained Michael Chan @ 2026-09-02 5:46 ` netdev-bot+sashiko 0 siblings, 0 replies; 11+ messages in thread From: netdev-bot+sashiko @ 2026-09-02 5:46 UTC (permalink / raw) To: michael.chan Cc: davem, netdev, edumazet, kuba, pabeni, andrew+netdev, pavan.chebbi, andrew.gospodarek, kalesh-anakkur.purayil, scott.branden Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: Critical: 0 · High: 1 · Medium: 1 (1) · Low: 0 - [High] bnxt_adj_tx_rings() (drivers/net/ethernet/broadcom/bnxt/bnxt.c:13214) now scales… - [Medium] The patch deletes the only unwind of the netdev/driver TC configuration from bnxt_reserve_rings() (the 'tx ring reservation… Pre-existing issues: - [Medium] bnxt_adj_tx_rings() lowers bp->tx_nr_rings (leftover reserved rings are, per the new commit message, 'intentionally left unused')… -- bnxt_en: Fix ring accounting underflow when rings are constrained The patch reworks bnxt_adj_tx_rings() to scale the XDP and per-TC TX ring counts down evenly when fewer TX rings were reserved than requested, adds a minimum TX ring requirement to bnxt_rings_ok(), moves that check earlier in __bnxt_reserve_rings(), and drops the TC reservation failure path at the end of bnxt_reserve_rings(). Link: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260810051358.1244418-7-michael.chan@broadcom.com > diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c > index d59bcca73a2b..219a6f551f1d 100644 > --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c > +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c > @@ -8135,8 +8135,14 @@ static void bnxt_copy_reserved_rings(struct bnxt *bp, struct bnxt_hw_rings *hwr) > > static bool bnxt_rings_ok(struct bnxt *bp, struct bnxt_hw_rings *hwr) > { > - return hwr->tx && hwr->rx && hwr->cp && hwr->grp && hwr->vnic && > - hwr->stat && (hwr->cp_p5 || !(bp->flags & BNXT_FLAG_CHIP_P5_PLUS)); > + int min_tx = bp->num_tc ? bp->num_tc : 1; > + > + if (bp->tx_nr_rings_xdp) > + min_tx++; > + > + return hwr->tx >= min_tx && hwr->rx && hwr->cp && hwr->grp && > + hwr->vnic && hwr->stat && > + (hwr->cp_p5 || !(bp->flags & BNXT_FLAG_CHIP_P5_PLUS)); > } [ ... ] > @@ -11701,17 +11709,6 @@ int bnxt_reserve_rings(struct bnxt *bp, bool irq_re_init) > netdev_err(bp->dev, "ring reservation/IRQ init failure rc: %d\n", rc); > return rc; > } > - if (tcs && (bp->tx_nr_rings_per_tc * tcs != > - bp->tx_nr_rings - bp->tx_nr_rings_xdp)) { > - netdev_err(bp->dev, "tx ring reservation failure\n"); > - netdev_reset_tc(bp->dev); > - bp->num_tc = 0; > - if (bp->tx_nr_rings_xdp) > - bp->tx_nr_rings_per_tc = bp->tx_nr_rings_xdp; > - else > - bp->tx_nr_rings_per_tc = bp->tx_nr_rings; > - return -ENOMEM; > - } > return 0; > } [Severity: Medium] This removed block was the only place that reset the TC configuration when the reservation could not back the configured traffic classes. Can dropping it leave bp->num_tc permanently set after a failed reservation? bnxt_setup_mq_tc() commits the configuration before the reservation happens: netdev_set_num_tc(dev, tc); bp->num_tc = tc; ... if (netif_running(bp->dev)) return bnxt_open_nic(bp, true, false); and has no unwind of its own. Its pre-flight bnxt_check_rings() only checks against maximum resources, not against what the firmware will actually reserve. If the reservation later yields hwr.tx < bp->num_tc (+1 for XDP), the new bnxt_rings_ok() check in __bnxt_reserve_rings() now returns -ENOMEM before any software state is touched, so bp->num_tc stays at tc. Since bnxt_setup_mq_tc() is the only place in the driver that ever assigns bp->num_tc, does bnxt_rings_ok() then keep computing min_tx = bp->num_tc, making every subsequent ifup fail with -ENOMEM until the mqprio configuration is torn down? There also seems to be a divergence between driver and core state on the mqprio path. When mqprio_init() propagates the error, qdisc_create() calls mqprio_destroy(), which with priv->hw_offload == 0 does: net/sched/sch_mqprio.c:mqprio_destroy() { if (priv->hw_offload && dev->netdev_ops->ndo_setup_tc) mqprio_disable_offload(sch); else netdev_set_num_tc(dev, 0); } That leaves dev->num_tc == 0 while bp->num_tc == tc and bp->tx_nr_rings is still sized for tc traffic classes. On a later successful open, the netdev_set_tc_queue() calls in bnxt_setup_msix() then have no traffic classes to program while the driver still lays out rings per TC. Was that resync intentional to drop? > @@ -13216,11 +13213,17 @@ static void bnxt_set_xdp_tx_rings(struct bnxt *bp) > > static void bnxt_adj_tx_rings(struct bnxt *bp) > { > + int tcs = bp->num_tc ? bp->num_tc : 1; > + > /* Make adjustments if reserved TX rings are less than requested */ > - bp->tx_nr_rings -= bp->tx_nr_rings_xdp; > - bp->tx_nr_rings_per_tc = bnxt_tx_nr_rings_per_tc(bp); > - if (bp->tx_nr_rings_xdp) > - bnxt_set_xdp_tx_rings(bp); > + if (bp->tx_nr_rings_xdp) { > + tcs++; > + bp->tx_nr_rings_per_tc = bp->tx_nr_rings / tcs; > + bp->tx_nr_rings_xdp = bp->tx_nr_rings_per_tc; [Severity: High] bp->tx_nr_rings_xdp is lowered here, but bp->rx_nr_rings is left untouched. Can that break the 1:1 XDP TX ring to RX ring mapping the commit message relies on? bnxt_xdp_set() establishes the invariant: drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c:bnxt_xdp_set() { ... bp->tx_nr_rings_xdp = tx_xdp; /* tx_xdp = bp->rx_nr_rings */ } and bnxt_alloc_mem() only installs XDP TX rings for the first bp->tx_nr_rings_xdp bnapi entries: if (i >= bp->tx_nr_rings_xdp) { int k = j + BNXT_RING_TO_TC_OFF(bp, i); bnapi2 = bp->bnapi[k]; ... bnapi2->tx_int = bnxt_tx_int; } else { bnapi2 = bp->bnapi[j]; bnapi2->flags |= BNXT_NAPI_FLAG_XDP; bnapi2->tx_ring[0] = txr; bnapi2->tx_int = bnxt_tx_int_xdp; Meanwhile every RX ring still gets the program in bnxt_init_one_rx_ring(): if (BNXT_RX_PAGE_MODE(bp) && bp->xdp_prog) { bpf_prog_add(bp->xdp_prog, 1); rxr->xdp_prog = bp->xdp_prog; } and bnxt_rx_xdp() uses the paired TX ring unconditionally: drivers/net/ethernet/broadcom/bnxt/bnxt_xdp.c:bnxt_rx_xdp() { txr = rxr->bnapi->tx_ring[0]; ... } Walking a P5+ combined-ring case with num_tc = 0, rx_nr_rings = 8 and XDP attached (requested tx_nr_rings_xdp = 8, tx_nr_rings = 16): Firmware reserves hwr.tx = 10. The new min_tx in bnxt_rings_ok() is 1 + 1 = 2, so the reservation is accepted and bp->tx_nr_rings = 10 with bp->rx_nr_rings = 8. Here tcs = 2, so tx_nr_rings_per_tc = 5 and tx_nr_rings_xdp = 5. In bnxt_alloc_mem() the regular rings i in [5,10) map to k = 5..9, so bnapi[5..7] own both an RX ring and a stack TX ring in tx_ring[0]. RX rings 5-7 then run XDP on a stack-owned TX ring with no txq lock, and __bnxt_tx_int() sees tx_buf->skb == NULL and calls bnxt_sched_reset_txr(). Firmware reserves hwr.tx = 6. Now tx_nr_rings_per_tc = tx_nr_rings_xdp = 3 and bp->tx_nr_rings = 6, while rx_nr_rings is still 8. The regular rings map to bnapi[3..5], so bnapi[6] and bnapi[7] get no TX ring at all and rxr->bnapi->tx_ring[0] is NULL for RX rings 6 and 7. Does the first packet received on those rings then oops in bnxt_rx_xdp() via bnxt_tx_avail(), which reads txr->tx_prod? Before this patch this second reservation produced a negative bp->tx_nr_rings whose allocation in bnxt_alloc_mem() failed and aborted the open, so the device did not reach this state. Nothing between bnxt_adj_tx_rings() and the data path re-establishes the invariant: __bnxt_open_nic() calls bnxt_adj_tx_rings() and then bnxt_alloc_mem() directly, and the only place that resyncs rx_nr_rings to tx_nr_rings_per_tc is bnxt_trim_dflt_sh_rings()/bnxt_adj_dflt_rings() on the probe/default-rings path: bp->cp_nr_rings = min_t(int, bp->tx_nr_rings_per_tc, bp->rx_nr_rings); bp->rx_nr_rings = bp->cp_nr_rings; Would it work to have bnxt_rings_ok() require num_tc rings plus bp->rx_nr_rings XDP rings, or to trim bp->rx_nr_rings down to bp->tx_nr_rings_per_tc here? > + } else { > + bp->tx_nr_rings_per_tc = bnxt_tx_nr_rings_per_tc(bp); > + } > + bp->tx_nr_rings = bp->tx_nr_rings_per_tc * tcs; [Severity: Medium] This isn't a bug introduced by this patch, but bp->tx_nr_rings is reduced here while bp->cp_nr_rings keeps the value __bnxt_reserve_rings() derived from the un-adjusted hwr.tx: tx_cp = bnxt_num_tx_to_cp(bp, hwr.tx); hwr.cp = sh ? max_t(int, tx_cp, rx_rings) : tx_cp + rx_rings; ... bp->cp_nr_rings = hwr.cp; Nothing recomputes it in the open path, since __bnxt_open_nic() calls bnxt_adj_tx_rings() and then bnxt_alloc_mem(); only the probe path re-runs bnxt_adj_dflt_rings()/bnxt_set_cp_rings(). Should bnxt_adj_tx_rings() also resync bp->cp_nr_rings now that leftover rings are "intentionally left unused"? With P5+, combined rings, num_tc = 0, rx = 8, requested xdp = 8 and reserved hwr.tx = 11: tx_cp = (11 - 8) + 8 = 11 so bp->cp_nr_rings = 11, while bnxt_adj_tx_rings() gives tx_nr_rings_per_tc = tx_nr_rings_xdp = 5 and bp->tx_nr_rings = 10. For i = 10 in bnxt_alloc_all_cp_arrays() neither the rx branch nor the tx branch applies, so cp_count is 0 and: cpr->cp_ring_arr = kzalloc_objs(*cpr, cp_count); if (!cpr->cp_ring_arr) return -ENOMEM; cpr->cp_ring_count = cp_count; returns ZERO_SIZE_PTR, which passes the NULL check. Besides the wasted MSIX/NQ/stat context, bnxt_poll_p5() reads that array unguarded at its poll_done label: poll_done: cpr_rx = &cpr->cp_ring_arr[0]; if (cpr_rx->cp_ring_type == BNXT_NQ_HDL_TYPE_RX && so anything that polls every NAPI of the device, such as netpoll's poll_napi(), would dereference ZERO_SIZE_PTR. The pre-patch code shrank bp->tx_nr_rings even more aggressively and produced the same cp_count == 0 contexts. -- Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260831024342.2161156-1-michael.chan%40broadcom.com ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH net 2/4] bnxt_en: Add bnxt_clear_bars() helper 2026-08-31 2:43 [PATCH net 0/4] bnxt_en: Bug fixes Michael Chan 2026-08-31 2:43 ` [PATCH net 1/4] bnxt_en: Fix ring accounting underflow when rings are constrained Michael Chan @ 2026-08-31 2:43 ` Michael Chan 2026-09-01 22:09 ` Joe Damato 2026-08-31 2:43 ` [PATCH net 3/4] bnxt_en: Fix driver init in kdump kernel Michael Chan 2026-08-31 2:43 ` [PATCH net 4/4] bnxt_en: Re-write the BARs following any type of PCIe errors Michael Chan 3 siblings, 1 reply; 11+ messages in thread From: Michael Chan @ 2026-08-31 2:43 UTC (permalink / raw) To: davem Cc: netdev, edumazet, kuba, pabeni, andrew+netdev, pavan.chebbi, andrew.gospodarek, Kalesh AP, Somnath Kotur In bnxt_io_slot_reset(), we clear the 6 BAR registers. Add a helper function to do that. The helper will be used again in the next 2 patches. Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com> Reviewed-by: Somnath Kotur <somnath.kotur@broadcom.com> Signed-off-by: Pavan Chebbi <pavan.chebbi@broadcom.com> Signed-off-by: Michael Chan <michael.chan@broadcom.com> --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index 219a6f551f1d..a76674fd0d6b 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -17063,6 +17063,14 @@ void bnxt_print_device_info(struct bnxt *bp) pcie_print_link_status(bp->pdev); } +static void bnxt_clear_bars(struct pci_dev *pdev) +{ + int off; + + for (off = PCI_BASE_ADDRESS_0; off <= PCI_BASE_ADDRESS_5; off += 4) + pci_write_config_dword(pdev, off, 0); +} + static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { struct bnxt_hw_resc *hw_resc; @@ -17550,7 +17558,6 @@ static pci_ers_result_t bnxt_io_slot_reset(struct pci_dev *pdev) struct bnxt *bp = netdev_priv(netdev); int retry = 0; int err = 0; - int off; netdev_info(bp->dev, "PCI Slot Reset\n"); @@ -17579,11 +17586,8 @@ static pci_ers_result_t bnxt_io_slot_reset(struct pci_dev *pdev) * write the BARs to 0 to force restore, in case of fatal error. */ if (test_and_clear_bit(BNXT_STATE_PCI_CHANNEL_IO_FROZEN, - &bp->state)) { - for (off = PCI_BASE_ADDRESS_0; - off <= PCI_BASE_ADDRESS_5; off += 4) - pci_write_config_dword(bp->pdev, off, 0); - } + &bp->state)) + bnxt_clear_bars(pdev); pci_restore_state(pdev); bnxt_inv_fw_health_reg(bp); -- 2.51.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH net 2/4] bnxt_en: Add bnxt_clear_bars() helper 2026-08-31 2:43 ` [PATCH net 2/4] bnxt_en: Add bnxt_clear_bars() helper Michael Chan @ 2026-09-01 22:09 ` Joe Damato 0 siblings, 0 replies; 11+ messages in thread From: Joe Damato @ 2026-09-01 22:09 UTC (permalink / raw) To: Michael Chan Cc: davem, netdev, edumazet, kuba, pabeni, andrew+netdev, pavan.chebbi, andrew.gospodarek, Kalesh AP, Somnath Kotur On Sun, Aug 30, 2026 at 07:43:40PM -0700, Michael Chan wrote: > In bnxt_io_slot_reset(), we clear the 6 BAR registers. Add a helper > function to do that. The helper will be used again in the next 2 > patches. > > Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com> > Reviewed-by: Somnath Kotur <somnath.kotur@broadcom.com> > Signed-off-by: Pavan Chebbi <pavan.chebbi@broadcom.com> > Signed-off-by: Michael Chan <michael.chan@broadcom.com> > --- > drivers/net/ethernet/broadcom/bnxt/bnxt.c | 16 ++++++++++------ > 1 file changed, 10 insertions(+), 6 deletions(-) Reviewed-by: Joe Damato <joe@dama.to> ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH net 3/4] bnxt_en: Fix driver init in kdump kernel 2026-08-31 2:43 [PATCH net 0/4] bnxt_en: Bug fixes Michael Chan 2026-08-31 2:43 ` [PATCH net 1/4] bnxt_en: Fix ring accounting underflow when rings are constrained Michael Chan 2026-08-31 2:43 ` [PATCH net 2/4] bnxt_en: Add bnxt_clear_bars() helper Michael Chan @ 2026-08-31 2:43 ` Michael Chan 2026-09-01 22:20 ` Joe Damato 2026-09-02 5:46 ` [net,3/4] " netdev-bot+sashiko 2026-08-31 2:43 ` [PATCH net 4/4] bnxt_en: Re-write the BARs following any type of PCIe errors Michael Chan 3 siblings, 2 replies; 11+ messages in thread From: Michael Chan @ 2026-08-31 2:43 UTC (permalink / raw) To: davem Cc: netdev, edumazet, kuba, pabeni, andrew+netdev, pavan.chebbi, andrew.gospodarek, Kalesh AP, Somnath Kotur The driver forces an FLR during kdump kernel initialization to reset the device. If the NIC is behind a PCIe switch in synthetic (smart) mode, the switch may need to see that the BARs have been initialized before it will pass Mem read/write TLPs to the NIC. Save the PCI state before FLR and restore the state after FLR. The BARs have to be cleared to ensure that they get re-initialized. Fixes: 8743db4a9acf ("bnxt_en: Issue PCIe FLR in kdump kernel to cleanup pending DMAs.") Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com> Reviewed-by: Somnath Kotur <somnath.kotur@broadcom.com> Signed-off-by: Pavan Chebbi <pavan.chebbi@broadcom.com> Signed-off-by: Michael Chan <michael.chan@broadcom.com> --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index a76674fd0d6b..c3d561ac53dc 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -17091,7 +17091,10 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) */ if (is_kdump_kernel()) { pci_clear_master(pdev); + pci_save_state(pdev); pcie_flr(pdev); + bnxt_clear_bars(pdev); + pci_restore_state(pdev); } max_irqs = bnxt_get_max_irq(pdev); -- 2.51.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH net 3/4] bnxt_en: Fix driver init in kdump kernel 2026-08-31 2:43 ` [PATCH net 3/4] bnxt_en: Fix driver init in kdump kernel Michael Chan @ 2026-09-01 22:20 ` Joe Damato 2026-09-02 5:46 ` [net,3/4] " netdev-bot+sashiko 1 sibling, 0 replies; 11+ messages in thread From: Joe Damato @ 2026-09-01 22:20 UTC (permalink / raw) To: Michael Chan Cc: davem, netdev, edumazet, kuba, pabeni, andrew+netdev, pavan.chebbi, andrew.gospodarek, Kalesh AP, Somnath Kotur On Sun, Aug 30, 2026 at 07:43:41PM -0700, Michael Chan wrote: > The driver forces an FLR during kdump kernel initialization to reset > the device. If the NIC is behind a PCIe switch in synthetic (smart) > mode, the switch may need to see that the BARs have been initialized > before it will pass Mem read/write TLPs to the NIC. Save the PCI > state before FLR and restore the state after FLR. The BARs have to > be cleared to ensure that they get re-initialized. > > Fixes: 8743db4a9acf ("bnxt_en: Issue PCIe FLR in kdump kernel to cleanup pending DMAs.") > Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com> > Reviewed-by: Somnath Kotur <somnath.kotur@broadcom.com> > Signed-off-by: Pavan Chebbi <pavan.chebbi@broadcom.com> > Signed-off-by: Michael Chan <michael.chan@broadcom.com> > --- > drivers/net/ethernet/broadcom/bnxt/bnxt.c | 3 +++ > 1 file changed, 3 insertions(+) > > diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c > index a76674fd0d6b..c3d561ac53dc 100644 > --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c > +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c > @@ -17091,7 +17091,10 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) > */ > if (is_kdump_kernel()) { > pci_clear_master(pdev); > + pci_save_state(pdev); > pcie_flr(pdev); idk if you gotta check the return value of pcie_flr. seems like most drivers don't except ice :( > + bnxt_clear_bars(pdev); > + pci_restore_state(pdev); > } > > max_irqs = bnxt_get_max_irq(pdev); the above aside: Reviewed-by: Joe Damato <joe@dama.to> ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [net,3/4] bnxt_en: Fix driver init in kdump kernel 2026-08-31 2:43 ` [PATCH net 3/4] bnxt_en: Fix driver init in kdump kernel Michael Chan 2026-09-01 22:20 ` Joe Damato @ 2026-09-02 5:46 ` netdev-bot+sashiko 1 sibling, 0 replies; 11+ messages in thread From: netdev-bot+sashiko @ 2026-09-02 5:46 UTC (permalink / raw) To: michael.chan Cc: davem, netdev, edumazet, kuba, pabeni, andrew+netdev, pavan.chebbi, andrew.gospodarek, kalesh-anakkur.purayil, scott.branden Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider: Critical: 0 · High: 0 · Medium: 1 · Low: 2 - [Medium] Unchecked pcie_flr() return combined with unconditional BAR reprogramming in bnxt_init_one()… - [Low] The newly added pci_save_state(pdev) call in bnxt_init_one() (drivers/net/ethernet/broadcom/bnxt/bnxt.c:17094) discards a… - [Low] The new save/clear-BARs/restore sequence in bnxt_init_one() is left undocumented in the tree, and the only in-tree rationale for… -- bnxt_en: Fix driver init in kdump kernel In the kdump path, bnxt_init_one() now saves the PCI state before the forced FLR, zeroes the BAR registers with bnxt_clear_bars() and restores the state afterwards, so that a PCIe switch in synthetic mode observes the BARs being (re-)initialized. > diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c > index a76674fd0d6b..c3d561ac53dc 100644 > --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c > +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c > @@ -17091,7 +17091,10 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) > */ > if (is_kdump_kernel()) { > pci_clear_master(pdev); > + pci_save_state(pdev); [Severity: Low] Should the return value of pci_save_state() be checked here? pci_save_state() saves the 64-byte header and sets dev->state_saved = true before it attempts the capability saves: drivers/pci/pci.c:pci_save_state() { ... dev->state_saved = true; i = pci_save_pcie_state(dev); if (i != 0) return i; i = pci_save_pcix_state(dev); if (i != 0) return i; ... } and pci_save_pcie_state() can fail when no save buffer was preallocated at device add time: drivers/pci/pci.c:pci_save_pcie_state() { save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP); if (!save_state) { pci_err(dev, "buffer not found in %s\n", __func__); return -ENOMEM; } ... } In that case the header/BAR portion this fix depends on is still saved, but the PCIe capability state that pcie_flr() resets (DEVCTL MPS/MRRS, LNKCTL) is silently left at reset defaults with no driver-side diagnostic. Note the pre-existing pci_save_state() call in the bnxt error recovery path ignores the return value in the same way, so this is not a new pattern in this driver. > pcie_flr(pdev); > + bnxt_clear_bars(pdev); > + pci_restore_state(pdev); [Severity: Medium] Is it safe to run bnxt_clear_bars() and pci_restore_state() unconditionally when pcie_flr() may not have reset the function? pcie_flr() has two paths that return without ever writing PCI_EXP_DEVCTL_BCR_FLR, plus a timeout path: drivers/pci/pci.c:pcie_flr() { if (!pci_dev_config_accessible(dev, "FLR")) return -ENOTTY; ... ret = pci_dev_reset_iommu_prepare(dev); if (ret) { pci_err(dev, "failed to stop IOMMU for a PCI reset: %d\n", ret); return ret; } ... ret = pci_dev_wait(dev, "FLR", PCIE_RESET_READY_POLL_MS); done: pci_dev_reset_iommu_done(dev); return ret; } If the FLR never took effect, PCI_COMMAND still carries the crashed kernel's Memory Space Enable bit, since pci_clear_master() only clears Bus Master Enable. bnxt_clear_bars() then zeroes all six BAR dwords on a function that is still decoding: static void bnxt_clear_bars(struct pci_dev *pdev) { int off; for (off = PCI_BASE_ADDRESS_0; off <= PCI_BASE_ADDRESS_5; off += 4) pci_write_config_dword(pdev, off, 0); } and pci_restore_state() reprograms them one dword at a time, high dword first: drivers/pci/pci.c:pci_restore_config_space_range() { for (index = end; index >= start; index--) pci_restore_config_dword(pdev, 4 * index, pdev->saved_config_space[index], force); } bnxt uses 64-bit memory BARs (pci_ioremap_bar(pdev, 0), pci_iomap(pdev, 2, ...), pci_ioremap_bar(pdev, 4)), so that ordering leaves a transient (high << 32) | 0 decode window. This is the hazard the PCI core avoids explicitly: drivers/pci/setup-res.c:pci_std_update_resource() { /* * We can't update a 64-bit BAR atomically, so when possible, * disable decoding so that a half-updated BAR won't conflict * with another device. */ disable = (res->flags & IORESOURCE_MEM_64) && !dev->mmio_always_on; ... } Would it make sense to clear PCI_COMMAND_MEMORY around the BAR writes here as well? The other case is a pci_dev_wait() timeout: per PCIe r4.0 sec 6.6.2 the device may silently discard config writes while the reset is still in progress, so the clear and restore can both be dropped. The commit message's guarantee that "The BARs have to be cleared to ensure that they get re-initialized" would then not hold, and probe continues into bnxt_get_max_irq() and the BAR0 ioremap in bnxt_init_board() with no indication of why. Would bailing out (or at least logging) on a non-zero pcie_flr() return be preferable to proceeding? > } > > max_irqs = bnxt_get_max_irq(pdev); [Severity: Low] This isn't a bug, but the comment above this block still reads only: /* Clear any pending DMA transactions from crash kernel * while loading driver in capture kernel. */ which describes pci_clear_master() plus pcie_flr() and not the new save / clear-BARs / restore sequence. Could the switch-in-synthetic-mode rationale from the changelog be added to the comment? The reason matters because the only in-tree explanation of bnxt_clear_bars() is in bnxt_io_slot_reset(): /* Upon fatal error, our device internal logic that latches to * BAR value is getting reset and will restore only upon * rewriting the BARs. * * As pci_restore_state() does not re-write the BARs if the * value is same as saved value earlier, driver needs to * write the BARs to 0 to force restore, in case of fatal error. */ After an FLR the function's own BAR registers read back as 0, so they no longer match the saved non-zero values and pci_restore_config_dword() would rewrite them regardless. Applying that comment's reasoning to the new call site would make bnxt_clear_bars() look like dead code that can be removed, which would reintroduce the problem being fixed. Is the intent that the synthetic-mode switch shadows config-space reads, and can that be spelled out next to the new call? -- Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260831024342.2161156-1-michael.chan%40broadcom.com ^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH net 4/4] bnxt_en: Re-write the BARs following any type of PCIe errors 2026-08-31 2:43 [PATCH net 0/4] bnxt_en: Bug fixes Michael Chan ` (2 preceding siblings ...) 2026-08-31 2:43 ` [PATCH net 3/4] bnxt_en: Fix driver init in kdump kernel Michael Chan @ 2026-08-31 2:43 ` Michael Chan 2026-09-01 22:15 ` Joe Damato 2026-09-02 5:46 ` [net,4/4] " netdev-bot+sashiko 3 siblings, 2 replies; 11+ messages in thread From: Michael Chan @ 2026-08-31 2:43 UTC (permalink / raw) To: davem Cc: netdev, edumazet, kuba, pabeni, andrew+netdev, pavan.chebbi, andrew.gospodarek, Kalesh AP, Scott Branden From: Pavan Chebbi <pavan.chebbi@broadcom.com> Currently the driver zeroes the BARs only when fatal PCIe errors are reported so that pci_restore_state() restores it. However firmware handles both fatal and non-fatal errors the same way when it sees the slot reset resulting from the PCI_ERS_RESULT_NEED_RESET return code from the driver. This means that we must re-write the BARs post recovery even during non-fatal errors. Otherwise we will see that every MMIO access returns all-ones and the firmware appears dead. Zero-out the BARs during PCIe error recovery regardless of type of PCIe error. Fixes: f75d9a0aa967 ("bnxt_en: Re-write PCI BARs after PCI fatal error.") Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com> Reviewed-by: Scott Branden <scott.branden@broadcom.com> Signed-off-by: Pavan Chebbi <pavan.chebbi@broadcom.com> Signed-off-by: Michael Chan <michael.chan@broadcom.com> --- drivers/net/ethernet/broadcom/bnxt/bnxt.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c index c3d561ac53dc..09fed8784a2a 100644 --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c @@ -17564,7 +17564,7 @@ static pci_ers_result_t bnxt_io_slot_reset(struct pci_dev *pdev) netdev_info(bp->dev, "PCI Slot Reset\n"); - if (test_bit(BNXT_STATE_PCI_CHANNEL_IO_FROZEN, &bp->state)) { + if (test_and_clear_bit(BNXT_STATE_PCI_CHANNEL_IO_FROZEN, &bp->state)) { /* After DPC, the chip should return CRS when the vendor ID * config register is read until it is ready. On all chips, * this is not happening reliably so add a 5-second delay as a @@ -17580,17 +17580,15 @@ static pci_ers_result_t bnxt_io_slot_reset(struct pci_dev *pdev) "Cannot re-enable PCI device after reset.\n"); } else { pci_set_master(pdev); - /* Upon fatal error, our device internal logic that latches to + /* Upon PCIe error, our device internal logic that latches to * BAR value is getting reset and will restore only upon * rewriting the BARs. * * As pci_restore_state() does not re-write the BARs if the * value is same as saved value earlier, driver needs to - * write the BARs to 0 to force restore, in case of fatal error. + * write the BARs to 0 to force restore. */ - if (test_and_clear_bit(BNXT_STATE_PCI_CHANNEL_IO_FROZEN, - &bp->state)) - bnxt_clear_bars(pdev); + bnxt_clear_bars(pdev); pci_restore_state(pdev); bnxt_inv_fw_health_reg(bp); -- 2.51.0 ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH net 4/4] bnxt_en: Re-write the BARs following any type of PCIe errors 2026-08-31 2:43 ` [PATCH net 4/4] bnxt_en: Re-write the BARs following any type of PCIe errors Michael Chan @ 2026-09-01 22:15 ` Joe Damato 2026-09-02 5:46 ` [net,4/4] " netdev-bot+sashiko 1 sibling, 0 replies; 11+ messages in thread From: Joe Damato @ 2026-09-01 22:15 UTC (permalink / raw) To: Michael Chan Cc: davem, netdev, edumazet, kuba, pabeni, andrew+netdev, pavan.chebbi, andrew.gospodarek, Kalesh AP, Scott Branden On Sun, Aug 30, 2026 at 07:43:42PM -0700, Michael Chan wrote: > From: Pavan Chebbi <pavan.chebbi@broadcom.com> > > Currently the driver zeroes the BARs only when fatal PCIe errors > are reported so that pci_restore_state() restores it. However > firmware handles both fatal and non-fatal errors the same way when > it sees the slot reset resulting from the PCI_ERS_RESULT_NEED_RESET > return code from the driver. This means that we must re-write the > BARs post recovery even during non-fatal errors. Otherwise we will > see that every MMIO access returns all-ones and the firmware appears > dead. > > Zero-out the BARs during PCIe error recovery regardless of type of > PCIe error. > > Fixes: f75d9a0aa967 ("bnxt_en: Re-write PCI BARs after PCI fatal error.") > Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com> > Reviewed-by: Scott Branden <scott.branden@broadcom.com> > Signed-off-by: Pavan Chebbi <pavan.chebbi@broadcom.com> > Signed-off-by: Michael Chan <michael.chan@broadcom.com> > --- > drivers/net/ethernet/broadcom/bnxt/bnxt.c | 10 ++++------ > 1 file changed, 4 insertions(+), 6 deletions(-) > Reviewed-by: Joe Damato <joe@dama.to> ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [net,4/4] bnxt_en: Re-write the BARs following any type of PCIe errors 2026-08-31 2:43 ` [PATCH net 4/4] bnxt_en: Re-write the BARs following any type of PCIe errors Michael Chan 2026-09-01 22:15 ` Joe Damato @ 2026-09-02 5:46 ` netdev-bot+sashiko 1 sibling, 0 replies; 11+ messages in thread From: netdev-bot+sashiko @ 2026-09-02 5:46 UTC (permalink / raw) To: michael.chan Cc: davem, netdev, edumazet, kuba, pabeni, andrew+netdev, pavan.chebbi, andrew.gospodarek, kalesh-anakkur.purayil, scott.branden Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: Critical: 0 · High: 0 · Medium: 1 · Low: 0 (1) - [Medium] The patch makes the BAR rewrite unconditional but leaves the chip-readiness workaround gated on the fatal-only bit. Pre-existing issues: - [Low] bnxt_io_slot_reset() (drivers/net/ethernet/broadcom/bnxt/bnxt.c:17578-17592) zeroes all six… -- bnxt_en: Re-write the BARs following any type of PCIe errors The patch makes bnxt_io_slot_reset() zero the BARs unconditionally so that pci_restore_state() always rewrites them, instead of only doing so when BNXT_STATE_PCI_CHANNEL_IO_FROZEN was set. The clearing of that state bit moves up into the existing readiness-delay test. A couple of questions about the new ordering below. > diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c > index c3d561ac53dc..09fed8784a2a 100644 > --- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c > +++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c > @@ -17564,7 +17564,7 @@ static pci_ers_result_t bnxt_io_slot_reset(struct pci_dev *pdev) > > netdev_info(bp->dev, "PCI Slot Reset\n"); > > - if (test_bit(BNXT_STATE_PCI_CHANNEL_IO_FROZEN, &bp->state)) { > + if (test_and_clear_bit(BNXT_STATE_PCI_CHANNEL_IO_FROZEN, &bp->state)) { > /* After DPC, the chip should return CRS when the vendor ID > * config register is read until it is ready. On all chips, > * this is not happening reliably so add a 5-second delay as a [Severity: Medium] The BAR rewrite becomes unconditional, but the chip-readiness delay stays gated on the fatal-only bit. Is that intentional? BNXT_STATE_PCI_CHANNEL_IO_FROZEN is only set for pci_channel_io_frozen in bnxt_io_error_detected(), yet that function returns PCI_ERS_RESULT_NEED_RESET for non-fatal errors too, and the core then does a real secondary bus reset before calling back: drivers/pci/pcie/err.c:pcie_do_recovery() { ... if (status == PCI_ERS_RESULT_NEED_RESET || state == pci_channel_io_frozen) { if (reset_subordinates(bridge) != PCI_ERS_RESULT_RECOVERED) { ... } So on the non-fatal path the driver now issues bnxt_clear_bars() plus pci_restore_state() right after a bus reset with no delay, even though the comment just above says the chip does not reliably signal readiness after such a reset. If one of those BAR-clear writes does not land while the function is still coming out of reset, the BAR still equals the saved value and the restore is skipped: drivers/pci/pci.c:pci_restore_config_dword() { ... if (!force && val == saved_val) return; ... } which leaves the internal BAR latch stale, MMIO reading all-ones, and the bnxt_try_recover_fw() loop failing all BNXT_FW_SLOT_RESET_RETRY attempts followed by "Firmware not ready" and PCI_ERS_RESULT_DISCONNECT - the same failure mode the commit message aims to remove. Should the readiness delay be made unconditional along with the BAR clear, or should the rewrite be verified with a read-back and retried? Related: bnxt_clear_bars() discards the return value of every pci_write_config_dword() and nothing reads the BARs back afterwards, so a dropped write is silent: for (off = PCI_BASE_ADDRESS_0; off <= PCI_BASE_ADDRESS_5; off += 4) pci_write_config_dword(pdev, off, 0); > @@ -17580,17 +17580,15 @@ static pci_ers_result_t bnxt_io_slot_reset(struct pci_dev *pdev) > "Cannot re-enable PCI device after reset.\n"); > } else { > pci_set_master(pdev); > - /* Upon fatal error, our device internal logic that latches to > + /* Upon PCIe error, our device internal logic that latches to > * BAR value is getting reset and will restore only upon > * rewriting the BARs. > * > * As pci_restore_state() does not re-write the BARs if the > * value is same as saved value earlier, driver needs to > - * write the BARs to 0 to force restore, in case of fatal error. > + * write the BARs to 0 to force restore. > */ > - if (test_and_clear_bit(BNXT_STATE_PCI_CHANNEL_IO_FROZEN, > - &bp->state)) > - bnxt_clear_bars(pdev); > + bnxt_clear_bars(pdev); > pci_restore_state(pdev); [Severity: Low] This isn't a bug introduced by this patch, since the same sequence has been used on the fatal path since f75d9a0aa967, but the patch now makes it run on every PCIe error recovery, so it may be a good moment to ask about the write ordering. bnxt_clear_bars() programs all six BAR dwords to 0 after pci_enable_device() and pci_set_master() have already re-enabled memory decode and bus mastering. bnxt_io_error_detected() calls pci_disable_device(), so enable_cnt reaches 0 and the pci_enable_device() here really does set PCI_COMMAND_MEMORY again. Between bnxt_clear_bars() and pci_restore_state() the function is therefore an enabled decoder claiming a window based at 0, and for a 64-bit BAR written one dword at a time transiently at old_high << 32. The PCI core takes the opposite order: drivers/pci/pci.c:pci_restore_config_space() { ... /* Restore BARs before the command register. */ ... } and pci_std_update_resource() clears PCI_COMMAND_MEMORY before rewriting a memory BAR. The other caller, bnxt_init_one(), matches that convention: if (is_kdump_kernel()) { pci_clear_master(pdev); pci_save_state(pdev); pcie_flr(pdev); bnxt_clear_bars(pdev); pci_restore_state(pdev); } Would it be preferable to zero the BARs with decode disabled, i.e. before pci_enable_device()/pci_set_master(), or to clear PCI_COMMAND_MEMORY around bnxt_clear_bars()? -- Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260831024342.2161156-1-michael.chan%40broadcom.com ^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2026-09-02 5:46 UTC | newest] Thread overview: 11+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-08-31 2:43 [PATCH net 0/4] bnxt_en: Bug fixes Michael Chan 2026-08-31 2:43 ` [PATCH net 1/4] bnxt_en: Fix ring accounting underflow when rings are constrained Michael Chan 2026-09-02 5:46 ` [net,1/4] " netdev-bot+sashiko 2026-08-31 2:43 ` [PATCH net 2/4] bnxt_en: Add bnxt_clear_bars() helper Michael Chan 2026-09-01 22:09 ` Joe Damato 2026-08-31 2:43 ` [PATCH net 3/4] bnxt_en: Fix driver init in kdump kernel Michael Chan 2026-09-01 22:20 ` Joe Damato 2026-09-02 5:46 ` [net,3/4] " netdev-bot+sashiko 2026-08-31 2:43 ` [PATCH net 4/4] bnxt_en: Re-write the BARs following any type of PCIe errors Michael Chan 2026-09-01 22:15 ` Joe Damato 2026-09-02 5:46 ` [net,4/4] " netdev-bot+sashiko
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox