From: Xiaofei Tan <tanxiaofei@huawei.com> driver inclusion category: feature bugzilla: https://atomgit.com/openeuler/kernel/issues/8787 ------------------------------------------ In the vendor specific error info of ARM Processor Error Section, Hisi defines a critical flag. When a CPU core consumes memory fault and a synchronization exception occurs. Set this flag if the memory fault is device-level fault, such as a remote memory link disconnection, where the CPU core may generate a large number of synchronization exceptions. OS can handle the error more efficient with this flag. Signed-off-by: Xiaofei Tan <tanxiaofei@huawei.com> --- drivers/acpi/apei/Kconfig | 9 +++ drivers/acpi/apei/Makefile | 1 + drivers/acpi/apei/apei-internal.h | 11 ++++ drivers/acpi/apei/ghes-vendor-info.c | 90 ++++++++++++++++++++++++++++ 4 files changed, 111 insertions(+) create mode 100644 drivers/acpi/apei/ghes-vendor-info.c diff --git a/drivers/acpi/apei/Kconfig b/drivers/acpi/apei/Kconfig index 5f34dd572829..cf799e7b68bf 100644 --- a/drivers/acpi/apei/Kconfig +++ b/drivers/acpi/apei/Kconfig @@ -34,6 +34,15 @@ config ACPI_APEI_GHES by firmware to produce more valuable hardware error information for Linux. +config ACPI_APEI_GHES_ARMP_VENDOR_INFO + bool "ARM processor vendor specific error info" + depends on ARM64 && ACPI_APEI_GHES + default n + help + Parse vendor specific error info of ARM processor error section, + for platform-related fault status to handle system failures. This + functionality requires support from both the chip and the firmware. + config ACPI_APEI_GHES_NOTIFY_ALL_RAS_ERR bool "Notify all ras err to driver" depends on ARM64 && ACPI_APEI_GHES diff --git a/drivers/acpi/apei/Makefile b/drivers/acpi/apei/Makefile index a2f54a554abd..10f22e6e4de3 100644 --- a/drivers/acpi/apei/Makefile +++ b/drivers/acpi/apei/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_ACPI_APEI) += apei.o obj-$(CONFIG_ACPI_APEI_GHES) += ghes.o +obj-$(CONFIG_ACPI_APEI_GHES_ARMP_VENDOR_INFO) += ghes-vendor-info.o obj-$(CONFIG_ACPI_APEI_EINJ) += einj.o obj-$(CONFIG_ACPI_APEI_ERST_DEBUG) += erst-dbg.o obj-$(CONFIG_ACPI_APEI_MEMORY_FAILURE) += ghes-policy.o diff --git a/drivers/acpi/apei/apei-internal.h b/drivers/acpi/apei/apei-internal.h index 472f023bb227..f5519153e32d 100644 --- a/drivers/acpi/apei/apei-internal.h +++ b/drivers/acpi/apei/apei-internal.h @@ -10,6 +10,7 @@ #include <linux/acpi.h> struct apei_exec_context; +struct cper_sec_proc_arm; typedef int (*apei_exec_ins_func_t)(struct apei_exec_context *ctx, struct acpi_whea_header *entry); @@ -138,4 +139,14 @@ static inline bool apei_page_should_offline(unsigned long pfn) return true; } #endif + +#ifdef CONFIG_ACPI_APEI_GHES_ARMP_VENDOR_INFO +bool ghes_armp_vendor_critical_error(struct cper_sec_proc_arm *err, bool sync); +#else +static inline bool +ghes_armp_vendor_critical_error(struct cper_sec_proc_arm *err, bool sync) +{ + return false; +} +#endif #endif diff --git a/drivers/acpi/apei/ghes-vendor-info.c b/drivers/acpi/apei/ghes-vendor-info.c new file mode 100644 index 000000000000..55db619638a2 --- /dev/null +++ b/drivers/acpi/apei/ghes-vendor-info.c @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Handle ARM processor vendor specific error info. + * Copyright (c) Huawei Technologies Co., Ltd. 2026. All rights reserved. + */ + +#include <linux/init.h> +#include <linux/acpi.h> +#include <acpi/ghes.h> +#include <acpi/apei.h> +#include "apei-internal.h" + +#define HISI_OEM BIT(0) + +static int vender_oem __ro_after_init; + +#ifdef CONFIG_ARCH_HISI + +#define HISI_VENDOR_MAGIC_NUM 0xCC08CC08CC08CC08 +#define HISI_VENDOR_CRITICAL_ERR BIT(0) + +struct hisi_armp_vendor_info { + u64 magic_num; + u32 ver_info; + u32 err_flag; /* bit0:critical error, others: reserved */ + u32 *regs; +} __packed; + +static bool ghes_hisi_critical_hw_error(struct cper_sec_proc_arm *err, bool sync) +{ + struct hisi_armp_vendor_info *vendor_info; + unsigned long err_info_sz; + char *p; + + if (!sync) + return false; + + if (!(err->validation_bits & CPER_ARM_VALID_VENDOR_INFO)) + return false; + + p = (char *)(err + 1); + err_info_sz = sizeof(struct cper_arm_err_info) * err->err_info_num; + if (!err->context_info_num) { + vendor_info = (struct hisi_armp_vendor_info *) + (p + err_info_sz); + } else { + struct cper_arm_ctx_info *ctx_info = (struct cper_arm_ctx_info *) + (p + err_info_sz); + + vendor_info = (struct hisi_armp_vendor_info *) + (p + err_info_sz + + ctx_info->size * err->context_info_num); + } + + if (vendor_info->magic_num != HISI_VENDOR_MAGIC_NUM) + return false; + + return (bool)(vendor_info->err_flag & HISI_VENDOR_CRITICAL_ERR); +} +#else +static inline bool ghes_hisi_critical_hw_error(struct cper_sec_proc_arm *err, bool sync) +{ + return false; +} +#endif + +bool ghes_armp_vendor_critical_error(struct cper_sec_proc_arm *err, bool sync) +{ + if (vender_oem & HISI_OEM) + return ghes_hisi_critical_hw_error(err, sync); + + return false; +} + +static int __init ghes_check_oem_table(void) +{ + struct acpi_table_header *tbl; + acpi_status status = AE_OK; + + status = acpi_get_table(ACPI_SIG_HEST, 0, &tbl); + if (ACPI_FAILURE(status) || !tbl) + return -ENODEV; + + if (!memcmp(tbl->oem_id, "HISI ", ACPI_OEM_ID_SIZE)) + vender_oem |= HISI_OEM; + + acpi_put_table(tbl); + return 0; +} +subsys_initcall(ghes_check_oem_table); -- 2.43.0