diff --git a/src/acpi/Kconfig b/src/acpi/Kconfig index 2bb56ba91d..0d3730baa1 100644 --- a/src/acpi/Kconfig +++ b/src/acpi/Kconfig @@ -127,3 +127,16 @@ config ACPI_WDAT_WDT help Selected by platforms that support and fill ACPI Watchdog Action Table (WDAT). + +config ACPI_HEST + bool + depends on HAVE_ACPI_TABLES + help + Selected by platforms that support and fill ACPI Hardware Error Source Table (HEST) + +config ACPI_HEST_ERROR_LOG_BUFFER_SIZE + hex + default 0x4000 + depends on ACPI_HEST + help + Define the size of the HEST ACPI error log buffer diff --git a/src/acpi/acpi.c b/src/acpi/acpi.c index 07e84f6d39..7dad21f12d 100644 --- a/src/acpi/acpi.c +++ b/src/acpi/acpi.c @@ -14,6 +14,8 @@ */ #include +#include +#include #include #include #include @@ -1062,20 +1064,32 @@ unsigned long acpi_create_hest_error_source(acpi_hest_t *hest, } /* ACPI 4.0 */ -void acpi_write_hest(acpi_hest_t *hest, - unsigned long (*acpi_fill_hest)(acpi_hest_t *hest)) +static void acpi_create_hest(acpi_header_t *header, void *unused) { - acpi_header_t *header = &(hest->header); + if (!CONFIG(ACPI_HEST)) + return; + + /* Reserve memory for Enhanced error logging */ + void *log_mem = cbmem_add(CBMEM_ID_ACPI_HEST, CONFIG_ACPI_HEST_ERROR_LOG_BUFFER_SIZE); + if (!log_mem) { + printk(BIOS_ERR, "Unable to allocate HEST memory\n"); + return; + } + printk(BIOS_DEBUG, "HEST elog_addr: %p, size:%d\n", log_mem, + CONFIG_ACPI_HEST_ERROR_LOG_BUFFER_SIZE); + + acpi_hest_t *hest = (acpi_hest_t *)header; + uintptr_t current = (uintptr_t)(hest + 1); memset(hest, 0, sizeof(acpi_hest_t)); if (acpi_fill_header(header, "HEST", HEST, sizeof(acpi_hest_t)) != CB_SUCCESS) return; - acpi_fill_hest(hest); + current = acpi_soc_fill_hest(hest, current, log_mem); - /* Calculate checksums. */ - header->checksum = acpi_checksum((void *)hest, header->length); + /* (Re)calculate length. */ + header->length = current - (uintptr_t)hest; } /* ACPI 3.0b */ @@ -1456,6 +1470,7 @@ unsigned long write_acpi_tables(const unsigned long start) { acpi_create_tpm2, NULL, sizeof(acpi_tpm2_t) }, { acpi_create_lpit, NULL, sizeof(acpi_lpit_t) }, { acpi_create_madt, NULL, sizeof(acpi_header_t) }, + { acpi_create_hest, NULL, sizeof(acpi_hest_t) }, { acpi_create_bert, NULL, sizeof(acpi_bert_t) }, { acpi_create_spcr, NULL, sizeof(acpi_spcr_t) }, { acpi_create_gtdt, NULL, sizeof(acpi_gtdt_t) }, diff --git a/src/include/acpi/acpi.h b/src/include/acpi/acpi.h index 06dba65738..1acdd7f7e7 100644 --- a/src/include/acpi/acpi.h +++ b/src/include/acpi/acpi.h @@ -1879,11 +1879,9 @@ unsigned long acpi_create_dmar_ds_ioapic_from_hw(unsigned long current, unsigned long acpi_create_dmar_ds_msi_hpet(unsigned long current, u8 enumeration_id, u8 bus, u8 dev, u8 fn); -void acpi_write_hest(acpi_hest_t *hest, - unsigned long (*acpi_fill_hest)(acpi_hest_t *hest)); -unsigned long acpi_create_hest_error_source(acpi_hest_t *hest, - acpi_hest_esd_t *esd, u16 type, void *data, u16 len); +unsigned long acpi_create_hest_error_source(acpi_hest_t *hest, acpi_hest_esd_t *esd, u16 type, + void *data, u16 len); unsigned long acpi_create_lpi_desc_ncst(acpi_lpi_desc_ncst_t *lpi_desc, uint16_t uid); diff --git a/src/include/acpi/acpi_apei.h b/src/include/acpi/acpi_apei.h new file mode 100644 index 0000000000..b2edc2dea3 --- /dev/null +++ b/src/include/acpi/acpi_apei.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +/* + * Contains ACPI Platform Error Interfaces (APEI) definitions and declarations. + * These are mostly used by: + * - BERT (Boot Error Record Table) ACPI Table. + * - HEST (Hardware Error Source Table) ACPI Table. + */ + +#ifndef _ACPI_APEI_H_ +#define _ACPI_APEI_H_ + +#include + +/* Generic Hardware Error Source Descriptor */ +typedef struct acpi_ghes_esd { + u16 type; + u16 source_id; + u16 related_src_id; + u8 flags; + u8 enabled; + u32 prealloc_erecords; + u32 max_section_per_record; +} __packed acpi_ghes_esd_t; + +typedef struct ghes_record { + acpi_ghes_esd_t esd; + u32 max_raw_data_length; + acpi_addr64_t sts_addr; + acpi_hest_hen_t notify; + u32 err_sts_blk_len; +} __packed ghes_record_t; + +uintptr_t acpi_soc_fill_hest(acpi_hest_t *hest, uintptr_t current, void *log_mem); + +#endif diff --git a/src/northbridge/amd/pi/00730F01/Kconfig b/src/northbridge/amd/pi/00730F01/Kconfig index 3c2829efe7..76a0aa3260 100644 --- a/src/northbridge/amd/pi/00730F01/Kconfig +++ b/src/northbridge/amd/pi/00730F01/Kconfig @@ -3,6 +3,7 @@ config NORTHBRIDGE_AMD_PI_00730F01 bool select DRAM_SUPPORT_DDR3 + select ACPI_HEST if NORTHBRIDGE_AMD_PI_00730F01 diff --git a/src/northbridge/amd/pi/00730F01/northbridge.c b/src/northbridge/amd/pi/00730F01/northbridge.c index 826c19e862..c3914516bb 100644 --- a/src/northbridge/amd/pi/00730F01/northbridge.c +++ b/src/northbridge/amd/pi/00730F01/northbridge.c @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ +#include #include #include #include @@ -91,22 +92,19 @@ static void northbridge_init(struct device *dev) register_new_ioapic(IO_APIC2_ADDR); } -static unsigned long acpi_fill_hest(acpi_hest_t *hest) +uintptr_t acpi_soc_fill_hest(acpi_hest_t *hest, uintptr_t current, void *log_mem) { - void *addr, *current; - - /* Skip the HEST header. */ - current = (void *)(hest + 1); + void *addr; addr = agesawrapper_getlateinitptr(PICK_WHEA_MCE); if (addr != NULL) - current += acpi_create_hest_error_source(hest, current, 0, (void *)((u32)addr + 2), *(UINT16 *)addr - 2); + current += acpi_create_hest_error_source(hest, (acpi_hest_esd_t *)current, 0, (void *)((u32)addr + 2), *(UINT16 *)addr - 2); addr = agesawrapper_getlateinitptr(PICK_WHEA_CMC); if (addr != NULL) - current += acpi_create_hest_error_source(hest, current, 1, (void *)((u32)addr + 2), *(UINT16 *)addr - 2); + current += acpi_create_hest_error_source(hest, (acpi_hest_esd_t *)current, 1, (void *)((u32)addr + 2), *(UINT16 *)addr - 2); - return (unsigned long)current; + return current; } static unsigned long acpi_fill_ivrs_ioapic(acpi_ivrs_t *ivrs, unsigned long current) @@ -430,12 +428,6 @@ static unsigned long agesa_write_acpi_tables(const struct device *device, acpi_header_t *alib; acpi_ivrs_t *ivrs; - /* HEST */ - current = ALIGN_UP(current, 8); - acpi_write_hest((void *)current, acpi_fill_hest); - acpi_add_table(rsdp, (void *)current); - current += ((acpi_header_t *)current)->length; - /* IVRS */ if (is_dev_enabled(DEV_PTR(iommu))) { current = ALIGN_UP(current, 8); diff --git a/src/soc/amd/stoneyridge/Kconfig b/src/soc/amd/stoneyridge/Kconfig index 2abd9d7985..1d236363a6 100644 --- a/src/soc/amd/stoneyridge/Kconfig +++ b/src/soc/amd/stoneyridge/Kconfig @@ -3,6 +3,7 @@ config SOC_AMD_STONEYRIDGE bool select ACPI_SOC_NVS + select ACPI_HEST select ARCH_X86 select BOOT_DEVICE_SUPPORTS_WRITES if BOOT_DEVICE_SPI_FLASH select COLLECT_TIMESTAMPS_NO_TSC diff --git a/src/soc/amd/stoneyridge/northbridge.c b/src/soc/amd/stoneyridge/northbridge.c index b6ebf4db4b..e8c3110c0e 100644 --- a/src/soc/amd/stoneyridge/northbridge.c +++ b/src/soc/amd/stoneyridge/northbridge.c @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ +#include #include #include #include @@ -102,24 +103,21 @@ static void acpi_fill_root_complex_tom(const struct device *device) acpigen_pop_len(); } -static unsigned long acpi_fill_hest(acpi_hest_t *hest) +uintptr_t acpi_soc_fill_hest(acpi_hest_t *hest, uintptr_t current, void *log_mem) { - void *addr, *current; - - /* Skip the HEST header. */ - current = (void *)(hest + 1); + void *addr; addr = agesawrapper_getlateinitptr(PICK_WHEA_MCE); if (addr != NULL) - current += acpi_create_hest_error_source(hest, current, 0, + current += acpi_create_hest_error_source(hest, (acpi_hest_esd_t *)current, 0, (void *)((u32)addr + 2), *(uint16_t *)addr - 2); addr = agesawrapper_getlateinitptr(PICK_WHEA_CMC); if (addr != NULL) - current += acpi_create_hest_error_source(hest, current, 1, + current += acpi_create_hest_error_source(hest, (acpi_hest_esd_t *)current, 1, (void *)((u32)addr + 2), *(uint16_t *)addr - 2); - return (unsigned long)current; + return current; } unsigned long soc_acpi_write_tables(const struct device *device, unsigned long current, @@ -129,14 +127,6 @@ unsigned long soc_acpi_write_tables(const struct device *device, unsigned long c acpi_slit_t *slit; acpi_header_t *alib; acpi_header_t *ivrs; - acpi_hest_t *hest; - - /* HEST */ - current = acpi_align_current(current); - hest = (acpi_hest_t *)current; - acpi_write_hest(hest, acpi_fill_hest); - acpi_add_table(rsdp, (void *)current); - current += hest->header.length; current = acpi_align_current(current); printk(BIOS_DEBUG, "ACPI: * IVRS at %lx\n", current); diff --git a/src/soc/intel/xeon_sp/Kconfig b/src/soc/intel/xeon_sp/Kconfig index 24923a5a29..eed04fbc62 100644 --- a/src/soc/intel/xeon_sp/Kconfig +++ b/src/soc/intel/xeon_sp/Kconfig @@ -108,8 +108,7 @@ config HPET_MIN_TICKS config SOC_INTEL_XEON_RAS bool - select SOC_ACPI_HEST - select SOC_RAS_ELOG + select ACPI_HEST config HAVE_IOAT_DOMAINS bool diff --git a/src/soc/intel/xeon_sp/include/soc/hest.h b/src/soc/intel/xeon_sp/include/soc/hest.h deleted file mode 100644 index ad79d45fdf..0000000000 --- a/src/soc/intel/xeon_sp/include/soc/hest.h +++ /dev/null @@ -1,40 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -#ifndef _HEST_H_ -#define _HEST_H_ -#include - -#define MCE_ERR_POLL_MS_INTERVAL 1000 -#define HEST_PCIE_RP_AER_DESC_TYPE 6 -#define HEST_GHES_DESC_TYPE 9 -#define GHES_MAX_RAW_DATA_LENGTH (((CONFIG_ERROR_LOG_BUFFER_SIZE) >> 1) - 8) -#define GHEST_ERROR_STATUS_BLOCK_LENGTH ((CONFIG_ERROR_LOG_BUFFER_SIZE) >> 1) -#define GHEST_ASSIST (1 << 2) -#define FIRMWARE_FIRST (1 << 0) -#define MEM_VALID_BITS 0x66ff -#define PCIE_VALID_BITS 0xef -#define QWORD_ACCESS 4 -#define NOTIFY_TYPE_SCI 3 - -/* Generic Error Source Descriptor */ -typedef struct acpi_ghes_esd { - u16 type; - u16 source_id; - u16 related_src_id; - u8 flags; - u8 enabled; - u32 prealloc_erecords; - u32 max_section_per_record; -} __packed acpi_ghes_esd_t; - -typedef struct ghes_record { - acpi_ghes_esd_t esd; - u32 max_raw_data_length; - acpi_addr64_t sts_addr; - acpi_hest_hen_t notify; - u32 err_sts_blk_len; -} __packed ghes_record_t; - -unsigned long hest_create(unsigned long current, struct acpi_rsdp *rsdp); - -#endif diff --git a/src/soc/intel/xeon_sp/ras/Kconfig b/src/soc/intel/xeon_sp/ras/Kconfig deleted file mode 100644 index 79c599c2fb..0000000000 --- a/src/soc/intel/xeon_sp/ras/Kconfig +++ /dev/null @@ -1,20 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-or-later - -config SOC_ACPI_HEST - def_bool n - depends on HAVE_ACPI_TABLES - help - This variable provides control for ACPI hardware error source table (HEST) - -config SOC_RAS_ELOG - def_bool n - depends on SOC_ACPI_HEST - help - This variable provides enhanced error logging support used with HEST - -config ERROR_LOG_BUFFER_SIZE - hex - default 0x4000 - depends on SOC_RAS_ELOG - help - This variable allows a configurable error log based on system requirements diff --git a/src/soc/intel/xeon_sp/ras/Makefile.mk b/src/soc/intel/xeon_sp/ras/Makefile.mk index 93c8705f94..a4c2923eb2 100644 --- a/src/soc/intel/xeon_sp/ras/Makefile.mk +++ b/src/soc/intel/xeon_sp/ras/Makefile.mk @@ -1,3 +1,3 @@ ## SPDX-License-Identifier: GPL-2.0-or-later -ramstage-$(CONFIG_SOC_ACPI_HEST) += hest.c +ramstage-$(CONFIG_ACPI_HEST) += hest.c diff --git a/src/soc/intel/xeon_sp/ras/hest.c b/src/soc/intel/xeon_sp/ras/hest.c index 2da720a744..eb46b00dad 100644 --- a/src/soc/intel/xeon_sp/ras/hest.c +++ b/src/soc/intel/xeon_sp/ras/hest.c @@ -1,29 +1,25 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -#include +#include #include #include #include -#include #include +#include -static u64 hest_get_elog_addr(void) -{ - /* The elog address comes from reserved memory */ - struct global_nvs *gnvs; - gnvs = acpi_get_gnvs(); - if (!gnvs) { - printk(BIOS_ERR, "Unable to get gnvs\n"); - return 0; - } +#define MCE_ERR_POLL_MS_INTERVAL 1000 +#define HEST_PCIE_RP_AER_DESC_TYPE 6 +#define HEST_GHES_DESC_TYPE 9 +#define GHES_MAX_RAW_DATA_LENGTH (((CONFIG_ACPI_HEST_ERROR_LOG_BUFFER_SIZE) >> 1) - 8) +#define GHEST_ERROR_STATUS_BLOCK_LENGTH ((CONFIG_ACPI_HEST_ERROR_LOG_BUFFER_SIZE) >> 1) +#define GHEST_ASSIST (1 << 2) +#define FIRMWARE_FIRST (1 << 0) +#define MEM_VALID_BITS 0x66ff +#define PCIE_VALID_BITS 0xef +#define QWORD_ACCESS 4 +#define NOTIFY_TYPE_SCI 3 - /* Runtime logging address */ - printk(BIOS_DEBUG, "\t status blk start addr = %llx\n", gnvs->hest_log_addr); - printk(BIOS_DEBUG, "\t size = %x\n", CONFIG_ERROR_LOG_BUFFER_SIZE); - return gnvs->hest_log_addr; -} - -static u32 acpi_hest_add_ghes(void *current) +static u32 acpi_hest_add_ghes(uintptr_t current, uintptr_t log_mem) { ghes_record_t *rec = (ghes_record_t *)current; u32 size = sizeof(ghes_record_t); @@ -50,51 +46,22 @@ static u32 acpi_hest_add_ghes(void *current) rec->err_sts_blk_len = GHEST_ERROR_STATUS_BLOCK_LENGTH; /* error status block entries start address */ - if (CONFIG(SOC_ACPI_HEST)) - rec->sts_addr.addr = hest_get_elog_addr(); + rec->sts_addr.addr = log_mem; return size; } -static unsigned long acpi_fill_hest(acpi_hest_t *hest) +uintptr_t acpi_soc_fill_hest(acpi_hest_t *hest, uintptr_t current, void *log_mem) { - acpi_header_t *header = &(hest->header); - void *current; - current = (void *)(hest); - void *next = current; - next = hest + 1; - next += acpi_hest_add_ghes(next); + // fill ACPI global non volatile storage with hest elog addr + struct global_nvs *gnvs = acpi_get_gnvs(); + if (gnvs) + gnvs->hest_log_addr = (uintptr_t)log_mem; + else + printk(BIOS_ERR, "ACPI fill HEST: Unable to get gnvs\n"); + + current = acpi_hest_add_ghes(current, (uintptr_t)log_mem); // add first entry hest->error_source_count += 1; - header->length = next - current; - return header->length; -} -unsigned long hest_create(unsigned long current, struct acpi_rsdp *rsdp) -{ - struct global_nvs *gnvs; - acpi_hest_t *hest; - - /* Reserve memory for Enhanced error logging */ - void *mem = cbmem_add(CBMEM_ID_ACPI_HEST, CONFIG_ERROR_LOG_BUFFER_SIZE); - if (!mem) { - printk(BIOS_ERR, "Unable to allocate HEST memory\n"); - return current; - } - - printk(BIOS_DEBUG, "HEST memory created: %p\n", mem); - gnvs = acpi_get_gnvs(); - if (!gnvs) { - printk(BIOS_ERR, "Unable to get gnvs\n"); - return current; - } - gnvs->hest_log_addr = (uintptr_t)mem; - printk(BIOS_DEBUG, "elog_addr: %llx, size:%x\n", gnvs->hest_log_addr, - CONFIG_ERROR_LOG_BUFFER_SIZE); - - current = ALIGN_UP(current, 8); - hest = (acpi_hest_t *)current; - acpi_write_hest(hest, acpi_fill_hest); - acpi_add_table(rsdp, (void *)current); - current += hest->header.length; return current; } diff --git a/src/soc/intel/xeon_sp/spr/acpi/uncore.asl b/src/soc/intel/xeon_sp/spr/acpi/uncore.asl index ab2c3eb68c..76066242e9 100644 --- a/src/soc/intel/xeon_sp/spr/acpi/uncore.asl +++ b/src/soc/intel/xeon_sp/spr/acpi/uncore.asl @@ -18,7 +18,7 @@ Scope (\_SB) #include "iiostack.asl" #undef SOCKET - #if CONFIG(SOC_ACPI_HEST) + #if CONFIG(ACPI_HEST) Method (_OSC, 4, NotSerialized) { CreateDWordField (Arg3, 0x00, CDW1) diff --git a/src/soc/intel/xeon_sp/uncore_acpi.c b/src/soc/intel/xeon_sp/uncore_acpi.c index 86519448bf..7acae310b8 100644 --- a/src/soc/intel/xeon_sp/uncore_acpi.c +++ b/src/soc/intel/xeon_sp/uncore_acpi.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -633,10 +632,5 @@ unsigned long northbridge_write_acpi_tables(const struct device *device, unsigne } } - if (CONFIG(SOC_ACPI_HEST)) { - printk(BIOS_DEBUG, "ACPI: * HEST at %lx\n", current); - current = hest_create(current, rsdp); - } - return current; }