Skip to content
This repository has been archived by the owner on Jul 16, 2024. It is now read-only.

Commit

Permalink
BACKPORT: ACPI / APEI: Split ghes_read_estatus() to allow a peek at t…
Browse files Browse the repository at this point in the history
…he CPER length

ghes_read_estatus() reads the record address, then the record's
header, then performs some sanity checks before reading the
records into the provided estatus buffer.

To provide this estatus buffer the caller must know the size of the
records in advance, or always provide a worst-case sized buffer as
happens today for the non-NMI notifications.

Add a function to peek at the record's header to find the size. This
will let the NMI path allocate the right amount of memory before reading
the records, instead of using the worst-case size, and having to copy
the records.

Split ghes_read_estatus() to create __ghes_peek_estatus() which
returns the address and size of the CPER records.

This patch is needed because Quicksilver firmware-first error handling
uses the SDEI notification type for communication between trusted
firmware and the OS. This adds needed NMI and SDEI functionality so
that the SDEI path in the kernel through APEI acts as an NMI and is
properly wired up to the APEI interfaces.

Backported from: torvalds/linux@e00a6e3

Signed-off-by: James Morse <[email protected]>
Signed-off-by: Tyler Baicar <[email protected]>
  • Loading branch information
James Morse authored and tphan-ampere committed Apr 21, 2020
1 parent 4c66fd1 commit a90df19
Showing 1 changed file with 29 additions and 11 deletions.
40 changes: 29 additions & 11 deletions drivers/acpi/apei/ghes.c
Original file line number Diff line number Diff line change
Expand Up @@ -317,12 +317,12 @@ int __ghes_check_estatus(struct ghes *ghes,
return 0;
}

static int ghes_read_estatus(struct ghes *ghes,
struct acpi_hest_generic_status *estatus,
u64 *buf_paddr, enum fixed_addresses fixmap_idx)
/* Read the CPER block, returning its address, and header in estatus. */
static int __ghes_peek_estatus(struct ghes *ghes,
struct acpi_hest_generic_status *estatus,
u64 *buf_paddr, enum fixed_addresses fixmap_idx)
{
struct acpi_hest_generic *g = ghes->generic;
u32 len;
int rc;

rc = apei_read(buf_paddr, &g->error_status_address);
Expand All @@ -343,14 +343,14 @@ static int ghes_read_estatus(struct ghes *ghes,
return -ENOENT;
}

rc = __ghes_check_estatus(ghes, estatus);
if (rc)
return rc;
return __ghes_check_estatus(ghes, estatus);
}

len = cper_estatus_len(estatus);
ghes_copy_tofrom_phys(estatus + 1,
*buf_paddr + sizeof(*estatus),
len - sizeof(*estatus), 1, fixmap_idx);
static int __ghes_read_estatus(struct acpi_hest_generic_status *estatus,
u64 buf_paddr, enum fixed_addresses fixmap_idx,
size_t buf_len)
{
ghes_copy_tofrom_phys(estatus, buf_paddr, buf_len, 1, fixmap_idx);
if (cper_estatus_check(estatus)) {
pr_warn_ratelimited(FW_WARN GHES_PFX
"Failed to read error status block!\n");
Expand All @@ -360,6 +360,24 @@ static int ghes_read_estatus(struct ghes *ghes,
return 0;
}

static int ghes_read_estatus(struct ghes *ghes,
struct acpi_hest_generic_status *estatus,
u64 *buf_paddr, enum fixed_addresses fixmap_idx)
{
int rc;

rc = __ghes_peek_estatus(ghes, estatus, buf_paddr, fixmap_idx);
if (rc)
return rc;

rc = __ghes_check_estatus(ghes, estatus);
if (rc)
return rc;

return __ghes_read_estatus(estatus, *buf_paddr, fixmap_idx,
cper_estatus_len(estatus));
}

static void ghes_clear_estatus(struct ghes *ghes,
struct acpi_hest_generic_status *estatus,
u64 buf_paddr, enum fixed_addresses fixmap_idx)
Expand Down

0 comments on commit a90df19

Please sign in to comment.