[RESEND PATCH v7 2/6] ACPI / APEI: Add callback for memory errors to the GHES notifier

From: Shiju Jose
Date: Tue Apr 21 2020 - 09:23:47 EST


Add callback function for handling the memory errors to the GHES notifier.

Signed-off-by: Shiju Jose <shiju.jose@xxxxxxxxxx>
---
drivers/acpi/apei/ghes.c | 55 ++++++++++++++++++++++++++++++----------
1 file changed, 42 insertions(+), 13 deletions(-)

diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index 5c0ab5422311..053c4a2ed96c 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -471,23 +471,33 @@ static void ghes_clear_estatus(struct ghes *ghes,
ghes_ack_error(ghes->generic_v2);
}

-static void ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, int sev)
+static int ghes_handle_memory_failure(struct notifier_block *nb,
+ unsigned long event, void *data)
{
#ifdef CONFIG_ACPI_APEI_MEMORY_FAILURE
unsigned long pfn;
int flags = -1;
+ int sev = event;
+ struct acpi_hest_generic_data *gdata = data;
int sec_sev = ghes_severity(gdata->error_severity);
struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);

+ if (!guid_equal((guid_t *)gdata->section_type, &CPER_SEC_PLATFORM_MEM))
+ return NOTIFY_DONE;
+
+ ghes_edac_report_mem_error(sev, mem_err);
+
+ arch_apei_report_mem_error(sev, mem_err);
+
if (!(mem_err->validation_bits & CPER_MEM_VALID_PA))
- return;
+ return NOTIFY_STOP;

pfn = mem_err->physical_addr >> PAGE_SHIFT;
if (!pfn_valid(pfn)) {
pr_warn_ratelimited(FW_WARN GHES_PFX
"Invalid address in generic error data: %#llx\n",
mem_err->physical_addr);
- return;
+ return NOTIFY_STOP;
}

/* iff following two events can be handled properly by now */
@@ -500,6 +510,7 @@ static void ghes_handle_memory_failure(struct acpi_hest_generic_data *gdata, int
if (flags != -1)
memory_failure_queue(pfn, flags);
#endif
+ return NOTIFY_STOP;
}

/*
@@ -547,6 +558,22 @@ static void ghes_handle_aer(struct acpi_hest_generic_data *gdata)
#endif
}

+static struct notifier_block ghes_notifier_mem_error = {
+ .notifier_call = ghes_handle_memory_failure,
+};
+
+struct ghes_error_handler_list {
+ const char *name;
+ struct notifier_block *nb;
+};
+
+static const struct ghes_error_handler_list ghes_error_handler_list[] = {
+ {
+ .name = "ghes_notifier_mem_error",
+ .nb = &ghes_notifier_mem_error,
+ },
+};
+
static BLOCKING_NOTIFIER_HEAD(ghes_event_notify_list);

/**
@@ -630,15 +657,7 @@ static void ghes_do_proc(struct ghes *ghes,
break;
}

- if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) {
- struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);
-
- ghes_edac_report_mem_error(sev, mem_err);
-
- arch_apei_report_mem_error(sev, mem_err);
- ghes_handle_memory_failure(gdata, sev);
- }
- else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
+ if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
ghes_handle_aer(gdata);
}
else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) {
@@ -1431,7 +1450,7 @@ static struct platform_driver ghes_platform_driver = {

static int __init ghes_init(void)
{
- int rc;
+ int rc, i;

if (acpi_disabled)
return -ENODEV;
@@ -1473,6 +1492,16 @@ static int __init ghes_init(void)
goto err;
}

+ for (i = 0; i < ARRAY_SIZE(ghes_error_handler_list); i++) {
+ const struct ghes_error_handler_list *list =
+ &ghes_error_handler_list[i];
+ rc = ghes_register_event_notifier(list->nb);
+ if (rc) {
+ pr_warn(GHES_PFX "fail to register %s\n", list->name);
+ goto err;
+ }
+ }
+
return 0;
err:
return rc;
--
2.17.1