From: Zhang Jian zhangjian210@huawei.com
ascend inclusion category: feature bugzilla: NA CVE: NA
-------------------------------------------------
RAS Function only support by acpi, in some scenarios no use acpi.The features add support by dts, apei table can passed and parsed by dts mode
Signed-off-by: Zhang Jian zhangjian210@huawei.com Signed-off-by: Zhang Zekun zhangzekun11@huawei.com Reviewed-by: Weilong Chen chenweilong@huawei.com --- drivers/acpi/Kconfig | 11 ++++ drivers/acpi/Makefile | 1 + drivers/acpi/apei/hest.c | 35 ++++++++++ drivers/acpi/dt_apei.c | 136 +++++++++++++++++++++++++++++++++++++++ include/acpi/apei.h | 7 ++ 5 files changed, 190 insertions(+) create mode 100644 drivers/acpi/dt_apei.c
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index b9753969b0db..4f69768a6a91 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -538,3 +538,14 @@ config X86_PM_TIMER
You should nearly always say Y here because many modern systems require this timer. + +config ACPI_DT_APEI + bool "APEI support for DTS" + depends on ACPI + default n + help + Select this option to enable support for DTS, parameters in the + APEI table are transmitted through by DTS. + + If the RAS function is required but the firmware does not support + the ACPI function, the DTS can be used for transmission. diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 4466156474ee..c463e1fa3551 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -98,6 +98,7 @@ obj-$(CONFIG_ACPI_CPPC_LIB) += cppc_acpi.o obj-$(CONFIG_ACPI_SPCR_TABLE) += spcr.o obj-$(CONFIG_ACPI_DEBUGGER_USER) += acpi_dbg.o obj-$(CONFIG_ACPI_PPTT) += pptt.o +obj-$(CONFIG_ACPI_DT_APEI) += dt_apei.o
# processor has its own "processor." module_param namespace processor-y := processor_driver.o diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c index 7bf48c2776fb..5b336200d133 100644 --- a/drivers/acpi/apei/hest.c +++ b/drivers/acpi/apei/hest.c @@ -268,3 +268,38 @@ void __init acpi_hest_init(void) hest_disable = HEST_DISABLED; acpi_put_table((struct acpi_table_header *)hest_tab); } + +#ifdef CONFIG_ACPI_DT_APEI +void __init acpi_dt_hest_init(struct acpi_table_hest *table_hest) +{ + int rc = -ENODEV; + unsigned int ghes_count = 0; + + if (table_hest == NULL) { + pr_err(HEST_PFX "Failed to get hest table\n"); + return; + } + + hest_tab = table_hest; + hest_disable = HEST_ENABLED; + + rc = apei_hest_parse(hest_parse_cmc, NULL); + if (rc) + goto err; + + if (!ghes_disable) { + rc = apei_hest_parse(hest_parse_ghes_count, &ghes_count); + if (rc) + goto err; + rc = hest_ghes_dev_register(ghes_count); + if (rc) + goto err; + } + + pr_info(HEST_PFX "Table parsing has been initialized.\n"); + return; +err: + pr_info(HEST_PFX "Hest init fail.\n"); + hest_disable = HEST_DISABLED; +} +#endif diff --git a/drivers/acpi/dt_apei.c b/drivers/acpi/dt_apei.c new file mode 100644 index 000000000000..bec3c1cc4d00 --- /dev/null +++ b/drivers/acpi/dt_apei.c @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * dt_apei kernel module + * Copyright (c) 2020, Hisilicon Ltd. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation.* + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/acpi.h> +#include <linux/platform_device.h> +#include <linux/device.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <acpi/apei.h> + +struct apei_table_params { + acpi_physical_address phys; + acpi_size size; +}; + +static void dt_apei_print_table_header(struct acpi_table_header *header) +{ + pr_info("%-4.4s %06X (v%.2d %-6.6s %-8.8s %08X %-4.4s %08X)", + header->signature, header->length, header->revision, + header->oem_id, header->oem_table_id, header->oem_revision, + header->asl_compiler_id, header->asl_compiler_revision); +} + +static acpi_size dt_apei_get_table_size(struct apei_table_params *table_params, + char *signature) +{ + struct acpi_table_header *header = NULL; + acpi_size size = 0; + + if (table_params->size < sizeof(struct acpi_table_header)) + return -ENOMEM; + + /* Map the hest table header, and extract the hest length */ + header = acpi_os_map_memory(table_params->phys, + sizeof(struct acpi_table_header)); + if (!header) { + pr_err("%s: map hest table fail\n", __func__); + return -ENOMEM; + } + + dt_apei_print_table_header(header); + if (strncmp(header->signature, signature, + sizeof(header->signature)) == 0) + size = header->length; + + acpi_os_unmap_memory(header, sizeof(struct acpi_table_header)); + + return size; +} + +static int __init dt_apei_parse_hest(struct apei_table_params *table_params) +{ + struct acpi_table_hest *table_hest = NULL; + acpi_size table_size; + + table_size = dt_apei_get_table_size(table_params, ACPI_SIG_HEST); + if ((table_size > table_params->phys) || (table_size <= 0)) + return -ENOMEM; + + /* Map the hest table, for exttract hest table */ + table_hest = acpi_os_map_memory(table_params->phys, table_size); + if (!table_hest) { + pr_err("%s: map hest table fail\n", __func__); + return -ENOMEM; + } + + acpi_dt_hest_init(table_hest); + return 0; +} + +static int dt_apei_parse_dtb(struct device_node *np, + struct apei_table_params *table_params) +{ + int rc; + struct resource res; + resource_size_t res_size; + + rc = of_address_to_resource(np, 0, &res); + if (rc) { + pr_err("%s: read resource address failed\n", __func__); + return -ENODEV; + } + res_size = resource_size(&res); + table_params->phys = (acpi_physical_address)res.start; + table_params->size = (acpi_size)(uintptr_t)res_size; + + return 0; +} + +static int __init do_dt_apei_init(void) +{ + int rc; + struct device_node *np; + struct apei_table_params table_params; + + np = of_find_compatible_node(NULL, NULL, "dt_apei, hest"); + if (np == NULL) { + pr_err("%s:apei hest table not exist\n", __func__); + return -ENODEV; + } + + rc = dt_apei_parse_dtb(np, &table_params); + if (rc != 0) + return rc; + + /* acpi permanent mmap has been set in acpi map table */ + acpi_permanent_mmap = true; + + rc = dt_apei_parse_hest(&table_params); + if (rc != 0) + return rc; + + pr_info("%s: dt apei probe success\n", __func__); + return 0; +} + +static int __init dt_apei_init(void) +{ + return do_dt_apei_init(); +} + +subsys_initcall(dt_apei_init); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("XiaoXun Huang huangxiaoxun@huawei.com"); +MODULE_DESCRIPTION("HISI DT APEI DRIVER"); diff --git a/include/acpi/apei.h b/include/acpi/apei.h index 680f80960c3d..324013d22d09 100644 --- a/include/acpi/apei.h +++ b/include/acpi/apei.h @@ -37,6 +37,13 @@ void __init acpi_hest_init(void); static inline void acpi_hest_init(void) { return; } #endif
+#ifdef CONFIG_ACPI_DT_APEI +void acpi_dt_hest_init(struct acpi_table_hest *table_hest); +#else +static inline void acpi_dt_hest_init(struct acpi_table_hest *table_hest) +{ return; } +#endif + typedef int (*apei_hest_func_t)(struct acpi_hest_header *hest_hdr, void *data); int apei_hest_parse(apei_hest_func_t func, void *data);