@@ -19,6 +19,7 @@
#include <linux/pm_runtime.h>
#include <linux/pm_qos.h>
#include <linux/rwsem.h>
+#include <acpi/apei.h>
#include "pci.h"
/*
@@ -806,6 +807,95 @@ int pci_acpi_program_hp_params(struct pci_dev *dev)
return -ENODEV;
}
+#ifdef CONFIG_ACPI_APEI
+/*
+ * program_hest_aer_common() - configure AER common registers for Root Ports,
+ * Endpoints and PCIe to PCI/PCI-X bridges
+ */
+static void program_hest_aer_common(struct acpi_hest_aer_common aer_common, struct pci_dev *dev,
+ int pos)
+{
+ u32 uncor_mask = aer_common.uncorrectable_mask;
+ u32 uncor_severity = aer_common.uncorrectable_severity;
+ u32 cor_mask = aer_common.correctable_mask;
+ u32 adv_cap = aer_common.advanced_capabilities;
+
+ pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_MASK, uncor_mask);
+ pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, uncor_severity);
+ pci_write_config_dword(dev, pos + PCI_ERR_COR_MASK, cor_mask);
+ pci_write_config_dword(dev, pos + PCI_ERR_CAP, adv_cap);
+}
+
+static void program_hest_aer_root(struct acpi_hest_aer_root *aer_root, struct pci_dev *dev, int pos)
+{
+ u32 root_err_cmd = aer_root->root_error_command;
+
+ pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, root_err_cmd);
+}
+
+static void program_hest_aer_bridge(struct acpi_hest_aer_bridge *hest_aer_bridge,
+ struct pci_dev *dev, int pos)
+{
+ u32 uncor_mask2 = hest_aer_bridge->uncorrectable_mask2;
+ u32 uncor_severity2 = hest_aer_bridge->uncorrectable_severity2;
+ u32 adv_cap2 = hest_aer_bridge->advanced_capabilities2;
+
+ pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_MASK2, uncor_mask2);
+ pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER2, uncor_severity2);
+ pci_write_config_dword(dev, pos + PCI_ERR_CAP2, adv_cap2);
+}
+
+static void program_hest_aer_params(struct hest_parse_aer_info info)
+{
+ struct pci_dev *dev;
+ int port_type;
+ int pos;
+ struct acpi_hest_aer_root *hest_aer_root;
+ struct acpi_hest_aer *hest_aer_endpoint;
+ struct acpi_hest_aer_bridge *hest_aer_bridge;
+
+ dev = info.pci_dev;
+ port_type = pci_pcie_type(dev);
+ pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ERR);
+ if (!pos)
+ return;
+
+ switch (port_type) {
+ case PCI_EXP_TYPE_ROOT_PORT:
+ hest_aer_root = (struct acpi_hest_aer_root *)info.data;
+ program_hest_aer_common(hest_aer_root->aer, dev, pos);
+ program_hest_aer_root(hest_aer_root, dev, pos);
+ break;
+ case PCI_EXP_TYPE_ENDPOINT:
+ hest_aer_endpoint = (struct acpi_hest_aer *)info.data;
+ program_hest_aer_common(hest_aer_endpoint->aer, dev, pos);
+ break;
+ case PCI_EXP_TYPE_PCI_BRIDGE:
+ hest_aer_bridge = (struct acpi_hest_aer_bridge *)info.data;
+ program_hest_aer_common(hest_aer_bridge->aer, dev, pos);
+ program_hest_aer_bridge(hest_aer_bridge, dev, pos);
+ break;
+ default:
+ break;
+ }
+}
+
+void pci_acpi_program_hest_aer_params(struct pci_dev *dev)
+{
+ struct hest_parse_aer_info info = {
+ .pci_dev = dev
+ };
+
+ if (!pci_is_pcie(dev))
+ return;
+
+ if (apei_hest_parse(hest_parse_pcie_aer, &info) > 0)
+ program_hest_aer_params(info);
+
+ return;
+}
+#endif
+
/**
* pciehp_is_native - Check whether a hotplug port is handled by the OS
* @bridge: Hotplug port to check
@@ -902,6 +902,12 @@ static inline void pci_save_aer_state(struct pci_dev *dev) { }
static inline void pci_restore_aer_state(struct pci_dev *dev) { }
#endif
+#ifdef CONFIG_ACPI_APEI
+void pci_acpi_program_hest_aer_params(struct pci_dev *dev);
+#else
+static inline void pci_acpi_program_hest_aer_params(struct pci_dev *dev){ }
+#endif
+
#ifdef CONFIG_ACPI
bool pci_acpi_preserve_config(struct pci_host_bridge *bridge);
int pci_acpi_program_hp_params(struct pci_dev *dev);
@@ -2352,6 +2352,7 @@ static void pci_configure_device(struct pci_dev *dev)
pci_configure_serr(dev);
pci_acpi_program_hp_params(dev);
+ pci_acpi_program_hest_aer_params(dev);
}
static void pci_release_capabilities(struct pci_dev *dev)