Message ID | 20241205114048.60291-4-LeoLiu-oc@zhaoxin.com |
---|---|
State | New |
Headers | show |
Series | Parse the HEST PCIe AER and set to relevant registers | expand |
On Thu, Dec 05, 2024 at 07:40:48PM +0800, LeoLiu-oc wrote: > From: LeoLiuoc <LeoLiu-oc@zhaoxin.com> > > Call the func pci_acpi_program_hest_aer_params() for every PCIe device, > the purpose of this function is to extract register value from HEST PCIe > AER structures and program them into AER Capabilities. This function > applies to all hardware platforms that has a PCI Express AER structure > in HEST. > > Signed-off-by: LeoLiuoc <LeoLiu-oc@zhaoxin.com> > --- > drivers/pci/pci-acpi.c | 103 +++++++++++++++++++++++++++++++++++++++++ > drivers/pci/pci.h | 9 ++++ > drivers/pci/probe.c | 1 + > 3 files changed, 113 insertions(+) > > diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c > index af370628e583..6e29af8e6cc4 100644 > --- a/drivers/pci/pci-acpi.c > +++ b/drivers/pci/pci-acpi.c > @@ -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,108 @@ 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; > + u32 uncor_severity; > + u32 cor_mask; > + u32 adv_cap; > + > + uncor_mask = aer_common.uncorrectable_mask; > + uncor_severity = aer_common.uncorrectable_severity; > + cor_mask = aer_common.correctable_mask; > + adv_cap = aer_common.advanced_capabilities; > + These can be done at the same time as the declarations. Same for the remaining functions. > + 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; > + > + 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; > + u32 uncor_severity2; > + u32 adv_cap2; > + > + uncor_mask2 = hest_aer_bridge->uncorrectable_mask2; > + uncor_severity2 = hest_aer_bridge->uncorrectable_severity2; > + 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 = info.hest_aer_root_port; > + 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 = info.hest_aer_endpoint; > + program_hest_aer_common(hest_aer_endpoint->aer, dev, pos); > + break; > + case PCI_EXP_TYPE_PCI_BRIDGE: > + hest_aer_bridge = info.hest_aer_bridge; > + program_hest_aer_common(hest_aer_bridge->aer, dev, pos); > + program_hest_aer_bridge(hest_aer_bridge, dev, pos); > + break; > + default: > + return; > + break; > + } > +} > + > +int 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 -ENODEV; > + > + if (apei_hest_parse(hest_parse_pcie_aer, &info) == 1) Don't need the "== 1". > + program_hest_aer_params(info); > + > + return 0; > +} > +#endif > + > /** > * pciehp_is_native - Check whether a hotplug port is handled by the OS > * @bridge: Hotplug port to check > diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h > index 2e40fc63ba31..78bdc121c905 100644 > --- a/drivers/pci/pci.h > +++ b/drivers/pci/pci.h > @@ -897,6 +897,15 @@ 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 > +int pci_acpi_program_hest_aer_params(struct pci_dev *dev); The return value is never checked, so this can return void. > +#else > +static inline int pci_acpi_program_hest_aer_params(struct pci_dev *dev) > +{ > + return 0; > +} > +#endif > + > #ifdef CONFIG_ACPI > bool pci_acpi_preserve_config(struct pci_host_bridge *bridge); > int pci_acpi_program_hp_params(struct pci_dev *dev); > diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c > index 2e81ab0f5a25..33b8b46ca554 100644 > --- a/drivers/pci/probe.c > +++ b/drivers/pci/probe.c > @@ -2304,6 +2304,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); This should not be called here unconditionally. OS should only write AER registers if granted permission through _OSC. It would be more appropriate to call this from pci_aer_init(). Thanks, Yazen
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index af370628e583..6e29af8e6cc4 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -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,108 @@ 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; + u32 uncor_severity; + u32 cor_mask; + u32 adv_cap; + + uncor_mask = aer_common.uncorrectable_mask; + uncor_severity = aer_common.uncorrectable_severity; + cor_mask = aer_common.correctable_mask; + 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; + + 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; + u32 uncor_severity2; + u32 adv_cap2; + + uncor_mask2 = hest_aer_bridge->uncorrectable_mask2; + uncor_severity2 = hest_aer_bridge->uncorrectable_severity2; + 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 = info.hest_aer_root_port; + 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 = info.hest_aer_endpoint; + program_hest_aer_common(hest_aer_endpoint->aer, dev, pos); + break; + case PCI_EXP_TYPE_PCI_BRIDGE: + hest_aer_bridge = info.hest_aer_bridge; + program_hest_aer_common(hest_aer_bridge->aer, dev, pos); + program_hest_aer_bridge(hest_aer_bridge, dev, pos); + break; + default: + return; + break; + } +} + +int 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 -ENODEV; + + if (apei_hest_parse(hest_parse_pcie_aer, &info) == 1) + program_hest_aer_params(info); + + return 0; +} +#endif + /** * pciehp_is_native - Check whether a hotplug port is handled by the OS * @bridge: Hotplug port to check diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 2e40fc63ba31..78bdc121c905 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -897,6 +897,15 @@ 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 +int pci_acpi_program_hest_aer_params(struct pci_dev *dev); +#else +static inline int pci_acpi_program_hest_aer_params(struct pci_dev *dev) +{ + return 0; +} +#endif + #ifdef CONFIG_ACPI bool pci_acpi_preserve_config(struct pci_host_bridge *bridge); int pci_acpi_program_hp_params(struct pci_dev *dev); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 2e81ab0f5a25..33b8b46ca554 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2304,6 +2304,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)