diff options
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv.c | 2 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv.h | 3 | ||||
-rw-r--r-- | drivers/pci/pcie/aer/aerdrv_acpi.c | 34 | ||||
-rw-r--r-- | drivers/pci/pcie/portdrv_acpi.c | 2 |
4 files changed, 39 insertions, 2 deletions
diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c index f409948e1a9b..2b2b6508efde 100644 --- a/drivers/pci/pcie/aer/aerdrv.c +++ b/drivers/pci/pcie/aer/aerdrv.c @@ -416,7 +416,7 @@ static void aer_error_resume(struct pci_dev *dev) */ static int __init aer_service_init(void) { - if (!pci_aer_available()) + if (!pci_aer_available() || aer_acpi_firmware_first()) return -ENXIO; return pcie_port_service_register(&aerdriver); } diff --git a/drivers/pci/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h index 80c11d131499..9656e3060412 100644 --- a/drivers/pci/pcie/aer/aerdrv.h +++ b/drivers/pci/pcie/aer/aerdrv.h @@ -132,6 +132,7 @@ static inline int aer_osc_setup(struct pcie_device *pciedev) #ifdef CONFIG_ACPI_APEI extern int pcie_aer_get_firmware_first(struct pci_dev *pci_dev); +extern bool aer_acpi_firmware_first(void); #else static inline int pcie_aer_get_firmware_first(struct pci_dev *pci_dev) { @@ -139,6 +140,8 @@ static inline int pcie_aer_get_firmware_first(struct pci_dev *pci_dev) return pci_dev->__aer_firmware_first; return 0; } + +static inline bool aer_acpi_firmware_first(void) { return false; } #endif static inline void pcie_aer_force_firmware_first(struct pci_dev *pci_dev, diff --git a/drivers/pci/pcie/aer/aerdrv_acpi.c b/drivers/pci/pcie/aer/aerdrv_acpi.c index 2bb9b8972211..275bf158ffa7 100644 --- a/drivers/pci/pcie/aer/aerdrv_acpi.c +++ b/drivers/pci/pcie/aer/aerdrv_acpi.c @@ -93,4 +93,38 @@ int pcie_aer_get_firmware_first(struct pci_dev *dev) aer_set_firmware_first(dev); return dev->__aer_firmware_first; } + +static bool aer_firmware_first; + +static int aer_hest_parse_aff(struct acpi_hest_header *hest_hdr, void *data) +{ + struct acpi_hest_aer_common *p; + + if (aer_firmware_first) + return 0; + + switch (hest_hdr->type) { + case ACPI_HEST_TYPE_AER_ROOT_PORT: + case ACPI_HEST_TYPE_AER_ENDPOINT: + case ACPI_HEST_TYPE_AER_BRIDGE: + p = (struct acpi_hest_aer_common *)(hest_hdr + 1); + aer_firmware_first = !!(p->flags & ACPI_HEST_FIRMWARE_FIRST); + default: + return 0; + } +} + +/** + * aer_acpi_firmware_first - Check if APEI should control AER. + */ +bool aer_acpi_firmware_first(void) +{ + static bool parsed = false; + + if (!parsed) { + apei_hest_parse(aer_hest_parse_aff, NULL); + parsed = true; + } + return aer_firmware_first; +} #endif diff --git a/drivers/pci/pcie/portdrv_acpi.c b/drivers/pci/pcie/portdrv_acpi.c index b7c4cb1ccb23..5982b6a63b89 100644 --- a/drivers/pci/pcie/portdrv_acpi.c +++ b/drivers/pci/pcie/portdrv_acpi.c @@ -49,7 +49,7 @@ int pcie_port_acpi_setup(struct pci_dev *port, int *srv_mask) | OSC_PCI_EXPRESS_PME_CONTROL; if (pci_aer_available()) { - if (pcie_aer_get_firmware_first(port)) + if (aer_acpi_firmware_first()) dev_dbg(&port->dev, "PCIe errors handled by BIOS.\n"); else flags |= OSC_PCI_EXPRESS_AER_CONTROL; |