Merge back APEI material for v4.16.

This commit is contained in:
Rafael J. Wysocki 2017-12-21 01:54:44 +01:00
commit fd0861952d
1 changed files with 46 additions and 33 deletions

View File

@ -414,6 +414,51 @@ static void ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, int
#endif #endif
} }
/*
* PCIe AER errors need to be sent to the AER driver for reporting and
* recovery. The GHES severities map to the following AER severities and
* require the following handling:
*
* GHES_SEV_CORRECTABLE -> AER_CORRECTABLE
* These need to be reported by the AER driver but no recovery is
* necessary.
* GHES_SEV_RECOVERABLE -> AER_NONFATAL
* GHES_SEV_RECOVERABLE && CPER_SEC_RESET -> AER_FATAL
* These both need to be reported and recovered from by the AER driver.
* GHES_SEV_PANIC does not make it to this handling since the kernel must
* panic.
*/
static void ghes_handle_aer(struct acpi_hest_generic_data *gdata)
{
#ifdef CONFIG_ACPI_APEI_PCIEAER
struct cper_sec_pcie *pcie_err = acpi_hest_get_payload(gdata);
if (pcie_err->validation_bits & CPER_PCIE_VALID_DEVICE_ID &&
pcie_err->validation_bits & CPER_PCIE_VALID_AER_INFO) {
unsigned int devfn;
int aer_severity;
devfn = PCI_DEVFN(pcie_err->device_id.device,
pcie_err->device_id.function);
aer_severity = cper_severity_to_aer(gdata->error_severity);
/*
* If firmware reset the component to contain
* the error, we must reinitialize it before
* use, so treat it as a fatal AER error.
*/
if (gdata->flags & CPER_SEC_RESET)
aer_severity = AER_FATAL;
aer_recover_queue(pcie_err->device_id.segment,
pcie_err->device_id.bus,
devfn, aer_severity,
(struct aer_capability_regs *)
pcie_err->aer_info);
}
#endif
}
static void ghes_do_proc(struct ghes *ghes, static void ghes_do_proc(struct ghes *ghes,
const struct acpi_hest_generic_status *estatus) const struct acpi_hest_generic_status *estatus)
{ {
@ -441,38 +486,9 @@ static void ghes_do_proc(struct ghes *ghes,
arch_apei_report_mem_error(sev, mem_err); arch_apei_report_mem_error(sev, mem_err);
ghes_handle_memory_failure(gdata, sev); ghes_handle_memory_failure(gdata, sev);
} }
#ifdef CONFIG_ACPI_APEI_PCIEAER
else if (guid_equal(sec_type, &CPER_SEC_PCIE)) { else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
struct cper_sec_pcie *pcie_err = acpi_hest_get_payload(gdata); ghes_handle_aer(gdata);
if (sev == GHES_SEV_RECOVERABLE &&
sec_sev == GHES_SEV_RECOVERABLE &&
pcie_err->validation_bits & CPER_PCIE_VALID_DEVICE_ID &&
pcie_err->validation_bits & CPER_PCIE_VALID_AER_INFO) {
unsigned int devfn;
int aer_severity;
devfn = PCI_DEVFN(pcie_err->device_id.device,
pcie_err->device_id.function);
aer_severity = cper_severity_to_aer(gdata->error_severity);
/*
* If firmware reset the component to contain
* the error, we must reinitialize it before
* use, so treat it as a fatal AER error.
*/
if (gdata->flags & CPER_SEC_RESET)
aer_severity = AER_FATAL;
aer_recover_queue(pcie_err->device_id.segment,
pcie_err->device_id.bus,
devfn, aer_severity,
(struct aer_capability_regs *)
pcie_err->aer_info);
}
} }
#endif
else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) { else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) {
struct cper_sec_proc_arm *err = acpi_hest_get_payload(gdata); struct cper_sec_proc_arm *err = acpi_hest_get_payload(gdata);
@ -870,7 +886,6 @@ static void ghes_print_queued_estatus(void)
struct ghes_estatus_node *estatus_node; struct ghes_estatus_node *estatus_node;
struct acpi_hest_generic *generic; struct acpi_hest_generic *generic;
struct acpi_hest_generic_status *estatus; struct acpi_hest_generic_status *estatus;
u32 len, node_len;
llnode = llist_del_all(&ghes_estatus_llist); llnode = llist_del_all(&ghes_estatus_llist);
/* /*
@ -882,8 +897,6 @@ static void ghes_print_queued_estatus(void)
estatus_node = llist_entry(llnode, struct ghes_estatus_node, estatus_node = llist_entry(llnode, struct ghes_estatus_node,
llnode); llnode);
estatus = GHES_ESTATUS_FROM_NODE(estatus_node); estatus = GHES_ESTATUS_FROM_NODE(estatus_node);
len = cper_estatus_len(estatus);
node_len = GHES_ESTATUS_NODE_LEN(len);
generic = estatus_node->generic; generic = estatus_node->generic;
ghes_print_estatus(NULL, generic, estatus); ghes_print_estatus(NULL, generic, estatus);
llnode = llnode->next; llnode = llnode->next;