diff options
| -rw-r--r-- | drivers/acpi/apei/ghes.c | 79 |
1 files changed, 46 insertions, 33 deletions
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 6402f7fad3bb..16c4a10b7506 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c | |||
| @@ -414,6 +414,51 @@ static void ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, int | |||
| 414 | #endif | 414 | #endif |
| 415 | } | 415 | } |
| 416 | 416 | ||
| 417 | /* | ||
| 418 | * PCIe AER errors need to be sent to the AER driver for reporting and | ||
| 419 | * recovery. The GHES severities map to the following AER severities and | ||
| 420 | * require the following handling: | ||
| 421 | * | ||
| 422 | * GHES_SEV_CORRECTABLE -> AER_CORRECTABLE | ||
| 423 | * These need to be reported by the AER driver but no recovery is | ||
| 424 | * necessary. | ||
| 425 | * GHES_SEV_RECOVERABLE -> AER_NONFATAL | ||
| 426 | * GHES_SEV_RECOVERABLE && CPER_SEC_RESET -> AER_FATAL | ||
| 427 | * These both need to be reported and recovered from by the AER driver. | ||
| 428 | * GHES_SEV_PANIC does not make it to this handling since the kernel must | ||
| 429 | * panic. | ||
| 430 | */ | ||
| 431 | static void ghes_handle_aer(struct acpi_hest_generic_data *gdata) | ||
| 432 | { | ||
| 433 | #ifdef CONFIG_ACPI_APEI_PCIEAER | ||
| 434 | struct cper_sec_pcie *pcie_err = acpi_hest_get_payload(gdata); | ||
| 435 | |||
| 436 | if (pcie_err->validation_bits & CPER_PCIE_VALID_DEVICE_ID && | ||
| 437 | pcie_err->validation_bits & CPER_PCIE_VALID_AER_INFO) { | ||
| 438 | unsigned int devfn; | ||
| 439 | int aer_severity; | ||
| 440 | |||
| 441 | devfn = PCI_DEVFN(pcie_err->device_id.device, | ||
| 442 | pcie_err->device_id.function); | ||
| 443 | aer_severity = cper_severity_to_aer(gdata->error_severity); | ||
| 444 | |||
| 445 | /* | ||
| 446 | * If firmware reset the component to contain | ||
| 447 | * the error, we must reinitialize it before | ||
| 448 | * use, so treat it as a fatal AER error. | ||
| 449 | */ | ||
| 450 | if (gdata->flags & CPER_SEC_RESET) | ||
| 451 | aer_severity = AER_FATAL; | ||
| 452 | |||
| 453 | aer_recover_queue(pcie_err->device_id.segment, | ||
| 454 | pcie_err->device_id.bus, | ||
| 455 | devfn, aer_severity, | ||
| 456 | (struct aer_capability_regs *) | ||
| 457 | pcie_err->aer_info); | ||
| 458 | } | ||
| 459 | #endif | ||
| 460 | } | ||
| 461 | |||
| 417 | static void ghes_do_proc(struct ghes *ghes, | 462 | static void ghes_do_proc(struct ghes *ghes, |
| 418 | const struct acpi_hest_generic_status *estatus) | 463 | const struct acpi_hest_generic_status *estatus) |
| 419 | { | 464 | { |
| @@ -441,38 +486,9 @@ static void ghes_do_proc(struct ghes *ghes, | |||
| 441 | arch_apei_report_mem_error(sev, mem_err); | 486 | arch_apei_report_mem_error(sev, mem_err); |
| 442 | ghes_handle_memory_failure(gdata, sev); | 487 | ghes_handle_memory_failure(gdata, sev); |
| 443 | } | 488 | } |
| 444 | #ifdef CONFIG_ACPI_APEI_PCIEAER | ||
| 445 | else if (guid_equal(sec_type, &CPER_SEC_PCIE)) { | 489 | else if (guid_equal(sec_type, &CPER_SEC_PCIE)) { |
| 446 | struct cper_sec_pcie *pcie_err = acpi_hest_get_payload(gdata); | 490 | ghes_handle_aer(gdata); |
| 447 | |||
| 448 | if (sev == GHES_SEV_RECOVERABLE && | ||
| 449 | sec_sev == GHES_SEV_RECOVERABLE && | ||
| 450 | pcie_err->validation_bits & CPER_PCIE_VALID_DEVICE_ID && | ||
| 451 | pcie_err->validation_bits & CPER_PCIE_VALID_AER_INFO) { | ||
| 452 | unsigned int devfn; | ||
| 453 | int aer_severity; | ||
| 454 | |||
| 455 | devfn = PCI_DEVFN(pcie_err->device_id.device, | ||
| 456 | pcie_err->device_id.function); | ||
| 457 | aer_severity = cper_severity_to_aer(gdata->error_severity); | ||
| 458 | |||
| 459 | /* | ||
| 460 | * If firmware reset the component to contain | ||
| 461 | * the error, we must reinitialize it before | ||
| 462 | * use, so treat it as a fatal AER error. | ||
| 463 | */ | ||
| 464 | if (gdata->flags & CPER_SEC_RESET) | ||
| 465 | aer_severity = AER_FATAL; | ||
| 466 | |||
| 467 | aer_recover_queue(pcie_err->device_id.segment, | ||
| 468 | pcie_err->device_id.bus, | ||
| 469 | devfn, aer_severity, | ||
| 470 | (struct aer_capability_regs *) | ||
| 471 | pcie_err->aer_info); | ||
| 472 | } | ||
| 473 | |||
| 474 | } | 491 | } |
| 475 | #endif | ||
| 476 | else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) { | 492 | else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) { |
| 477 | struct cper_sec_proc_arm *err = acpi_hest_get_payload(gdata); | 493 | struct cper_sec_proc_arm *err = acpi_hest_get_payload(gdata); |
| 478 | 494 | ||
| @@ -870,7 +886,6 @@ static void ghes_print_queued_estatus(void) | |||
| 870 | struct ghes_estatus_node *estatus_node; | 886 | struct ghes_estatus_node *estatus_node; |
| 871 | struct acpi_hest_generic *generic; | 887 | struct acpi_hest_generic *generic; |
| 872 | struct acpi_hest_generic_status *estatus; | 888 | struct acpi_hest_generic_status *estatus; |
| 873 | u32 len, node_len; | ||
| 874 | 889 | ||
| 875 | llnode = llist_del_all(&ghes_estatus_llist); | 890 | llnode = llist_del_all(&ghes_estatus_llist); |
| 876 | /* | 891 | /* |
| @@ -882,8 +897,6 @@ static void ghes_print_queued_estatus(void) | |||
| 882 | estatus_node = llist_entry(llnode, struct ghes_estatus_node, | 897 | estatus_node = llist_entry(llnode, struct ghes_estatus_node, |
| 883 | llnode); | 898 | llnode); |
| 884 | estatus = GHES_ESTATUS_FROM_NODE(estatus_node); | 899 | estatus = GHES_ESTATUS_FROM_NODE(estatus_node); |
| 885 | len = cper_estatus_len(estatus); | ||
| 886 | node_len = GHES_ESTATUS_NODE_LEN(len); | ||
| 887 | generic = estatus_node->generic; | 900 | generic = estatus_node->generic; |
| 888 | ghes_print_estatus(NULL, generic, estatus); | 901 | ghes_print_estatus(NULL, generic, estatus); |
| 889 | llnode = llnode->next; | 902 | llnode = llnode->next; |
