summaryrefslogtreecommitdiff
path: root/src/soc/intel/xeon_sp/ras
diff options
context:
space:
mode:
authorRocky Phagura <rphagura@fb.com>2021-04-03 08:49:32 -0700
committerPatrick Georgi <pgeorgi@google.com>2021-06-04 12:38:32 +0000
commitd4db36e672644ac7f528d12c5ce3539725456085 (patch)
tree54887ccb33b3d62df2a684613006da4275c46d16 /src/soc/intel/xeon_sp/ras
parent3bfa1bde60dc3197c27f60ed7b25f9cbdbd3c4bb (diff)
src/intel/xeon_sp: add hardware error support (HEST)
This patch adds the ACPI hardware error source table (HEST) support. This involves a few different parts: (1) The ACPI HEST table which is filled with the appropriate fields (2) Reserved memory which is used by runtime SW to provide error information. OS will not accept a HEST table with this memory set to 0. The ASL code to enable APEI bit will be submitted in a separate patch. Tested on DeltaLake mainboard with following options enabled SOC_INTEL_XEON_RAS After boot to Linux, the following will show in dmesg: HEST: Table parsing has been initialized Change-Id: If76b2af153616182cc053ca878f30fe056e9c8bd Signed-off-by: Rocky Phagura <rphagura@fb.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/52090 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
Diffstat (limited to 'src/soc/intel/xeon_sp/ras')
-rw-r--r--src/soc/intel/xeon_sp/ras/Kconfig20
-rw-r--r--src/soc/intel/xeon_sp/ras/Makefile.inc3
-rw-r--r--src/soc/intel/xeon_sp/ras/hest.c100
3 files changed, 123 insertions, 0 deletions
diff --git a/src/soc/intel/xeon_sp/ras/Kconfig b/src/soc/intel/xeon_sp/ras/Kconfig
new file mode 100644
index 0000000000..79c599c2fb
--- /dev/null
+++ b/src/soc/intel/xeon_sp/ras/Kconfig
@@ -0,0 +1,20 @@
+# 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.inc b/src/soc/intel/xeon_sp/ras/Makefile.inc
new file mode 100644
index 0000000000..93c8705f94
--- /dev/null
+++ b/src/soc/intel/xeon_sp/ras/Makefile.inc
@@ -0,0 +1,3 @@
+## SPDX-License-Identifier: GPL-2.0-or-later
+
+ramstage-$(CONFIG_SOC_ACPI_HEST) += hest.c
diff --git a/src/soc/intel/xeon_sp/ras/hest.c b/src/soc/intel/xeon_sp/ras/hest.c
new file mode 100644
index 0000000000..6164edfe19
--- /dev/null
+++ b/src/soc/intel/xeon_sp/ras/hest.c
@@ -0,0 +1,100 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <soc/acpi.h>
+#include <acpi/acpi_gnvs.h>
+#include <cbmem.h>
+#include <console/console.h>
+#include <soc/hest.h>
+#include <intelblocks/nvs.h>
+
+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;
+ }
+
+ /* 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)
+{
+ ghes_record_t *rec = (ghes_record_t *)current;
+ u32 size = sizeof(ghes_record_t);
+
+ /* Fill GHES error source descriptor */
+ memset(rec, 0, size);
+ rec->esd.type = HEST_GHES_DESC_TYPE;
+ rec->esd.source_id = 0; /* 0 for MCE check exception source */
+ rec->esd.enabled = 1;
+ rec->esd.related_src_id = 0xffff;
+ rec->esd.prealloc_erecords = 1;
+ rec->esd.max_section_per_record = 0xf;
+ rec->max_raw_data_length = GHES_MAX_RAW_DATA_LENGTH;
+
+ /* Add error_status_address */
+ rec->sts_addr.space_id = 0;
+ rec->sts_addr.bit_width = 0x40;
+ rec->sts_addr.bit_offset = 0;
+ rec->sts_addr.access_size = QWORD_ACCESS;
+
+ /* Add notification structure */
+ rec->notify.type = NOTIFY_TYPE_SCI;
+ rec->notify.length = sizeof(acpi_hest_hen_t);
+ 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();
+
+ return size;
+}
+
+static unsigned long acpi_fill_hest(acpi_hest_t *hest)
+{
+ acpi_header_t *header = &(hest->header);
+ void *current;
+ current = (void *)(hest);
+ void *next = current;
+ next = hest + 1;
+ next += acpi_hest_add_ghes(next);
+ 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(CMBMEM_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(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;
+}