diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2024-03-12 20:14:20 +0300 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2024-03-12 20:14:20 +0300 |
commit | c6c411a9489bd16c13e326fb503b46e5322d6eae (patch) | |
tree | 6875bf0db63f8006bce4cea50041b97ed7d9a0bf /drivers/pci/pcie | |
parent | 47c94b2de5cd86c98dc5a6c84c97024669b0ccac (diff) | |
parent | 627c6db20703b5d18d928464f411d0d4ec327508 (diff) | |
download | linux-c6c411a9489bd16c13e326fb503b46e5322d6eae.tar.xz |
Merge branch 'pci/dpc'
- After a DPC event, print all logged TLP Prefixes instead of printing the
first prefix several times (Ilpo Järvinen)
- Ignore the expected Surprise Down error that may cause a DPC event when
hot-removing a device (Smita Koralahalli)
- Add an RP PIO log size quirk for Intel Raptor Lake Root Ports, which
still don't advertise the correct log size, which prevented logging of RP
PIO Log registers when DPC is triggered (Paul Menzel)
* pci/dpc:
PCI/DPC: Quirk PIO log size for Intel Raptor Lake Root Ports
PCI/DPC: Ignore Surprise Down error on hot removal
PCI/DPC: Print all TLP Prefixes, not just the first
Diffstat (limited to 'drivers/pci/pcie')
-rw-r--r-- | drivers/pci/pcie/dpc.c | 62 |
1 files changed, 61 insertions, 1 deletions
diff --git a/drivers/pci/pcie/dpc.c b/drivers/pci/pcie/dpc.c index c197bc7f7f2c..a668820696dc 100644 --- a/drivers/pci/pcie/dpc.c +++ b/drivers/pci/pcie/dpc.c @@ -228,7 +228,7 @@ static void dpc_process_rp_pio_error(struct pci_dev *pdev) for (i = 0; i < pdev->dpc_rp_log_size - 5; i++) { pci_read_config_dword(pdev, - cap + PCI_EXP_DPC_RP_PIO_TLPPREFIX_LOG, &prefix); + cap + PCI_EXP_DPC_RP_PIO_TLPPREFIX_LOG + i * 4, &prefix); pci_err(pdev, "TLP Prefix Header: dw%d, %#010x\n", i, prefix); } clear_status: @@ -297,10 +297,70 @@ void dpc_process_error(struct pci_dev *pdev) } } +static void pci_clear_surpdn_errors(struct pci_dev *pdev) +{ + if (pdev->dpc_rp_extensions) + pci_write_config_dword(pdev, pdev->dpc_cap + + PCI_EXP_DPC_RP_PIO_STATUS, ~0); + + /* + * In practice, Surprise Down errors have been observed to also set + * error bits in the Status Register as well as the Fatal Error + * Detected bit in the Device Status Register. + */ + pci_write_config_word(pdev, PCI_STATUS, 0xffff); + + pcie_capability_write_word(pdev, PCI_EXP_DEVSTA, PCI_EXP_DEVSTA_FED); +} + +static void dpc_handle_surprise_removal(struct pci_dev *pdev) +{ + if (!pcie_wait_for_link(pdev, false)) { + pci_info(pdev, "Data Link Layer Link Active not cleared in 1000 msec\n"); + goto out; + } + + if (pdev->dpc_rp_extensions && dpc_wait_rp_inactive(pdev)) + goto out; + + pci_aer_raw_clear_status(pdev); + pci_clear_surpdn_errors(pdev); + + pci_write_config_word(pdev, pdev->dpc_cap + PCI_EXP_DPC_STATUS, + PCI_EXP_DPC_STATUS_TRIGGER); + +out: + clear_bit(PCI_DPC_RECOVERED, &pdev->priv_flags); + wake_up_all(&dpc_completed_waitqueue); +} + +static bool dpc_is_surprise_removal(struct pci_dev *pdev) +{ + u16 status; + + if (!pdev->is_hotplug_bridge) + return false; + + if (pci_read_config_word(pdev, pdev->aer_cap + PCI_ERR_UNCOR_STATUS, + &status)) + return false; + + return status & PCI_ERR_UNC_SURPDN; +} + static irqreturn_t dpc_handler(int irq, void *context) { struct pci_dev *pdev = context; + /* + * According to PCIe r6.0 sec 6.7.6, errors are an expected side effect + * of async removal and should be ignored by software. + */ + if (dpc_is_surprise_removal(pdev)) { + dpc_handle_surprise_removal(pdev); + return IRQ_HANDLED; + } + dpc_process_error(pdev); /* We configure DPC so it only triggers on ERR_FATAL */ |