mirror of
https://github.com/torvalds/linux.git
synced 2026-10-24 16:55:02 +02:00
bnxt_en: Fix driver init in kdump kernel
Fix and strengthen the FLR sequence when initializing in the kdump
kernel. 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.
On a Dell system with a PEX89144 PCIe switch, echo c > /proc/sysrq-trigger
will trigger fatal AER without this patch:
bnxt_en 0000:67:00.0: enabling device (0000 -> 0002)
[Hardware Error]: Hardware error from APEI Generic Hardware Error Source: 5
[Hardware Error]: event severity: recoverable
[Hardware Error]: Error 0, type: fatal
[Hardware Error]: section_type: PCIe error
[Hardware Error]: port_type: 5, upstream switch port
...
Add a new bnxt_kdump_reset() to do the expanded FLR sequence in the
kdump kernel. We now disable bus master and memory, save the PCI
state, do the FLR, clear the BARs, and restore the PCI state. The
BARs have to be cleared to ensure that they get re-initialized and
visible to the PCIe switch.
Since it is the kdump kernel, we make every effort to continue in
the best possible way even if pci_save_state() or pcie_flr() returns
error. After FLR, we poll for an additional 5 seconds before
aborting in case the device is not properly returning CRS. This is
similar to the 5-second wait in bnxt_io_slot_reset().
Fixes: 8743db4a9a ("bnxt_en: Issue PCIe FLR in kdump kernel to cleanup pending DMAs.")
Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
Signed-off-by: Pavan Chebbi <pavan.chebbi@broadcom.com>
Signed-off-by: Michael Chan <michael.chan@broadcom.com>
Reviewed-by: Jacob Keller <jacob.e.keller@intel.com>
Link: https://patch.msgid.link/20261005204246.3822563-3-michael.chan@broadcom.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
8f5d59b9cf
commit
386f887c82
|
|
@ -17119,6 +17119,43 @@ static void bnxt_clear_bars(struct pci_dev *pdev)
|
|||
pci_write_config_dword(pdev, off, 0);
|
||||
}
|
||||
|
||||
/* Clear any pending DMA transactions from crash kernel while loading driver in
|
||||
* capture kernel.
|
||||
*/
|
||||
static int bnxt_kdump_reset(struct pci_dev *pdev)
|
||||
{
|
||||
int rc, i;
|
||||
u16 cmd;
|
||||
|
||||
pci_read_config_word(pdev, PCI_COMMAND, &cmd);
|
||||
cmd &= ~(PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
|
||||
pci_write_config_word(pdev, PCI_COMMAND, cmd);
|
||||
|
||||
if (pci_save_state(pdev))
|
||||
dev_warn(&pdev->dev, "Failed to save PCI state, PCI restore may be incomplete\n");
|
||||
|
||||
rc = pcie_flr(pdev);
|
||||
if (rc)
|
||||
dev_warn(&pdev->dev, "pcie_flr() failed (rc: %d), trying to continue\n",
|
||||
rc);
|
||||
|
||||
/* In case device is not returning CRS, wait 5 seconds longer */
|
||||
for (i = 0; i < 50; i++) {
|
||||
pci_read_config_word(pdev, PCI_COMMAND, &cmd);
|
||||
if (!PCI_POSSIBLE_ERROR(cmd))
|
||||
break;
|
||||
msleep(100);
|
||||
}
|
||||
if (PCI_POSSIBLE_ERROR(cmd)) {
|
||||
dev_err(&pdev->dev, "PCI config space inaccessible after FLR, aborting\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
bnxt_clear_bars(pdev);
|
||||
pci_restore_state(pdev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
{
|
||||
struct bnxt_hw_resc *hw_resc;
|
||||
|
|
@ -17134,12 +17171,10 @@ static int bnxt_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Clear any pending DMA transactions from crash kernel
|
||||
* while loading driver in capture kernel.
|
||||
*/
|
||||
if (is_kdump_kernel()) {
|
||||
pci_clear_master(pdev);
|
||||
pcie_flr(pdev);
|
||||
rc = bnxt_kdump_reset(pdev);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
max_irqs = bnxt_get_max_irq(pdev);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user