From patchwork Fri Aug 2 21:44:01 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mauro Carvalho Chehab X-Patchwork-Id: 13752046 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 14053C3DA7F for ; Fri, 2 Aug 2024 21:46:10 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sa04w-000579-Mm; Fri, 02 Aug 2024 17:44:50 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sa04j-0004PX-9E; Fri, 02 Aug 2024 17:44:37 -0400 Received: from dfw.source.kernel.org ([139.178.84.217]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sa04f-0001AS-TA; Fri, 02 Aug 2024 17:44:37 -0400 Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by dfw.source.kernel.org (Postfix) with ESMTP id 6DAC062B65; Fri, 2 Aug 2024 21:44:24 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id B696CC4AF0A; Fri, 2 Aug 2024 21:44:23 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1722635063; bh=tBLbaTxDMIbrJ1ZF80aRktOv/E8tCJykpKL5ilb5tVo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=RZ2d+f2ZdBQH+uBVTT71p5zOXnZ3E3BKViG9mwQBIVz8IZ8uV8i/4I6m7ROwF7BTl onKGwKUFPDKZ63VXS6oARY5bgE9J/zMh1kj/3LuGe+1I7vFLbQuyJR5tVveUMB3x9i L4sZ/VCqdzbe4nKHsRaICWn8VGj4YAVX4f1CeJ/5w9swq3ERDvWK33W1f29u4yPgrI HBc3vUk8j9Qiu0Fld8ZB8o+BHg3tTtM1Hoa4o+qL3J6gU7yRDHYicpfOG46EEfvuaJ GUq/Zymlh3EtZDbMV+EMZVDxdMtDAAtd5Mc4zfWV4SfRHNz2xci8C/NviIxAvuExRz aGgnj+k7dEAAA== Received: from mchehab by mail.kernel.org with local (Exim 4.98) (envelope-from ) id 1sa04T-00000002naX-3Ctt; Fri, 02 Aug 2024 23:44:21 +0200 From: Mauro Carvalho Chehab To: Cc: Jonathan Cameron , Shiju Jose , Mauro Carvalho Chehab , "Michael S. Tsirkin" , Ani Sinha , Dongjiu Geng , Igor Mammedov , linux-kernel@vger.kernel.org, qemu-arm@nongnu.org, qemu-devel@nongnu.org Subject: [PATCH v5 6/7] acpi/ghes: add support for generic error injection via QAPI Date: Fri, 2 Aug 2024 23:44:01 +0200 Message-ID: <20c491e357340e0062b6ff09867c1661ed4d2479.1722634602.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: MIME-Version: 1.0 Received-SPF: pass client-ip=139.178.84.217; envelope-from=mchehab+huawei@kernel.org; helo=dfw.source.kernel.org X-Spam_score_int: -71 X-Spam_score: -7.2 X-Spam_bar: ------- X-Spam_report: (-7.2 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.124, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_HI=-5, RCVD_IN_VALIDITY_RPBL_BLOCKED=0.001, RCVD_IN_VALIDITY_SAFE_BLOCKED=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org 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 Co-authored-by: Shiju Jose Co-authored-by: Mauro Carvalho Chehab Cc: Jonathan Cameron Cc: Shiju Jose Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Jonathan Cameron Signed-off-by: Shiju Jose --- hw/acpi/ghes.c | 159 ++++++++++++++++++++++++++++++++++++++--- hw/acpi/ghes_cper.c | 2 +- include/hw/acpi/ghes.h | 3 + 3 files changed, 152 insertions(+), 12 deletions(-) diff --git a/hw/acpi/ghes.c b/hw/acpi/ghes.c index a745dcc7be5e..e125c9475773 100644 --- a/hw/acpi/ghes.c +++ b/hw/acpi/ghes.c @@ -395,23 +395,22 @@ void acpi_ghes_add_fw_cfg(AcpiGhesState *ags, FWCfgState *s, ags->present = true; } +static uint64_t ghes_get_state_start_address(void) +{ + AcpiGedState *acpi_ged_state = + ACPI_GED(object_resolve_path_type("", TYPE_ACPI_GED, NULL)); + AcpiGhesState *ags = &acpi_ged_state->ghes_state; + + return le64_to_cpu(ags->ghes_addr_le); +} + int acpi_ghes_record_errors(uint8_t source_id, uint64_t physical_address) { uint64_t error_block_addr, read_ack_register_addr, read_ack_register = 0; - uint64_t start_addr; + uint64_t start_addr = ghes_get_state_start_address(); bool ret = -1; - AcpiGedState *acpi_ged_state; - AcpiGhesState *ags; - assert(source_id < ACPI_HEST_SRC_ID_RESERVED); - acpi_ged_state = ACPI_GED(object_resolve_path_type("", TYPE_ACPI_GED, - NULL)); - g_assert(acpi_ged_state); - ags = &acpi_ged_state->ghes_state; - - start_addr = le64_to_cpu(ags->ghes_addr_le); - if (physical_address) { start_addr += source_id * sizeof(uint64_t); @@ -448,9 +447,147 @@ int acpi_ghes_record_errors(uint8_t source_id, uint64_t physical_address) return ret; } +/* + * Error register block data layout + * + * | +---------------------+ ges.ghes_addr_le + * | |error_block_address0 | + * | +---------------------+ + * | |error_block_address1 | + * | +---------------------+ --+-- + * | | ............. | GHES_ADDRESS_SIZE + * | +---------------------+ --+-- + * | |error_block_addressN | + * | +---------------------+ + * | | read_ack0 | + * | +---------------------+ --+-- + * | | read_ack1 | GHES_ADDRESS_SIZE + * | +---------------------+ --+-- + * | | ............. | + * | +---------------------+ + * | | read_ackN | + * | +---------------------+ --+-- + * | | CPER | | + * | | .... | GHES_MAX_RAW_DATA_LENGT + * | | CPER | | + * | +---------------------+ --+-- + * | | .......... | + * | +---------------------+ + * | | CPER | + * | | .... | + * | | CPER | + * | +---------------------+ + */ + +/* Map from uint32_t notify to entry offset in GHES */ +static const uint8_t error_source_to_index[] = { 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 1, 0}; + +static bool ghes_get_addr(uint32_t notify, uint64_t *error_block_addr, + uint64_t *read_ack_addr) +{ + uint64_t base; + + if (notify >= ACPI_GHES_NOTIFY_RESERVED) { + return false; + } + + /* Find and check the source id for this new CPER */ + if (error_source_to_index[notify] == 0xff) { + return false; + } + + base = ghes_get_state_start_address(); + + *read_ack_addr = base + + ACPI_GHES_ERROR_SOURCE_COUNT * sizeof(uint64_t) + + error_source_to_index[notify] * sizeof(uint64_t); + + /* Could also be read back from the error_block_address register */ + *error_block_addr = base + + ACPI_GHES_ERROR_SOURCE_COUNT * sizeof(uint64_t) + + ACPI_GHES_ERROR_SOURCE_COUNT * sizeof(uint64_t) + + error_source_to_index[notify] * ACPI_GHES_MAX_RAW_DATA_LENGTH; + + return true; +} + NotifierList generic_error_notifiers = NOTIFIER_LIST_INITIALIZER(error_device_notifiers); +void ghes_record_cper_errors(AcpiGhesCper *cper, Error **errp, + uint32_t notify) +{ + int read_ack = 0; + uint32_t i; + uint64_t read_ack_addr = 0; + uint64_t error_block_addr = 0; + uint32_t data_length; + GArray *block; + + if (!ghes_get_addr(notify, &error_block_addr, &read_ack_addr)) { + error_setg(errp, "GHES: Invalid error block/ack address(es)"); + return; + } + + cpu_physical_memory_read(read_ack_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_addr, + &read_ack, sizeof(uint64_t)); + return; + } + + read_ack = cpu_to_le64(0); + cpu_physical_memory_write(read_ack_addr, + &read_ack, sizeof(uint64_t)); + + /* Build CPER record */ + + /* + * Invalid fru id: ACPI 4.0: 17.3.2.6.1 Generic Error Data, + * Table 17-13 Generic Error Data Entry + */ + QemuUUID fru_id = {}; + + block = g_array_new(false, true /* clear */, 1); + data_length = ACPI_GHES_DATA_LENGTH + cper->data_len; + + /* + * It should not run out of the preallocated memory if + * adding a new generic error data entry + */ + assert((data_length + ACPI_GHES_GESB_SIZE) <= + ACPI_GHES_MAX_RAW_DATA_LENGTH); + + /* Build the new generic error status block header */ + acpi_ghes_generic_error_status(block, ACPI_GEBS_UNCORRECTABLE, + 0, 0, data_length, + ACPI_CPER_SEV_RECOVERABLE); + + /* Build this new generic error data entry header */ + acpi_ghes_generic_error_data(block, cper->guid, + ACPI_CPER_SEV_RECOVERABLE, 0, 0, + cper->data_len, fru_id, 0); + + /* Add CPER data */ + for (i = 0; i < cper->data_len; i++) { + build_append_int_noprefix(block, cper->data[i], 1); + } + + /* Write the generic error data entry into guest memory */ + cpu_physical_memory_write(error_block_addr, block->data, block->len); + + g_array_free(block, true); + + notifier_list_notify(&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 7aa7e71e90dc..d7ff7debee74 100644 --- a/hw/acpi/ghes_cper.c +++ b/hw/acpi/ghes_cper.c @@ -39,7 +39,7 @@ void qmp_ghes_cper(CommonPlatformErrorRecord *qmp_cper, return; } - /* TODO: call a function at ghes */ + ghes_record_cper_errors(&cper, errp, ACPI_GHES_NOTIFY_GPIO); g_free(cper.data); } diff --git a/include/hw/acpi/ghes.h b/include/hw/acpi/ghes.h index 06a5b8820cd5..ee6f6cd96911 100644 --- a/include/hw/acpi/ghes.h +++ b/include/hw/acpi/ghes.h @@ -85,6 +85,9 @@ typedef struct AcpiGhesCper { size_t data_len; } AcpiGhesCper; +void ghes_record_cper_errors(AcpiGhesCper *cper, Error **errp, + uint32_t notify); + /** * acpi_ghes_present: Report whether ACPI GHES table is present *