summaryrefslogtreecommitdiffstats
path: root/drivers/acpi/apei/ghes.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/apei/ghes.c')
-rw-r--r--drivers/acpi/apei/ghes.c46
1 files changed, 27 insertions, 19 deletions
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index 33144ab0661a..a34f79153b1a 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -305,29 +305,30 @@ static void ghes_copy_tofrom_phys(void *buffer, u64 paddr, u32 len,
}
}
-static int ghes_read_estatus(struct ghes *ghes)
+static int ghes_read_estatus(struct ghes *ghes, u64 *buf_paddr)
{
struct acpi_hest_generic *g = ghes->generic;
- u64 buf_paddr;
u32 len;
int rc;
- rc = apei_read(&buf_paddr, &g->error_status_address);
+ rc = apei_read(buf_paddr, &g->error_status_address);
if (rc) {
+ *buf_paddr = 0;
pr_warn_ratelimited(FW_WARN GHES_PFX
"Failed to read error status block address for hardware error source: %d.\n",
g->header.source_id);
return -EIO;
}
- if (!buf_paddr)
+ if (!*buf_paddr)
return -ENOENT;
- ghes_copy_tofrom_phys(ghes->estatus, buf_paddr,
+ ghes_copy_tofrom_phys(ghes->estatus, *buf_paddr,
sizeof(*ghes->estatus), 1);
- if (!ghes->estatus->block_status)
+ if (!ghes->estatus->block_status) {
+ *buf_paddr = 0;
return -ENOENT;
+ }
- ghes->buffer_paddr = buf_paddr;
ghes->flags |= GHES_TO_CLEAR;
rc = -EIO;
@@ -339,7 +340,7 @@ static int ghes_read_estatus(struct ghes *ghes)
if (cper_estatus_check_header(ghes->estatus))
goto err_read_block;
ghes_copy_tofrom_phys(ghes->estatus + 1,
- buf_paddr + sizeof(*ghes->estatus),
+ *buf_paddr + sizeof(*ghes->estatus),
len - sizeof(*ghes->estatus), 1);
if (cper_estatus_check(ghes->estatus))
goto err_read_block;
@@ -349,15 +350,20 @@ err_read_block:
if (rc)
pr_warn_ratelimited(FW_WARN GHES_PFX
"Failed to read error status block!\n");
+
return rc;
}
-static void ghes_clear_estatus(struct ghes *ghes)
+static void ghes_clear_estatus(struct ghes *ghes, u64 buf_paddr)
{
ghes->estatus->block_status = 0;
if (!(ghes->flags & GHES_TO_CLEAR))
return;
- ghes_copy_tofrom_phys(ghes->estatus, ghes->buffer_paddr,
+
+ if (!buf_paddr)
+ return;
+
+ ghes_copy_tofrom_phys(ghes->estatus, buf_paddr,
sizeof(ghes->estatus->block_status), 0);
ghes->flags &= ~GHES_TO_CLEAR;
}
@@ -666,11 +672,11 @@ static int ghes_ack_error(struct acpi_hest_generic_v2 *gv2)
return apei_write(val, &gv2->read_ack_register);
}
-static void __ghes_panic(struct ghes *ghes)
+static void __ghes_panic(struct ghes *ghes, u64 buf_paddr)
{
__ghes_print_estatus(KERN_EMERG, ghes->generic, ghes->estatus);
- ghes_clear_estatus(ghes);
+ ghes_clear_estatus(ghes, buf_paddr);
/* reboot to log the error! */
if (!panic_timeout)
@@ -680,14 +686,15 @@ static void __ghes_panic(struct ghes *ghes)
static int ghes_proc(struct ghes *ghes)
{
+ u64 buf_paddr;
int rc;
- rc = ghes_read_estatus(ghes);
+ rc = ghes_read_estatus(ghes, &buf_paddr);
if (rc)
goto out;
if (ghes_severity(ghes->estatus->error_severity) >= GHES_SEV_PANIC) {
- __ghes_panic(ghes);
+ __ghes_panic(ghes, buf_paddr);
}
if (!ghes_estatus_cached(ghes->estatus)) {
@@ -697,7 +704,7 @@ static int ghes_proc(struct ghes *ghes)
ghes_do_proc(ghes, ghes->estatus);
out:
- ghes_clear_estatus(ghes);
+ ghes_clear_estatus(ghes, buf_paddr);
if (rc == -ENOENT)
return rc;
@@ -912,6 +919,7 @@ static void __process_error(struct ghes *ghes)
static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs)
{
+ u64 buf_paddr;
struct ghes *ghes;
int sev, ret = NMI_DONE;
@@ -919,8 +927,8 @@ static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs)
return ret;
list_for_each_entry_rcu(ghes, &ghes_nmi, list) {
- if (ghes_read_estatus(ghes)) {
- ghes_clear_estatus(ghes);
+ if (ghes_read_estatus(ghes, &buf_paddr)) {
+ ghes_clear_estatus(ghes, buf_paddr);
continue;
} else {
ret = NMI_HANDLED;
@@ -929,14 +937,14 @@ static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs)
sev = ghes_severity(ghes->estatus->error_severity);
if (sev >= GHES_SEV_PANIC) {
ghes_print_queued_estatus();
- __ghes_panic(ghes);
+ __ghes_panic(ghes, buf_paddr);
}
if (!(ghes->flags & GHES_TO_CLEAR))
continue;
__process_error(ghes);
- ghes_clear_estatus(ghes);
+ ghes_clear_estatus(ghes, buf_paddr);
}
#ifdef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG