[PATCH net v2 1/9] bnxt_en: Clear bp->total_irqs in bnxt_init_int_mode() during error
From: Michael Chan <michael.chan@broadcom.com>
Date: 2026-09-28 04:19:54
Subsystem:
broadcom bnxt_en 50 gigabit ethernet driver, networking drivers, the rest · Maintainers:
Michael Chan, Pavan Chebbi, Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
During error, bnxt_init_int_mode() will free bp->irq_tbl but
bp->total_irqs retains the old value. If a subsequent
reinitialization happens, bnxt_reserve_rings() may see that
bp->total_irqs does not match a new irqs_required. It will then
try to adjust if dynamic MSI-X is supported and call
bnxt_change_msix(). It will then crash when dereferencing the NULL
bp->irq_tbl.
Fix it by clearing bp->total_irqs when freeing bp->irq_tbl. Dynamic
MSI-X adjustments should only proceed if bp->irq_tbl is valid which
means that MSI-X has been initialized and can be adjusted.
Add a bp->irq_tbl_size to prevent OOB bp->irq_tbl[] array access in
case MSI-X capabilities change during re-init. For dynamic MSI-X,
allocate the biggest bp->irq_tbl that is not clamped by CP/NQ rings
to allow dynamic MSI-X to grow to the max.
In the AER path, if MSI-X capabilities change, bnxt_reserve_rings()
will initialize MSI-X if BNXT_NEW_RM() is true. Add a check in
bnxt_io_resume() to skip doing it again later.
Fixes: e68256c8a73c ("bnxt_en: Support dynamic MSIX")
Reviewed-by: Andy Gospodarek <redacted>
Signed-off-by: Michael Chan <michael.chan@broadcom.com>
---
drivers/net/ethernet/broadcom/bnxt/bnxt.c | 18 ++++++++++++++----
drivers/net/ethernet/broadcom/bnxt/bnxt.h | 1 +
2 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.c b/drivers/net/ethernet/broadcom/bnxt/bnxt.c
index d7728d0c5b6e..51557ee6c9ad 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.c
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.c@@ -11511,6 +11511,12 @@ static int bnxt_change_msix(struct bnxt *bp, int total) struct msi_map map; int i; + if (!bp->irq_tbl) + return 0; + + if (total > bp->irq_tbl_size) + return bp->total_irqs; + /* add MSIX to the end if needed */ for (i = bp->total_irqs; i < total; i++) { map = pci_msix_alloc_irq_at(bp->pdev, i, NULL);
@@ -11653,12 +11659,13 @@ static int bnxt_init_int_mode(struct bnxt *bp) tbl_size = total_vecs; if (pci_msix_can_alloc_dyn(bp->pdev)) - tbl_size = max; + tbl_size = bp->hw_resc.max_irqs; bp->irq_tbl = kzalloc_objs(*bp->irq_tbl, tbl_size); if (!bp->irq_tbl) { rc = -ENOMEM; goto msix_setup_exit; } + bp->irq_tbl_size = tbl_size; for (i = 0; i < total_vecs; i++) bp->irq_tbl[i].vector = pci_irq_vector(bp->pdev, i);
@@ -11681,6 +11688,8 @@ static int bnxt_init_int_mode(struct bnxt *bp) netdev_err(bp->dev, "bnxt_init_int_mode err: %x\n", rc); kfree(bp->irq_tbl); bp->irq_tbl = NULL; + bp->total_irqs = 0; + bp->irq_tbl_size = 0; pci_free_irq_vectors(bp->pdev); return rc; }
@@ -11691,6 +11700,7 @@ static void bnxt_clear_int_mode(struct bnxt *bp) kfree(bp->irq_tbl); bp->irq_tbl = NULL; + bp->irq_tbl_size = 0; } int bnxt_reserve_rings(struct bnxt *bp, bool irq_re_init)
@@ -11717,7 +11727,7 @@ int bnxt_reserve_rings(struct bnxt *bp, bool irq_re_init) if (irq_re_init && BNXT_NEW_RM(bp) && irqs_required != bp->total_irqs) { irq_change = true; - if (!pci_msix_can_alloc_dyn(bp->pdev)) { + if (!pci_msix_can_alloc_dyn(bp->pdev) || !bp->irq_tbl) { bnxt_ulp_irq_stop(bp); bnxt_clear_int_mode(bp); irq_cleared = true;
@@ -15081,7 +15091,7 @@ int bnxt_check_rings(struct bnxt *bp, int tx, int rx, bool sh, int tcs, hwr.cp += bnxt_get_ulp_msix_num(bp); hwr.cp = min_t(int, hwr.cp, bnxt_get_max_func_irqs(bp)); } - if (hwr.cp > bp->total_irqs) { + if (bp->irq_tbl && hwr.cp > bp->total_irqs) { int total_msix = bnxt_change_msix(bp, hwr.cp); if (total_msix < hwr.cp) {
@@ -17692,7 +17702,7 @@ static void bnxt_io_resume(struct pci_dev *pdev) err = bnxt_open(netdev); } else { err = bnxt_reserve_rings(bp, true); - if (!err) + if (!err && !bp->irq_tbl) err = bnxt_init_int_mode(bp); } }
diff --git a/drivers/net/ethernet/broadcom/bnxt/bnxt.h b/drivers/net/ethernet/broadcom/bnxt/bnxt.h
index c673b2ce4a0d..a757d8258f71 100644
--- a/drivers/net/ethernet/broadcom/bnxt/bnxt.h
+++ b/drivers/net/ethernet/broadcom/bnxt/bnxt.h@@ -2490,6 +2490,7 @@ struct bnxt { */ unsigned long *ring_affinity_set; int max_irqs; + int irq_tbl_size; int total_irqs; int ulp_num_msix_want; u8 mac_addr[ETH_ALEN];
--
2.51.0