diff options
author | Saurabh Mishra <mishra.saurabh@intel.com> | 2024-09-12 10:52:56 +0530 |
---|---|---|
committer | Subrata Banik <subratabanik@google.com> | 2024-09-13 08:23:55 +0000 |
commit | 95cf9c0052234cf19599c03ea214eff4a6ed3b65 (patch) | |
tree | db9913d476eecffa50466c9df508524119ad29ff /src/soc/intel/pantherlake/crashlog.c | |
parent | 4ba9eeab08d3ab817b7751dc6f834148667ce065 (diff) |
soc/intel/ptl: Do initial Panther Lake SoC commit till ramstage
List of changes:
1. Add required SoC programming till ramstage.
2. Include only required headers into include/soc.
3. Skeleton code used to call FSP-S API.
BUG=b:348678529
TEST=Verified on Intel® Simics® Pre Silicon Simulation platform
for PTL using google/fatcat mainboard.
Change-Id: I61930726ad0c765bfa1d72c5df893262be884834
Signed-off-by: Saurabh Mishra <mishra.saurabh@intel.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/84332
Reviewed-by: Jérémy Compostella <jeremy.compostella@intel.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Subrata Banik <subratabanik@google.com>
Diffstat (limited to 'src/soc/intel/pantherlake/crashlog.c')
-rw-r--r-- | src/soc/intel/pantherlake/crashlog.c | 516 |
1 files changed, 516 insertions, 0 deletions
diff --git a/src/soc/intel/pantherlake/crashlog.c b/src/soc/intel/pantherlake/crashlog.c new file mode 100644 index 0000000000..d94f4c5476 --- /dev/null +++ b/src/soc/intel/pantherlake/crashlog.c @@ -0,0 +1,516 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <arch/bert_storage.h> +#include <console/console.h> +#include <cpu/cpu.h> +#include <cpu/intel/cpu_ids.h> +#include <delay.h> +#include <device/pci_ops.h> +#include <intelblocks/crashlog.h> +#include <intelblocks/pmc_ipc.h> +#include <soc/crashlog.h> +#include <soc/iomap.h> +#include <soc/pci_devs.h> +#include <string.h> + +#define CONTROL_INTERFACE_OFFSET 0x5 +#define CRASHLOG_NODES_COUNT 0x2 +#define CRASHLOG_PUNIT_STORAGE_OFF_MASK BIT(24) +#define CRASHLOG_RE_ARM_STATUS_MASK BIT(25) +#define CRASHLOG_CONSUMED_MASK BIT(31) + +/* Global crashLog info */ +static bool m_pmc_crash_log_support; +static bool m_pmc_crash_log_present; +static bool m_cpu_crash_log_support; +static bool m_cpu_crash_log_present; +static u32 m_pmc_crash_log_size; +static u32 m_cpu_crash_log_size; +static u32 cpu_crash_version; +static pmc_ipc_discovery_buf_t discovery_buf; +static pmc_crashlog_desc_table_t descriptor_table; +static tel_crashlog_devsc_cap_t cpu_cl_devsc_cap; +static cpu_crashlog_discovery_table_t cpu_cl_disc_tab; +static uintptr_t disc_tab_addr; + +static u64 get_disc_tab_header(void) +{ + return read64p(disc_tab_addr); +} + +/* Get the SRAM BAR. */ +static uintptr_t get_sram_bar(pci_devfn_t sram_devfn) +{ + const struct device *dev; + struct resource *res; + + dev = pcidev_path_on_root(sram_devfn); + if (!dev) { + printk(BIOS_ERR, "device: 0x%x not found!\n", sram_devfn); + return 0; + } + + res = probe_resource(dev, PCI_BASE_ADDRESS_0); + if (!res) { + printk(BIOS_ERR, "SOC SRAM device not found!\n"); + return 0; + } + + /* Return the base address of the resource */ + return res->base; +} + +static void configure_sram(const struct device *sram_dev, uintptr_t base_addr) +{ + pci_update_config16(sram_dev, PCI_COMMAND, ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY), 0); + + /* Program BAR 0 and enable command register memory space decoding */ + pci_write_config32(sram_dev, PCI_BASE_ADDRESS_0, base_addr); + pci_or_config16(sram_dev, PCI_COMMAND, PCI_COMMAND_MEMORY); +} + +void cl_get_pmc_sram_data(cl_node_t *head) +{ + uintptr_t pmc_sram_base = cl_get_cpu_tmp_bar(); + u32 pmc_crashLog_size = cl_get_pmc_record_size(); + cl_node_t *cl_cur = head; + + if (!pmc_crashLog_size) { + printk(BIOS_ERR, "No PMC crashlog records\n"); + return; + } + + if (!pmc_sram_base) { + printk(BIOS_ERR, "PMC SRAM base not valid\n"); + return; + } + + if (!cl_pmc_sram_has_mmio_access()) + return; + + printk(BIOS_DEBUG, "PMC crashLog size : 0x%x\n", pmc_crashLog_size); + + /* Goto tail node */ + while (cl_cur && cl_cur->next) { + cl_cur = cl_cur->next; + } + + /* Process crashlog records */ + for (int i = 0; i < descriptor_table.numb_regions + 1; i++) { + uintptr_t sram_base = 0; + bool pmc_sram = true; + printk(BIOS_DEBUG, "Region[0x%x].Tag=0x%x offset=0x%x, size=0x%x\n", + i, + descriptor_table.regions[i].bits.assign_tag, + descriptor_table.regions[i].bits.offset, + descriptor_table.regions[i].bits.size); + + if (!descriptor_table.regions[i].bits.size) + continue; + + /* + * Region with metadata TAG contains information about BDF entry for SOC PMC SRAM + * and IOE SRAM. We don't need to parse this as we already define BDFs in + * soc/pci_devs.h for these SRAMs. Also we need to skip this region as it does not + * contain any crashlog data. + */ + if (descriptor_table.regions[i].bits.assign_tag == + CRASHLOG_DESCRIPTOR_TABLE_TAG_META) { + pmc_crashLog_size -= descriptor_table.regions[i].bits.size * + sizeof(u32); + printk(BIOS_DEBUG, "Found metadata tag. PMC crashlog size adjusted to: 0x%x\n", + pmc_crashLog_size); + continue; + } else { + if (descriptor_table.regions[i].bits.assign_tag == + CRASHLOG_DESCRIPTOR_TABLE_TAG_SOC) + sram_base = pmc_sram_base; + else + continue; + + cl_node_t *cl_node = malloc_cl_node(descriptor_table.regions[i].bits.size); + + if (!cl_node) { + printk(BIOS_DEBUG, "failed to allocate cl_node [region = %d]\n", i); + goto pmc_send_re_arm_after_reset; + } + + if (cl_copy_data_from_sram(sram_base, + descriptor_table.regions[i].bits.offset, + descriptor_table.regions[i].bits.size, + cl_node->data, + i, + pmc_sram)) { + cl_cur->next = cl_node; + cl_cur = cl_cur->next; + } else { + /* Coping data from sram failed */ + pmc_crashLog_size -= descriptor_table.regions[i].bits.size * + sizeof(u32); + printk(BIOS_DEBUG, "PMC crashlog size adjusted to: 0x%x\n", + pmc_crashLog_size); + /* Free cl_node */ + free_cl_node(cl_node); + } + } + } + + 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 */ + cl_pmc_re_arm_after_reset(); + + /* Clear the SSRAM region after copying the error log */ + cl_pmc_clear(); +} + +bool pmc_cl_discovery(void) +{ + uintptr_t bar_addr = 0, desc_table_addr = 0; + + const struct pmc_ipc_buffer req = { 0 }; + struct pmc_ipc_buffer res; + uint32_t cmd_reg; + int r; + + cmd_reg = pmc_make_ipc_cmd(PMC_IPC_CMD_CRASHLOG, + PMC_IPC_CMD_ID_CRASHLOG_DISCOVERY, + PMC_IPC_CMD_SIZE_SHIFT); + printk(BIOS_DEBUG, "cmd_reg from pmc_make_ipc_cmd %d in %s\n", cmd_reg, __func__); + + 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 false; + } + discovery_buf.conv_val_64_bits = ((u64)res.buf[1] << 32) | res.buf[0]; + + if ((discovery_buf.conv_bits64.supported != 1) || + (discovery_buf.conv_bits64.discov_mechanism == 0) || + (discovery_buf.conv_bits64.crash_dis_sts == 1)) { + printk(BIOS_INFO, "PCH crashlog feature not supported.\n"); + m_pmc_crash_log_support = false; + m_pmc_crash_log_size = 0; + printk(BIOS_DEBUG, "discovery_buf supported: %d, mechanism: %d, CrashDisSts: %d\n", + discovery_buf.conv_bits64.supported, + discovery_buf.conv_bits64.discov_mechanism, + discovery_buf.conv_bits64.crash_dis_sts); + return false; + } + + printk(BIOS_INFO, "PMC crashlog feature is supported.\n"); + m_pmc_crash_log_support = true; + + /* Program BAR 0 and enable command register memory space decoding */ + bar_addr = get_sram_bar(PCI_DEVFN_SRAM); + if (bar_addr == 0) { + printk(BIOS_ERR, "PCH SRAM not available, crashlog feature can't be enabled.\n"); + return false; + } + + configure_sram(PCI_DEV_SRAM, bar_addr); + + desc_table_addr = bar_addr + discovery_buf.conv_bits64.desc_tabl_offset; + m_pmc_crash_log_size = pmc_cl_gen_descriptor_table(desc_table_addr, + &descriptor_table); + printk(BIOS_DEBUG, "PMC CrashLog size in discovery mode: 0x%X\n", + m_pmc_crash_log_size); + m_pmc_crash_log_present = m_pmc_crash_log_size > 0; + + return true; +} + +uintptr_t cl_get_cpu_bar_addr(void) +{ + uintptr_t base_addr = 0; + if (cpu_cl_devsc_cap.discovery_data.fields.t_bir_q == TEL_DVSEC_TBIR_BAR0) { + base_addr = pci_read_config32(PCI_DEV_TELEMETRY, PCI_BASE_ADDRESS_0) & + ~PCI_BASE_ADDRESS_MEM_ATTR_MASK; + } else if (cpu_cl_devsc_cap.discovery_data.fields.t_bir_q == TEL_DVSEC_TBIR_BAR1) { + base_addr = pci_read_config32(PCI_DEV_TELEMETRY, PCI_BASE_ADDRESS_1) & + ~PCI_BASE_ADDRESS_MEM_ATTR_MASK; + } else { + printk(BIOS_ERR, "Invalid TEL_CFG_BAR value %d, discovery failure expected.\n", + cpu_cl_devsc_cap.discovery_data.fields.t_bir_q); + } + + return base_addr; +} + +uintptr_t cl_get_cpu_tmp_bar(void) +{ + return get_sram_bar(PCI_DEVFN_SRAM); +} + +bool cl_pmc_sram_has_mmio_access(void) +{ + if (pci_read_config16(PCI_DEV_SRAM, PCI_VENDOR_ID) == 0xFFFF) { + printk(BIOS_ERR, "PMC SSRAM PCI device disabled. Can be enabled in device tree.\n"); + return false; + } + + return true; +} + +static bool cpu_cl_get_capability(tel_crashlog_devsc_cap_t *cl_devsc_cap) +{ + cl_devsc_cap->cap_data.data = pci_read_config32(PCI_DEV_TELEMETRY, + TEL_DVSEC_OFFSET + TEL_DVSEC_PCIE_CAP_ID); + if (cl_devsc_cap->cap_data.fields.pcie_cap_id != TELEMETRY_EXTENDED_CAP_ID) { + printk(BIOS_DEBUG, "Read ID for Telemetry: 0x%x differs from expected: 0x%x\n", + cl_devsc_cap->cap_data.fields.pcie_cap_id, TELEMETRY_EXTENDED_CAP_ID); + return false; + } + + /* Walk through the entries until crashLog entry */ + cl_devsc_cap->devsc_data.data_32[1] = pci_read_config32(PCI_DEV_TELEMETRY, TEL_DVSEV_ID); + int new_offset = 0; + while (cl_devsc_cap->devsc_data.fields.devsc_id != CRASHLOG_DVSEC_ID) { + if (cl_devsc_cap->cap_data.fields.next_cap_offset == 0 + || cl_devsc_cap->cap_data.fields.next_cap_offset == 0xFFFF) { + printk(BIOS_DEBUG, "Read invalid pcie_cap_id value: 0x%x\n", + cl_devsc_cap->cap_data.fields.pcie_cap_id); + return false; + } + new_offset = cl_devsc_cap->cap_data.fields.next_cap_offset; + cl_devsc_cap->cap_data.data = pci_read_config32(PCI_DEV_TELEMETRY, + new_offset + TEL_DVSEC_PCIE_CAP_ID); + cl_devsc_cap->devsc_data.data_32[1] = pci_read_config32(PCI_DEV_TELEMETRY, + new_offset + TEL_DVSEV_ID); + } + cpu_crash_version = cl_devsc_cap->devsc_data.fields.devsc_ver; + + cl_devsc_cap->discovery_data.data = pci_read_config32(PCI_DEV_TELEMETRY, new_offset + + TEL_DVSEV_DISCOVERY_TABLE_OFFSET); + + return true; +} + +static u32 get_disc_table_offset(void) +{ + u32 offset = cpu_cl_devsc_cap.discovery_data.fields.discovery_table_offset; + + return offset; +} + +static bool is_crashlog_data_valid(u32 dw0) +{ + return (dw0 != 0x0 && dw0 != INVALID_CRASHLOG_RECORD); +} + +static bool cpu_cl_gen_discovery_table(void) +{ + uintptr_t bar_addr = cl_get_cpu_bar_addr(); + + if (!bar_addr) + return false; + + disc_tab_addr = bar_addr + get_disc_table_offset(); + memset(&cpu_cl_disc_tab, 0, sizeof(cpu_crashlog_discovery_table_t)); + cpu_cl_disc_tab.header.data = get_disc_tab_header(); + /* Check both 32 bit header data and status register for non-zero values */ + if ((!is_crashlog_data_valid(cpu_cl_disc_tab.header.data & 0xFFFFFFFF)) && + (!is_crashlog_data_valid((cpu_cl_disc_tab.header.data) >> 32))) + return false; + + u32 cur_offset = 0; + cpu_cl_disc_tab.header.fields.count = CRASHLOG_NODES_COUNT; + printk(BIOS_DEBUG, "cpu_crashlog_discovery_table buffer count: 0x%x\n", + cpu_cl_disc_tab.header.fields.count); + for (int i = 0; i < cpu_cl_disc_tab.header.fields.count; i++) { + cur_offset = 8 + 24 * i; + u32 cl_buffer_size = read32p(disc_tab_addr + cur_offset + 4); + /* Check for buffer size */ + if (!(is_crashlog_data_valid(cl_buffer_size))) + continue; + + u32 dw0 = read32p(disc_tab_addr + cur_offset); + if (dw0 & CRASHLOG_CONSUMED_MASK) { + printk(BIOS_DEBUG, "cpu crashlog records already consumed." + "id: 0x%x dw0: 0x%x\n", i, dw0); + break; + } + + cpu_cl_disc_tab.buffers[i].data = read64p(disc_tab_addr + cur_offset); + printk(BIOS_DEBUG, "cpu_crashlog_discovery_table buffer: 0x%x size: " + "0x%x offset: 0x%x\n", i, cpu_cl_disc_tab.buffers[i].fields.size, + cpu_cl_disc_tab.buffers[i].fields.offset); + m_cpu_crash_log_size += cpu_cl_disc_tab.buffers[i].fields.size * sizeof(u32); + } + + if (m_cpu_crash_log_size > 0) + m_cpu_crash_log_present = true; + else + m_cpu_crash_log_present = false; + + return true; +} + +bool cpu_cl_discovery(void) +{ + memset(&cpu_cl_devsc_cap, 0, sizeof(tel_crashlog_devsc_cap_t)); + + if (!cpu_cl_get_capability(&cpu_cl_devsc_cap)) { + printk(BIOS_ERR, "CPU crashlog capability not found.\n"); + m_cpu_crash_log_support = false; + return false; + } + + m_cpu_crash_log_support = true; + + if (!cpu_cl_gen_discovery_table()) { + printk(BIOS_ERR, "CPU crashlog discovery table not valid.\n"); + m_cpu_crash_log_present = false; + return false; + } + + return true; +} + +void reset_discovery_buffers(void) +{ + memset(&discovery_buf, 0, sizeof(pmc_ipc_discovery_buf_t)); + memset(&descriptor_table, 0, sizeof(pmc_crashlog_desc_table_t)); + memset(&cpu_cl_devsc_cap, 0, sizeof(tel_crashlog_devsc_cap_t)); +} + +int cl_get_total_data_size(void) +{ + printk(BIOS_DEBUG, "crashlog size:pmc-0x%x, cpu-0x%x\n", + m_pmc_crash_log_size, m_cpu_crash_log_size); + return m_pmc_crash_log_size + m_cpu_crash_log_size; +} + +static uintptr_t get_control_status_interface(void) +{ + if (disc_tab_addr) + return (disc_tab_addr + CONTROL_INTERFACE_OFFSET * sizeof(u32)); + return 0; +} + +int cpu_cl_clear_data(void) +{ + return 0; +} + +static bool wait_and_check(u32 bit_mask) +{ + u32 stall_cnt = 0; + + do { + cpu_cl_disc_tab.header.data = get_disc_tab_header(); + udelay(CPU_CRASHLOG_WAIT_STALL); + stall_cnt++; + } while (((cpu_cl_disc_tab.header.data & bit_mask) == 0) && + ((stall_cnt * CPU_CRASHLOG_WAIT_STALL) < CPU_CRASHLOG_WAIT_TIMEOUT)); + + return (cpu_cl_disc_tab.header.data & bit_mask); +} + +void cpu_cl_rearm(void) +{ + uintptr_t ctrl_sts_intfc_addr = get_control_status_interface(); + + if (!ctrl_sts_intfc_addr) { + printk(BIOS_ERR, "CPU crashlog control and status interface address not valid\n"); + return; + } + + /* Rearm the CPU crashlog. Crashlog does not get collected if rearming fails */ + cl_punit_control_interface_t punit_ctrl_intfc; + memset(&punit_ctrl_intfc, 0, sizeof(cl_punit_control_interface_t)); + punit_ctrl_intfc.fields.set_re_arm = 1; + write32p(ctrl_sts_intfc_addr, punit_ctrl_intfc.data); + + if (!wait_and_check(CRASHLOG_RE_ARM_STATUS_MASK)) + printk(BIOS_ERR, "CPU crashlog re_arm not asserted\n"); + else + printk(BIOS_DEBUG, "CPU crashlog re_arm asserted\n"); +} + +void cpu_cl_cleanup(void) +{ + /* Perform any SOC specific cleanup after reading the crashlog data from SRAM */ + uintptr_t ctrl_sts_intfc_addr = get_control_status_interface(); + + if (!ctrl_sts_intfc_addr) { + printk(BIOS_ERR, "CPU crashlog control and status interface address not valid\n"); + return; + } + + /* If storage-off is supported, turn off the PUNIT SRAM + * stroage to save power. This clears crashlog records also. + */ + + if (!cpu_cl_disc_tab.header.fields.storage_off_support) { + printk(BIOS_INFO, "CPU crashlog storage_off not supported\n"); + return; + } + + cl_punit_control_interface_t punit_ctrl_intfc; + memset(&punit_ctrl_intfc, 0, sizeof(cl_punit_control_interface_t)); + punit_ctrl_intfc.fields.set_storage_off = 1; + write32p(ctrl_sts_intfc_addr, punit_ctrl_intfc.data); + + if (!wait_and_check(CRASHLOG_PUNIT_STORAGE_OFF_MASK)) + printk(BIOS_ERR, "CPU crashlog storage_off not asserted\n"); + else + printk(BIOS_DEBUG, "CPU crashlog storage_off asserted\n"); +} + +pmc_ipc_discovery_buf_t cl_get_pmc_discovery_buf(void) +{ + return discovery_buf; +} + +pmc_crashlog_desc_table_t cl_get_pmc_descriptor_table(void) +{ + return descriptor_table; +} + +int cl_get_pmc_record_size(void) +{ + return m_pmc_crash_log_size; +} + +int cl_get_cpu_record_size(void) +{ + return m_cpu_crash_log_size; +} + +bool cl_cpu_data_present(void) +{ + return m_cpu_crash_log_present; +} + +bool cl_pmc_data_present(void) +{ + return m_pmc_crash_log_present; +} + +bool cpu_crashlog_support(void) +{ + return m_cpu_crash_log_support; +} + +bool pmc_crashlog_support(void) +{ + return m_pmc_crash_log_support; +} + +void update_new_pmc_crashlog_size(u32 *pmc_crash_size) +{ + m_pmc_crash_log_size = *pmc_crash_size; +} + +cpu_crashlog_discovery_table_t cl_get_cpu_discovery_table(void) +{ + return cpu_cl_disc_tab; +} + +void update_new_cpu_crashlog_size(u32 *cpu_crash_size) +{ + m_cpu_crash_log_size = *cpu_crash_size; +} |