summaryrefslogtreecommitdiffstats
path: root/drivers/pci/pcie/err.c
diff options
context:
space:
mode:
authorSean V Kelley <sean.v.kelley@intel.com>2020-12-02 11:26:29 -0600
committerBjorn Helgaas <bhelgaas@google.com>2020-12-05 15:25:58 -0600
commita175102b0a82fc57853a9e611c42d1d6172e5180 (patch)
treef2e4d12b97fd865fa231fa1d44982fd21dd61d5d /drivers/pci/pcie/err.c
parentaa344bc8b727b47b4350b59d8166216a3f351e55 (diff)
downloadlinux-stable-a175102b0a82fc57853a9e611c42d1d6172e5180.tar.gz
linux-stable-a175102b0a82fc57853a9e611c42d1d6172e5180.tar.bz2
linux-stable-a175102b0a82fc57853a9e611c42d1d6172e5180.zip
PCI/ERR: Recover from RCEC AER errors
A Root Complex Event Collector (RCEC) collects and signals AER errors that were detected by Root Complex Integrated Endpoints (RCiEPs), but it may also signal errors it detects itself. This is analogous to errors detected and signaled by a Root Port. Update the AER service driver to claim RCECs in addition to Root Ports. Add support for handling RCEC-detected AER errors. This does not include handling RCiEP-detected errors that are signaled by the RCEC. Note that we expect these errors only from the native AER and APEI paths, not from DPC or EDR. [bhelgaas: split from combined RCEC/RCiEP patch, commit log] Signed-off-by: Sean V Kelley <sean.v.kelley@intel.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Diffstat (limited to 'drivers/pci/pcie/err.c')
-rw-r--r--drivers/pci/pcie/err.c19
1 files changed, 15 insertions, 4 deletions
diff --git a/drivers/pci/pcie/err.c b/drivers/pci/pcie/err.c
index 45a0ce95632a..87a2dc8d17f8 100644
--- a/drivers/pci/pcie/err.c
+++ b/drivers/pci/pcie/err.c
@@ -148,13 +148,16 @@ out:
/**
* pci_walk_bridge - walk bridges potentially AER affected
- * @bridge: bridge which may be a Port
+ * @bridge: bridge which may be a Port or an RCEC
* @cb: callback to be called for each device found
* @userdata: arbitrary pointer to be passed to callback
*
* If the device provided is a bridge, walk the subordinate bus, including
* any bridged devices on buses under this bus. Call the provided callback
* on each device found.
+ *
+ * If the device provided has no subordinate bus, e.g., an RCEC, call the
+ * callback on the device itself.
*/
static void pci_walk_bridge(struct pci_dev *bridge,
int (*cb)(struct pci_dev *, void *),
@@ -162,6 +165,8 @@ static void pci_walk_bridge(struct pci_dev *bridge,
{
if (bridge->subordinate)
pci_walk_bus(bridge->subordinate, cb, userdata);
+ else
+ cb(bridge, userdata);
}
pci_ers_result_t pcie_do_recovery(struct pci_dev *dev,
@@ -174,11 +179,17 @@ pci_ers_result_t pcie_do_recovery(struct pci_dev *dev,
struct pci_host_bridge *host = pci_find_host_bridge(dev->bus);
/*
- * Error recovery runs on all subordinates of the bridge. If the
- * bridge detected the error, it is cleared at the end.
+ * If the error was detected by a Root Port, Downstream Port, or
+ * RCEC, recovery runs on the device itself. For Ports, that also
+ * includes any subordinate devices.
+ *
+ * If it was detected by another device (Endpoint, etc), recovery
+ * runs on the device and anything else under the same Port, i.e.,
+ * everything under "bridge".
*/
if (type == PCI_EXP_TYPE_ROOT_PORT ||
- type == PCI_EXP_TYPE_DOWNSTREAM)
+ type == PCI_EXP_TYPE_DOWNSTREAM ||
+ type == PCI_EXP_TYPE_RC_EC)
bridge = dev;
else
bridge = pci_upstream_bridge(dev);