summaryrefslogtreecommitdiff
path: root/src/soc/intel/common/block
diff options
context:
space:
mode:
authorFrancois Toguo <francois.toguo.fotso@intel.com>2021-01-26 10:27:49 -0800
committerPatrick Georgi <pgeorgi@google.com>2021-02-22 07:22:50 +0000
commit15cbc3b5996ae64aff2e4741c4c3ec3d7f5cc1a7 (patch)
treeec401d461fcbbace3194553db3953a4d80e8d332 /src/soc/intel/common/block
parent619c60f94cc00251bfaedde4f1764e2f96dcdecd (diff)
soc/intel/tigerlake: Add CrashLog implementation for intel TGL
CrashLog is a diagnostic feature for Intel TGL based platforms. It is meant to capture the state of the platform before a crash. The state of relevant registers is preserved across a warm reset. BUG=None TEST=CrashLog data generated, extracted, processed, decoded sucessfully on delbin. Signed-off-by: Francois Toguo <francois.toguo.fotso@intel.com> Change-Id: Ie3763cebcd1178709cc8597710bf062a30901809 Reviewed-on: https://review.coreboot.org/c/coreboot/+/49943 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Tim Wawrzynczak <twawrzynczak@chromium.org>
Diffstat (limited to 'src/soc/intel/common/block')
-rw-r--r--src/soc/intel/common/block/acpi/Kconfig9
-rw-r--r--src/soc/intel/common/block/acpi/Makefile.inc1
-rw-r--r--src/soc/intel/common/block/acpi/acpi_bert.c95
-rw-r--r--src/soc/intel/common/block/crashlog/Makefile.inc1
-rw-r--r--src/soc/intel/common/block/crashlog/crashlog.c536
-rw-r--r--src/soc/intel/common/block/include/intelblocks/crashlog.h183
-rw-r--r--src/soc/intel/common/block/include/intelblocks/pmc_ipc.h2
7 files changed, 825 insertions, 2 deletions
diff --git a/src/soc/intel/common/block/acpi/Kconfig b/src/soc/intel/common/block/acpi/Kconfig
index a4f9844c70..8912ff3105 100644
--- a/src/soc/intel/common/block/acpi/Kconfig
+++ b/src/soc/intel/common/block/acpi/Kconfig
@@ -10,7 +10,13 @@ config SOC_INTEL_COMMON_BLOCK_ACPI_LPIT
depends on HAVE_ACPI_TABLES
select ACPI_LPIT
help
- Generate LPIT table with LPI state entries.
+ Generate LPIT table with LPI state entries
+
+config SOC_INTEL_COMMON_BLOCK_CRASHLOG
+ bool
+ depends on SOC_INTEL_CRASHLOG
+ help
+ Generate crash data for BERT table
if SOC_INTEL_COMMON_BLOCK_ACPI
@@ -19,4 +25,5 @@ config SOC_INTEL_COMMON_BLOCK_ACPI_CPPC
help
Generate CPPC entries for Intel SpeedShift
+
endif
diff --git a/src/soc/intel/common/block/acpi/Makefile.inc b/src/soc/intel/common/block/acpi/Makefile.inc
index c605088dbe..89565a6fd9 100644
--- a/src/soc/intel/common/block/acpi/Makefile.inc
+++ b/src/soc/intel/common/block/acpi/Makefile.inc
@@ -1,3 +1,4 @@
ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_ACPI) += acpi.c
ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_ACPI_LPIT) += lpit.c
+ramstage-$(CONFIG_ACPI_BERT) += acpi_bert.c
ramstage-$(CONFIG_SOC_INTEL_COMMON_ACPI_WAKE_SOURCE) += acpi_wake_source.c
diff --git a/src/soc/intel/common/block/acpi/acpi_bert.c b/src/soc/intel/common/block/acpi/acpi_bert.c
new file mode 100644
index 0000000000..d090dfd2cf
--- /dev/null
+++ b/src/soc/intel/common/block/acpi/acpi_bert.c
@@ -0,0 +1,95 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#include <acpi/acpi.h>
+#include <acpi/acpigen.h>
+#include <arch/bert_storage.h>
+#include <console/console.h>
+#include <intelblocks/acpi.h>
+#include <intelblocks/crashlog.h>
+
+
+void acpi_soc_fill_bert(acpi_bert_t *bert,
+ void **region,
+ size_t *length)
+{
+ acpi_generic_error_status_t *status = NULL;
+ size_t cpu_record_size, pmc_record_size;
+ void *cl_data = NULL;
+
+ if (!cl_get_total_data_size()) {
+ printk(BIOS_ERR, "Error: No crashlog record present\n");
+ return;
+ }
+
+ status = bert_new_event(&CPER_SEC_FW_ERR_REC_REF_GUID);
+ if (!status) {
+ printk(BIOS_ERR, "Error: unable to allocate GSB\n");
+ return;
+ }
+
+ if (cl_get_total_data_size() > bert_storage_remaining()) {
+ printk(BIOS_ERR, "Error: Crashlog entry would exceed "
+ "available region\n");
+ return;
+ }
+
+ cpu_record_size = cl_get_cpu_record_size();
+ if (cpu_record_size) {
+ cl_data = new_cper_fw_error_crashlog(status, cpu_record_size);
+ if (!cl_data) {
+ printk(BIOS_ERR, "Error: Crashlog CPU entry(size %lu) "
+ "would exceed available region\n",
+ cpu_record_size);
+ return;
+ }
+ printk(BIOS_DEBUG, "cl_data %p, cpu_record_size %lu\n",
+ cl_data, cpu_record_size);
+ cl_fill_cpu_records(cl_data);
+ }
+
+ pmc_record_size = cl_get_pmc_record_size();
+ if (pmc_record_size) {
+ /* Allocate new FW ERR structure in case CPU crashlog is present */
+ if (cpu_record_size && !bert_append_fw_err(status)) {
+ printk(BIOS_ERR, "Error: Crashlog PMC entry would "
+ "exceed available region\n");
+ return;
+ }
+
+ cl_data = new_cper_fw_error_crashlog(status, pmc_record_size);
+ if (!cl_data) {
+ printk(BIOS_ERR, "Error: Crashlog PMC entry(size %lu) "
+ "would exceed available region\n",
+ pmc_record_size);
+ return;
+ }
+ printk(BIOS_DEBUG, "cl_data %p, pmc_record_size %lu\n",
+ cl_data, pmc_record_size);
+ cl_fill_pmc_records(cl_data);
+ }
+
+ *length = status->raw_data_length;
+ *region = (void *)status;
+
+}
+
+bool acpi_is_boot_error_src_present(void)
+{
+
+ if (!CONFIG(SOC_INTEL_CRASHLOG)) {
+ printk(BIOS_DEBUG, "Crashlog disabled.\n");
+ return false;
+ }
+
+ if (!discover_crashlog()) {
+ printk(BIOS_SPEW, "Crashlog discovery result: crashlog not found\n");
+ return false;
+ }
+
+ collect_pmc_and_cpu_crashlog_from_srams();
+
+ /* Discovery tables sizes can be larger than the actual valid collected data */
+ u32 crashlog_size = cl_get_total_data_size();
+
+ return (crashlog_size > 0);
+}
diff --git a/src/soc/intel/common/block/crashlog/Makefile.inc b/src/soc/intel/common/block/crashlog/Makefile.inc
new file mode 100644
index 0000000000..3ff1120609
--- /dev/null
+++ b/src/soc/intel/common/block/crashlog/Makefile.inc
@@ -0,0 +1 @@
+ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_CRASHLOG) += crashlog.c
diff --git a/src/soc/intel/common/block/crashlog/crashlog.c b/src/soc/intel/common/block/crashlog/crashlog.c
new file mode 100644
index 0000000000..433545af17
--- /dev/null
+++ b/src/soc/intel/common/block/crashlog/crashlog.c
@@ -0,0 +1,536 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <console/console.h>
+#include <cbmem.h>
+#include <delay.h>
+#include <intelblocks/crashlog.h>
+#include <string.h>
+
+
+int __weak cl_get_cpu_record_size(void)
+{
+ return 0;
+}
+
+
+int __weak cl_get_pmc_record_size(void)
+{
+ return 0;
+}
+
+
+u32 __weak cl_get_cpu_bar_addr(void)
+{
+ return 0;
+}
+
+
+u32 __weak cl_get_cpu_tmp_bar(void)
+{
+ return 0;
+}
+
+
+u32 __weak cl_get_cpu_mb_int_addr(void)
+{
+ return 0;
+}
+
+
+int __weak cl_get_total_data_size(void)
+{
+ return cl_get_cpu_record_size() + cl_get_pmc_record_size();
+}
+
+
+bool __weak cl_pmc_sram_has_mmio_access(void)
+{
+ return false;
+}
+
+
+bool __weak cpu_crashlog_support(void)
+{
+ return false;
+}
+
+
+bool __weak pmc_crashlog_support(void)
+{
+ return false;
+}
+
+
+bool __weak cl_cpu_data_present(void)
+{
+ return false;
+}
+
+
+bool __weak cl_pmc_data_present(void)
+{
+ return false;
+}
+
+
+__weak void reset_discovery_buffers(void) {}
+
+
+__weak void update_new_pmc_crashlog_size(u32 *pmc_crash_size) {}
+
+
+__weak void update_new_cpu_crashlog_size(u32 *cpu_crash_size) {}
+
+
+pmc_ipc_discovery_buf_t __weak cl_get_pmc_discovery_buf(void)
+{
+ pmc_ipc_discovery_buf_t discov_buf;
+ memset(&discov_buf, 0, sizeof(pmc_ipc_discovery_buf_t));
+ return discov_buf;
+}
+
+
+pmc_crashlog_desc_table_t __weak cl_get_pmc_descriptor_table(void)
+{
+ pmc_crashlog_desc_table_t desc_tab;
+ memset(&desc_tab, 0, sizeof(pmc_crashlog_desc_table_t));
+ return desc_tab;
+}
+
+
+cpu_crashlog_discovery_table_t __weak cl_get_cpu_discovery_table(void)
+{
+ cpu_crashlog_discovery_table_t cpu_disc_tab;
+ memset(&cpu_disc_tab, 0, sizeof(cpu_crashlog_discovery_table_t));
+ return cpu_disc_tab;
+}
+
+
+int cpu_cl_poll_mailbox_ready(u32 cl_mailbox_addr)
+{
+ cpu_crashlog_mailbox_t cl_mailbox_interface;
+ u16 stall_cnt = 0;
+
+ do {
+ cl_mailbox_interface.data = read32((u32 *)cl_mailbox_addr);
+ udelay(CPU_CRASHLOG_MAILBOX_WAIT_STALL);
+ stall_cnt++;
+ } while ((cl_mailbox_interface.fields.busy == 1)
+ && stall_cnt < CPU_CRASHLOG_MAILBOX_WAIT_TIMEOUT);
+
+ if ((cl_mailbox_interface.fields.busy == 1)
+ && (stall_cnt >= CPU_CRASHLOG_MAILBOX_WAIT_TIMEOUT)) {
+ printk(BIOS_ERR, "CPU crashlog mailbox timed out.\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+
+int cpu_cl_mailbox_cmd(u8 cmd, u8 param)
+{
+ cpu_crashlog_mailbox_t cl_mailbox_intf;
+ u32 cl_base_addr;
+
+ memset(&cl_mailbox_intf, 0, sizeof(cpu_crashlog_mailbox_t));
+
+ cl_base_addr = cl_get_cpu_bar_addr();
+
+ cl_mailbox_intf.fields.command = cmd;
+ cl_mailbox_intf.fields.param = param;
+ cl_mailbox_intf.fields.busy = 1;
+
+ write32((u32 *)(cl_base_addr + cl_get_cpu_mb_int_addr()),
+ cl_mailbox_intf.data);
+
+ cpu_cl_poll_mailbox_ready(cl_base_addr + cl_get_cpu_mb_int_addr());
+
+ return 1;
+}
+
+
+int cpu_cl_clear_data(void)
+{
+ return cpu_cl_mailbox_cmd(CPU_CRASHLOG_CMD_CLEAR, 0);
+}
+
+
+int pmc_cl_gen_descriptor_table(u32 desc_table_addr,
+ pmc_crashlog_desc_table_t *descriptor_table)
+{
+ int total_data_size = 0;
+ descriptor_table->numb_regions = read32((u32 *)desc_table_addr);
+ printk(BIOS_DEBUG, "CL PMC desc table: numb of regions is 0x%x at addr 0x%x\n",
+ descriptor_table->numb_regions, desc_table_addr);
+ for (int i = 0; i < descriptor_table->numb_regions; i++) {
+ desc_table_addr += 4;
+ descriptor_table->regions[i].data = read32((u32 *)(desc_table_addr));
+ total_data_size += descriptor_table->regions[i].bits.size * sizeof(u32);
+ printk(BIOS_DEBUG, "CL PMC desc table: region 0x%x has size 0x%x at offset 0x%x\n",
+ i, descriptor_table->regions[i].bits.size,
+ descriptor_table->regions[i].bits.offset);
+ if (i > 255) {
+ printk(BIOS_ERR, "More than 255 regions in PMC crashLog descriptor table");
+ break;
+ }
+ }
+ return total_data_size;
+}
+
+
+bool __weak pmc_cl_discovery(void)
+{
+ return false;
+}
+
+
+bool __weak cpu_cl_discovery(void)
+{
+ return false;
+}
+
+
+int cl_pmc_re_arm_after_reset(void)
+{
+
+ const struct pmc_ipc_buffer *req = { 0 };
+ struct pmc_ipc_buffer *res = NULL;
+ uint32_t cmd_reg;
+ int r;
+
+ cmd_reg = pmc_make_ipc_cmd(PMC_IPC_CMD_CRASHLOG,
+ PMC_IPC_CMD_ID_CRASHLOG_RE_ARM_ON_RESET,
+ PMC_IPC_CMD_SIZE_SHIFT);
+
+ r = pmc_send_ipc_cmd(cmd_reg, req, res);
+
+ if (r < 0) {
+ printk(BIOS_ERR, "pmc_send_ipc_cmd failed in %s\n", __func__);
+ return 0;
+ }
+
+ return r;
+}
+
+
+/* Sends PMC IPC to clear CrashLog from PMC SSRAM area */
+int cl_pmc_clear(void)
+{
+ const struct pmc_ipc_buffer *req = { 0 };
+ struct pmc_ipc_buffer *res = NULL;
+ uint32_t cmd_reg;
+ int r;
+
+ cmd_reg = pmc_make_ipc_cmd(PMC_IPC_CMD_CRASHLOG,
+ PMC_IPC_CMD_ID_CRASHLOG_ERASE,
+ PMC_IPC_CMD_SIZE_SHIFT);
+
+ r = pmc_send_ipc_cmd(cmd_reg, req, res);
+
+ if (r < 0) {
+ printk(BIOS_ERR, "pmc_send_ipc_cmd failed in %s\n", __func__);
+ return 0;
+ }
+
+ return r;
+}
+
+
+/*
+ * Sends PMC IPC to populate CrashLog on all reboot.
+ * The SSRAM area will be cleared on G3 by PMC automatically
+ */
+
+int cl_pmc_en_gen_on_all_reboot(void)
+{
+ const struct pmc_ipc_buffer *req = { 0 };
+ struct pmc_ipc_buffer *res = NULL;
+ uint32_t cmd_reg;
+ int r;
+
+ cmd_reg = pmc_make_ipc_cmd(PMC_IPC_CMD_CRASHLOG,
+ PMC_IPC_CMD_ID_CRASHLOG_ON_RESET,
+ PMC_IPC_CMD_SIZE_SHIFT);
+
+ r = pmc_send_ipc_cmd(cmd_reg, req, res);
+
+ if (r < 0) {
+ printk(BIOS_ERR, "pmc_send_ipc_cmd failed in %s\n", __func__);
+ return 0;
+ }
+
+ return r;
+}
+
+
+bool discover_crashlog(void)
+{
+ bool cpu_cl_discovered = false, pmc_cl_discovered = false;
+
+ reset_discovery_buffers();
+
+ /* PCH crashLog discovery */
+ pmc_cl_discovered = pmc_cl_discovery();
+
+ /* CPU crashLog discovery */
+ cpu_cl_discovered = cpu_cl_discovery();
+
+ return (cpu_cl_discovered || pmc_cl_discovered);
+}
+
+
+bool cl_copy_data_from_sram(u32 src_bar,
+ u32 offset,
+ u32 size,
+ u32 *dest_addr,
+ u32 buffer_index,
+ bool pmc_sram)
+{
+ if (src_bar == 0) {
+ printk(BIOS_ERR, "Invalid bar 0x%x and offset 0x%x for %s\n",
+ src_bar, offset, __func__);
+ return false;
+ }
+
+ u32 src_addr = src_bar + offset;
+
+ u32 data = read32((u32 *)src_addr);
+ /* PMC: copy if 1st DWORD in buffer is not zero and its 31st bit is not set */
+ if (pmc_sram && !(data && !(data & BIT(31)))) {
+ printk(BIOS_DEBUG, "Invalid data 0x%x at offset 0x%x from addr 0x%x"
+ " of PMC SRAM.\n", data, offset, src_bar);
+ return false;
+ }
+ /*CPU: don't copy if 1st DWORD in first buffer is zero */
+ if (!pmc_sram && !data && (buffer_index == 0)) {
+ printk(BIOS_DEBUG, "Invalid data 0x%x at offset 0x%x from addr 0x%x"
+ " of telemetry SRAM.\n", data, offset, src_bar);
+ return false;
+ }
+
+ u32 copied = 0;
+ while (copied < size) {
+ /* DW by DW copy: byte access to PMC SRAM not allowed */
+ *dest_addr = read32((u32 *)src_addr);
+ dest_addr++;
+ src_addr += 4;
+ copied++;
+ }
+ return true;
+}
+
+
+void cl_get_pmc_sram_data(void)
+{
+ u32 *dest = NULL;
+ u32 tmp_bar_addr = cl_get_cpu_tmp_bar();
+ u32 pmc_crashLog_size = cl_get_pmc_record_size();
+
+ if (!cl_pmc_sram_has_mmio_access())
+ return;
+
+ pmc_ipc_discovery_buf_t discovery_buf = cl_get_pmc_discovery_buf();
+
+ if (discovery_buf.bits.supported != 1) {
+ printk(BIOS_DEBUG, "PCH crashlog feature not supported.\n");
+ goto pmc_send_re_arm_after_reset;
+ }
+
+ /* Get the size of data to copy */
+ if (discovery_buf.bits.discov_mechanism == 1) {
+ if (discovery_buf.bits.base_offset & BIT(31)) {
+ printk(BIOS_DEBUG, "PCH discovery to be used is disabled.\n");
+ goto pmc_send_re_arm_after_reset;
+ }
+ printk(BIOS_DEBUG, "PMC crashLog size in discovery mode : 0x%X\n",
+ pmc_crashLog_size);
+ } else {
+ if (discovery_buf.bits.dis) {
+ printk(BIOS_DEBUG, "PCH crashlog is disabled in legacy mode.\n");
+ return;
+ }
+ pmc_crashLog_size = (discovery_buf.bits.size != 0) ?
+ discovery_buf.bits.size : 0xC00;
+ printk(BIOS_DEBUG, "PMC crashLog size in legacy mode : 0x%X\n",
+ pmc_crashLog_size);
+ }
+
+ /* allocate mem for the record to be copied */
+ unsigned long pmc_cl_cbmem_addr;
+
+ pmc_cl_cbmem_addr = (unsigned long) cbmem_add(CBMEM_ID_PMC_CRASHLOG,
+ pmc_crashLog_size);
+ if (!pmc_cl_cbmem_addr) {
+ printk(BIOS_ERR, "Unable to allocate CBMEM PMC crashLog entry.\n");
+ return;
+ }
+
+ memset((void *)pmc_cl_cbmem_addr, 0, pmc_crashLog_size);
+ dest = (u32 *)(uintptr_t) pmc_cl_cbmem_addr;
+ bool pmc_sram = true;
+ pmc_crashlog_desc_table_t descriptor_table = cl_get_pmc_descriptor_table();
+ if (discovery_buf.bits.discov_mechanism == 1) {
+ for (int i = 0; i < descriptor_table.numb_regions; i++) {
+ if (cl_copy_data_from_sram(tmp_bar_addr,
+ descriptor_table.regions[i].bits.offset,
+ descriptor_table.regions[i].bits.size,
+ dest,
+ i,
+ pmc_sram)) {
+ dest = (u32 *)((u32)dest +
+ (descriptor_table.regions[i].bits.size
+ * sizeof(u32)));
+ } else {
+ pmc_crashLog_size -= descriptor_table.regions[i].bits.size *
+ sizeof(u32);
+ printk(BIOS_DEBUG, "discover mode PMC crashlog size adjusted"
+ " to: 0x%x\n", pmc_crashLog_size);
+ }
+ }
+ } else {
+ if (!cl_copy_data_from_sram(tmp_bar_addr,
+ discovery_buf.bits.base_offset,
+ discovery_buf.bits.size,
+ dest,
+ 0,
+ pmc_sram)) {
+ pmc_crashLog_size -= discovery_buf.bits.size * sizeof(u32);
+ printk(BIOS_DEBUG, "legacy mode PMC crashlog size adjusted to: 0x%x\n",
+ pmc_crashLog_size);
+ }
+ }
+
+ update_new_pmc_crashlog_size(&pmc_crashLog_size);
+
+pmc_send_re_arm_after_reset:
+ /* when bit 7 of discov cmd resp is set -> bit 2 of size field */
+ if (discovery_buf.bits.size & BIT(2))
+ cl_pmc_re_arm_after_reset();
+
+ /* Clear the SSRAM region after copying the error log */
+ cl_pmc_clear();
+
+}
+
+
+void cl_get_cpu_sram_data(void)
+{
+ u32 tmp_bar_addr = 0;
+ u32 *dest = NULL;
+ u32 m_cpu_crashLog_size = cl_get_cpu_record_size();
+ cpu_crashlog_discovery_table_t cpu_cl_disc_tab = cl_get_cpu_discovery_table();
+
+ if (m_cpu_crashLog_size < 1) {
+ printk(BIOS_DEBUG, "%s: no data to collect.\n", __func__);
+ return;
+ }
+
+ printk(BIOS_DEBUG, "CPU crash data size: 0x%X bytes in 0x%X region(s).\n",
+ m_cpu_crashLog_size, cpu_cl_disc_tab.header.fields.count);
+
+ /* allocate memory buffers for CPU crashog data to be copied */
+ unsigned long cpu_crashlog_cbmem_addr;
+ cpu_crashlog_cbmem_addr = (unsigned long) cbmem_add(CBMEM_ID_CPU_CRASHLOG,
+ m_cpu_crashLog_size);
+ if (!cpu_crashlog_cbmem_addr) {
+ printk(BIOS_ERR, "Failed to add CPU main crashLog entries to CBMEM.\n");
+ return;
+ }
+
+ memset((void *) cpu_crashlog_cbmem_addr, 0, m_cpu_crashLog_size);
+ tmp_bar_addr = cl_get_cpu_bar_addr();
+ dest = (u32 *)(uintptr_t) cpu_crashlog_cbmem_addr;
+ bool pmc_sram = false;
+ cpu_crashlog_buffer_info_t buff_info;
+
+ for (int i = 0 ; i < cpu_cl_disc_tab.header.fields.count ; i++) {
+ buff_info = cpu_cl_disc_tab.buffers[i];
+
+ if (cl_copy_data_from_sram(tmp_bar_addr,
+ cpu_cl_disc_tab.buffers[i].fields.offset,
+ cpu_cl_disc_tab.buffers[i].fields.size,
+ dest,
+ i,
+ pmc_sram)) {
+ dest = (u32 *)((u32)dest +
+ (cpu_cl_disc_tab.buffers[i].fields.size * sizeof(u32)));
+ } else {
+ m_cpu_crashLog_size -= cpu_cl_disc_tab.buffers[i].fields.size
+ * sizeof(u32);
+
+ /* for CPU skip all buffers if the 1st one is not valid */
+ if (i == 0) {
+ m_cpu_crashLog_size = 0;
+ break;
+ }
+ }
+ }
+
+ update_new_cpu_crashlog_size(&m_cpu_crashLog_size);
+
+ /* clear telemetry SRAM region */
+ cpu_cl_clear_data();
+
+}
+
+
+void collect_pmc_and_cpu_crashlog_from_srams(void)
+{
+ if (pmc_crashlog_support() && cl_pmc_data_present()
+ && (cl_get_pmc_record_size() > 0)) {
+ cl_pmc_en_gen_on_all_reboot();
+ printk(BIOS_DEBUG, "Crashlog collection enabled on every reboot.\n");
+ cl_get_pmc_sram_data();
+ } else {
+ printk(BIOS_DEBUG, "Skipping PMC crashLog collection. Data not present.\n");
+ }
+
+ printk(BIOS_DEBUG, "m_cpu_crashLog_size : 0x%X bytes\n", cl_get_cpu_record_size());
+
+ if (cpu_crashlog_support() && cl_cpu_data_present()
+ && (cl_get_cpu_record_size() > 0)) {
+ printk(BIOS_DEBUG, "CPU crashLog present.\n");
+ cl_get_cpu_sram_data();
+ } else {
+ printk(BIOS_DEBUG, "Skipping CPU crashLog collection. Data not present.\n");
+ }
+}
+
+
+bool cl_fill_cpu_records(void *cl_record)
+{
+ void *cl_src_addr = NULL;
+
+ u32 m_cpu_crashLog_size = cl_get_cpu_record_size();
+
+ if (!cl_cpu_data_present() || m_cpu_crashLog_size == 0) {
+ printk(BIOS_DEBUG, "CPU crashLog not present, skipping.\n");
+ return false;
+ }
+
+ printk(BIOS_DEBUG, "CPU crash data collection.\n");
+ cl_src_addr = cbmem_find(CBMEM_ID_CPU_CRASHLOG);
+ memcpy(cl_record, cl_src_addr, m_cpu_crashLog_size);
+
+ return true;
+}
+
+
+bool cl_fill_pmc_records(void *cl_record)
+{
+ void *cl_src_addr = NULL;
+
+ u32 m_pmc_crashLog_size = cl_get_pmc_record_size();
+
+ if (!cl_pmc_data_present() || m_pmc_crashLog_size == 0) {
+ printk(BIOS_DEBUG, "PMC crashLog not present, skipping.\n");
+ return false;
+ }
+
+ printk(BIOS_DEBUG, "PMC crash data collection.\n");
+ cl_src_addr = cbmem_find(CBMEM_ID_PMC_CRASHLOG);
+ memcpy(cl_record, cl_src_addr, m_pmc_crashLog_size);
+
+ return true;
+}
diff --git a/src/soc/intel/common/block/include/intelblocks/crashlog.h b/src/soc/intel/common/block/include/intelblocks/crashlog.h
new file mode 100644
index 0000000000..1e1bc020ad
--- /dev/null
+++ b/src/soc/intel/common/block/include/intelblocks/crashlog.h
@@ -0,0 +1,183 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef SOC_INTEL_COMMON_BLOCK_CRASHLOG_H
+#define SOC_INTEL_COMMON_BLOCK_CRASHLOG_H
+
+#include <console/console.h>
+#include <device/pci_ops.h>
+#include <device/pci_def.h>
+#include <device/mmio.h>
+#include <fsp/util.h>
+#include <intelblocks/pmc_ipc.h>
+#include <types.h>
+#include <arch/io.h>
+
+/* PMC CrashLog Command */
+#define PMC_IPC_CMD_CRASHLOG 0xA6
+#define PMC_IPC_CMD_ID_CRASHLOG_DISCOVERY 0x01
+#define PMC_IPC_CMD_ID_CRASHLOG_DISABLE 0x02
+#define PMC_IPC_CMD_ID_CRASHLOG_ERASE 0x04
+#define PMC_IPC_CMD_ID_CRASHLOG_ON_RESET 0x05
+#define PMC_IPC_CMD_ID_CRASHLOG_RE_ARM_ON_RESET 0x06
+
+/* CPU CrashLog Mailbox commands */
+#define CPU_CRASHLOG_CMD_DISABLE 0
+#define CPU_CRASHLOG_CMD_CLEAR 2
+#define CPU_CRASHLOG_MAILBOX_WAIT_STALL 1
+#define CPU_CRASHLOG_MAILBOX_WAIT_TIMEOUT 1000
+#define CPU_CRASHLOG_DISC_TAB_GUID_VALID 0x1600
+
+#define CRASHLOG_SIZE_DEBUG_PURPOSE 0x640
+
+/* PMC crashlog discovery structs */
+typedef union {
+ struct {
+ u16 offset;
+ u16 size;
+ } bits;
+ u32 data;
+} __packed pmc_crashlog_discov_region_t;
+
+typedef struct {
+ u32 numb_regions;
+ pmc_crashlog_discov_region_t regions[256];
+} __packed pmc_crashlog_desc_table_t;
+
+typedef union {
+ struct {
+ u32 supported :1;
+ u32 dis :1;
+ u32 discov_mechanism :2;
+ u32 size :12;
+ u32 base_offset :16; /* Start offset of CrashLog in PMC SSRAM */
+ u32 rsv :16;
+ u32 desc_tabl_offset :16; /* start offset of descriptor table */
+ } bits;
+ u64 val_64_bits;
+} __packed pmc_ipc_discovery_buf_t;
+
+
+/* CPU/TELEMETRY crashlog discovery structs */
+
+typedef union {
+ struct {
+ u32 pcie_cap_id :16;
+ u32 cap_ver :4;
+ u32 next_cap_offset :12;
+ } fields;
+ u32 data;
+} __packed cap_data_t;
+
+typedef union {
+ struct {
+ u64 devsc_ven_id :16;
+ u64 devsc_ver :4;
+ u64 devsc_len :12;
+ u64 devsc_id :16;
+ u64 num_entries :8; /*Numb of telemetry aggregators in lookup table. */
+ u64 entries_size :8; /* Entry Size in DWORDS */
+ } fields;
+ u64 data_64;
+ u32 data_32[2];
+} __packed devsc_data_t;
+
+typedef union {
+ struct {
+ u32 t_bir_q :3; /* tBIR, The BAR to be used */
+ u32 discovery_table_offset :29;
+ } fields;
+ u32 data;
+} __packed discovery_data_t;
+
+typedef struct {
+ cap_data_t cap_data;
+ devsc_data_t devsc_data;
+ discovery_data_t discovery_data;
+} __packed tel_crashlog_devsc_cap_t;
+
+typedef union {
+ struct {
+ u64 access_type :4;
+ u64 crash_type :4;
+ u64 count :8;
+ u64 reserved :16;
+ u64 guid :32;
+ } fields;
+ u64 data;
+} __packed cpu_crashlog_header_t;
+
+
+/* Structures for CPU CrashLog mailbox interface */
+typedef union {
+ struct {
+ u32 command :8;
+ u32 param :8;
+ u32 reserved :15;
+ u32 busy :1;
+ } fields;
+ u32 data;
+} __packed cpu_crashlog_mailbox_t;
+
+typedef union {
+ struct {
+ u32 offset :32;
+ u32 size :16;
+ u32 reserved :16;
+ } fields;
+ u64 data;
+} __packed cpu_crashlog_buffer_info_t;
+
+typedef struct {
+ cpu_crashlog_header_t header;
+ cpu_crashlog_mailbox_t cmd_mailbox;
+ u32 mailbox_data;
+ cpu_crashlog_buffer_info_t buffers[256];
+} __packed cpu_crashlog_discovery_table_t;
+
+int cl_get_cpu_record_size(void);
+int cl_get_pmc_record_size(void);
+u32 cl_get_cpu_bar_addr(void);
+u32 cl_get_cpu_tmp_bar(void);
+u32 cl_get_cpu_mb_int_addr(void);
+int cl_get_total_data_size(void);
+bool cl_pmc_sram_has_mmio_access(void);
+bool cpu_crashlog_support(void);
+bool pmc_crashlog_support(void);
+bool cl_cpu_data_present(void);
+bool cl_pmc_data_present(void);
+void cl_get_cpu_sram_data(void);
+void cl_get_pmc_sram_data(void);
+void reset_discovery_buffers(void);
+void update_new_pmc_crashlog_size(u32 *pmc_crash_size);
+void update_new_cpu_crashlog_size(u32 *cpu_crash_size);
+pmc_ipc_discovery_buf_t cl_get_pmc_discovery_buf(void);
+pmc_crashlog_desc_table_t cl_get_pmc_descriptor_table(void);
+cpu_crashlog_discovery_table_t cl_get_cpu_discovery_table(void);
+u32 cl_gen_cpu_bar_addr(void);
+int cpu_cl_poll_mailbox_ready(u32 cl_mailbox_addr);
+int cpu_cl_mailbox_cmd(u8 cmd, u8 param);
+int cpu_cl_clear_data(void);
+int pmc_cl_gen_descriptor_table(u32 desc_table_addr,
+ pmc_crashlog_desc_table_t *descriptor_table);
+bool pmc_cl_discovery(void);
+bool cpu_cl_discovery(void);
+int cl_pmc_re_arm_after_reset(void);
+int cl_pmc_clear(void);
+int cl_pmc_en_gen_on_all_reboot(void);
+bool discover_crashlog(void);
+bool cl_copy_data_from_sram(u32 src_bar,
+ u32 offset,
+ u32 size,
+ u32 *dest_addr,
+ u32 buffer_index,
+ bool pmc_sram);
+void collect_pmc_and_cpu_crashlog_from_srams(void);
+bool cl_fill_cpu_records(void *cl_record);
+bool cl_fill_pmc_records(void *cl_record);
+
+static const EFI_GUID FW_ERR_SECTION_GUID = {
+ 0x81212a96, 0x09ed, 0x4996,
+ { 0x94, 0x71, 0x8d, 0x72, 0x9c, 0x8e, 0x69, 0xed }
+};
+
+#endif /* SOC_INTEL_COMMON_BLOCK_CRASHLOG */
diff --git a/src/soc/intel/common/block/include/intelblocks/pmc_ipc.h b/src/soc/intel/common/block/include/intelblocks/pmc_ipc.h
index 71adf5bb9b..b67abc0fcd 100644
--- a/src/soc/intel/common/block/include/intelblocks/pmc_ipc.h
+++ b/src/soc/intel/common/block/include/intelblocks/pmc_ipc.h
@@ -17,7 +17,7 @@
#define PMC_IPC_CMD_SIZE_MASK 0xff
#define PMC_IPC_CMD_FIELD(name, val) \
- (((val) & PMC_IPC_CMD_##name##_MASK << PMC_IPC_CMD_##name##_SHIFT))
+ ((((val) & PMC_IPC_CMD_##name##_MASK) << PMC_IPC_CMD_##name##_SHIFT))
#define PMC_IPC_CMD_NO_MSI 0