Provide a generic interface for error injection via GHESv2. This patch is co-authored: - original ghes logic to inject a simple ARM record by Shiju Jose; - generic logic to handle block addresses by Jonathan Cameron; - generic GHESv2 error inject by Mauro Carvalho Chehab;
Co-authored-by: Jonathan Cameron <jonathan.came...@huawei.com> Co-authored-by: Shiju Jose <shiju.j...@huawei.com> Co-authored-by: Mauro Carvalho Chehab <mchehab+hua...@kernel.org> Signed-off-by: Jonathan Cameron <jonathan.came...@huawei.com> Signed-off-by: Shiju Jose <shiju.j...@huawei.com> Signed-off-by: Mauro Carvalho Chehab <mchehab+hua...@kernel.org> --- hw/acpi/ghes.c | 57 +++++++++++++++++++++++++++++++++++++++++++++ hw/acpi/ghes_cper.c | 2 +- 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/hw/acpi/ghes.c b/hw/acpi/ghes.c index 7870f51e2a9e..a3ae710dcf81 100644 --- a/hw/acpi/ghes.c +++ b/hw/acpi/ghes.c @@ -500,6 +500,63 @@ int acpi_ghes_record_errors(enum AcpiGhesNotifyType notify, NotifierList acpi_generic_error_notifiers = NOTIFIER_LIST_INITIALIZER(error_device_notifiers); +void ghes_record_cper_errors(uint8_t *cper, size_t len, + enum AcpiGhesNotifyType notify, Error **errp) +{ + uint64_t cper_addr, read_ack_start_addr; + enum AcpiHestSourceId source; + AcpiGedState *acpi_ged_state; + AcpiGhesState *ags; + uint64_t read_ack; + + if (ghes_notify_to_source_id(notify, &source)) { + error_setg(errp, + "GHES: Invalid error block/ack address(es) for notify %d", + notify); + return; + } + + acpi_ged_state = ACPI_GED(object_resolve_path_type("", TYPE_ACPI_GED, + NULL)); + g_assert(acpi_ged_state); + ags = &acpi_ged_state->ghes_state; + + cper_addr = le64_to_cpu(ags->ghes_addr_le); + cper_addr += ACPI_HEST_SRC_ID_COUNT * sizeof(uint64_t); + read_ack_start_addr = cper_addr + source * sizeof(uint64_t); + + cper_addr += ACPI_HEST_SRC_ID_COUNT * sizeof(uint64_t); + cper_addr += source * ACPI_GHES_MAX_RAW_DATA_LENGTH; + + cpu_physical_memory_read(read_ack_start_addr, + &read_ack, sizeof(uint64_t)); + + /* zero means OSPM does not acknowledge the error */ + if (!read_ack) { + error_setg(errp, + "Last CPER record was not acknowledged yet"); + read_ack = 1; + cpu_physical_memory_write(read_ack_start_addr, + &read_ack, sizeof(uint64_t)); + return; + } + + read_ack = cpu_to_le64(0); + cpu_physical_memory_write(read_ack_start_addr, + &read_ack, sizeof(uint64_t)); + + /* Build CPER record */ + + if (len > ACPI_GHES_MAX_RAW_DATA_LENGTH) { + error_setg(errp, "GHES CPER record is too big: %ld", len); + } + + /* Write the generic error data entry into guest memory */ + cpu_physical_memory_write(cper_addr, cper, len); + + notifier_list_notify(&acpi_generic_error_notifiers, NULL); +} + bool acpi_ghes_present(void) { AcpiGedState *acpi_ged_state; diff --git a/hw/acpi/ghes_cper.c b/hw/acpi/ghes_cper.c index 92ca84d738de..2328dbff7012 100644 --- a/hw/acpi/ghes_cper.c +++ b/hw/acpi/ghes_cper.c @@ -29,5 +29,5 @@ void qmp_ghes_cper(const char *qmp_cper, return; } - /* TODO: call a function at ghes */ + ghes_record_cper_errors(cper, len, ACPI_GHES_NOTIFY_GPIO, errp); } -- 2.46.0