1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <arch/bert_storage.h>
4 #include <console/console.h>
6 #include <cpu/intel/cpu_ids.h>
8 #include <device/pci_ops.h>
9 #include <intelblocks/crashlog.h>
10 #include <intelblocks/pmc_ipc.h>
11 #include <soc/crashlog.h>
12 #include <soc/iomap.h>
13 #include <soc/pci_devs.h>
16 #define CONTROL_INTERFACE_OFFSET 0x5
17 #define CRASHLOG_NODES_COUNT 0x2
18 #define CRASHLOG_PUNIT_STORAGE_OFF_MASK BIT(24)
19 #define CRASHLOG_RE_ARM_STATUS_MASK BIT(25)
20 #define CRASHLOG_CONSUMED_MASK BIT(31)
22 /* Global crashLog info */
23 static bool m_pmc_crash_log_support
;
24 static bool m_pmc_crash_log_present
;
25 static bool m_cpu_crash_log_support
;
26 static bool m_cpu_crash_log_present
;
27 static u32 m_pmc_crash_log_size
;
28 static u32 m_cpu_crash_log_size
;
29 static u32 cpu_crash_version
;
30 static pmc_ipc_discovery_buf_t discovery_buf
;
31 static pmc_crashlog_desc_table_t descriptor_table
;
32 static tel_crashlog_devsc_cap_t cpu_cl_devsc_cap
;
33 static cpu_crashlog_discovery_table_t cpu_cl_disc_tab
;
34 static uintptr_t disc_tab_addr
;
36 static u64
get_disc_tab_header(void)
38 return read64p(disc_tab_addr
);
41 /* Get the SRAM BAR. */
42 static uintptr_t get_sram_bar(pci_devfn_t sram_devfn
)
44 const struct device
*dev
;
47 dev
= pcidev_path_on_root(sram_devfn
);
49 printk(BIOS_ERR
, "device: 0x%x not found!\n", sram_devfn
);
53 res
= probe_resource(dev
, PCI_BASE_ADDRESS_0
);
55 printk(BIOS_ERR
, "SOC SRAM device not found!\n");
59 /* Return the base address of the resource */
63 static void configure_sram(const struct device
*sram_dev
, uintptr_t base_addr
)
65 pci_update_config16(sram_dev
, PCI_COMMAND
, ~(PCI_COMMAND_IO
| PCI_COMMAND_MEMORY
), 0);
67 /* Program BAR 0 and enable command register memory space decoding */
68 pci_write_config32(sram_dev
, PCI_BASE_ADDRESS_0
, base_addr
);
69 pci_or_config16(sram_dev
, PCI_COMMAND
, PCI_COMMAND_MEMORY
);
72 void cl_get_pmc_sram_data(cl_node_t
*head
)
74 uintptr_t pmc_sram_base
= cl_get_cpu_tmp_bar();
75 u32 pmc_crashLog_size
= cl_get_pmc_record_size();
76 cl_node_t
*cl_cur
= head
;
78 if (!pmc_crashLog_size
) {
79 printk(BIOS_ERR
, "No PMC crashlog records\n");
84 printk(BIOS_ERR
, "PMC SRAM base not valid\n");
88 if (!cl_pmc_sram_has_mmio_access())
91 printk(BIOS_DEBUG
, "PMC crashLog size : 0x%x\n", pmc_crashLog_size
);
94 while (cl_cur
&& cl_cur
->next
) {
95 cl_cur
= cl_cur
->next
;
98 /* Process crashlog records */
99 for (int i
= 0; i
< descriptor_table
.numb_regions
+ 1; i
++) {
100 uintptr_t sram_base
= 0;
101 bool pmc_sram
= true;
102 printk(BIOS_DEBUG
, "Region[0x%x].Tag=0x%x offset=0x%x, size=0x%x\n",
104 descriptor_table
.regions
[i
].bits
.assign_tag
,
105 descriptor_table
.regions
[i
].bits
.offset
,
106 descriptor_table
.regions
[i
].bits
.size
);
108 if (!descriptor_table
.regions
[i
].bits
.size
)
112 * Region with metadata TAG contains information about BDF entry for SOC PMC SRAM
113 * and IOE SRAM. We don't need to parse this as we already define BDFs in
114 * soc/pci_devs.h for these SRAMs. Also we need to skip this region as it does not
115 * contain any crashlog data.
117 if (descriptor_table
.regions
[i
].bits
.assign_tag
==
118 CRASHLOG_DESCRIPTOR_TABLE_TAG_META
) {
119 pmc_crashLog_size
-= descriptor_table
.regions
[i
].bits
.size
*
121 printk(BIOS_DEBUG
, "Found metadata tag. PMC crashlog size adjusted to: 0x%x\n",
125 if (descriptor_table
.regions
[i
].bits
.assign_tag
==
126 CRASHLOG_DESCRIPTOR_TABLE_TAG_SOC
)
127 sram_base
= pmc_sram_base
;
131 cl_node_t
*cl_node
= malloc_cl_node(descriptor_table
.regions
[i
].bits
.size
);
134 printk(BIOS_DEBUG
, "failed to allocate cl_node [region = %d]\n", i
);
135 goto pmc_send_re_arm_after_reset
;
138 if (cl_copy_data_from_sram(sram_base
,
139 descriptor_table
.regions
[i
].bits
.offset
,
140 descriptor_table
.regions
[i
].bits
.size
,
144 cl_cur
->next
= cl_node
;
145 cl_cur
= cl_cur
->next
;
147 /* Coping data from sram failed */
148 pmc_crashLog_size
-= descriptor_table
.regions
[i
].bits
.size
*
150 printk(BIOS_DEBUG
, "PMC crashlog size adjusted to: 0x%x\n",
153 free_cl_node(cl_node
);
158 update_new_pmc_crashlog_size(&pmc_crashLog_size
);
160 pmc_send_re_arm_after_reset
:
161 /* When bit 7 of discov cmd resp is set -> bit 2 of size field */
162 cl_pmc_re_arm_after_reset();
164 /* Clear the SSRAM region after copying the error log */
168 bool pmc_cl_discovery(void)
170 uintptr_t bar_addr
= 0, desc_table_addr
= 0;
172 const struct pmc_ipc_buffer req
= { 0 };
173 struct pmc_ipc_buffer res
;
177 cmd_reg
= pmc_make_ipc_cmd(PMC_IPC_CMD_CRASHLOG
,
178 PMC_IPC_CMD_ID_CRASHLOG_DISCOVERY
,
179 PMC_IPC_CMD_SIZE_SHIFT
);
180 printk(BIOS_DEBUG
, "cmd_reg from pmc_make_ipc_cmd %d in %s\n", cmd_reg
, __func__
);
182 r
= pmc_send_ipc_cmd(cmd_reg
, &req
, &res
);
185 printk(BIOS_ERR
, "pmc_send_ipc_cmd failed in %s\n", __func__
);
188 discovery_buf
.conv_val_64_bits
= ((u64
)res
.buf
[1] << 32) | res
.buf
[0];
190 if ((discovery_buf
.conv_bits64
.supported
!= 1) ||
191 (discovery_buf
.conv_bits64
.discov_mechanism
== 0) ||
192 (discovery_buf
.conv_bits64
.crash_dis_sts
== 1)) {
193 printk(BIOS_INFO
, "PCH crashlog feature not supported.\n");
194 m_pmc_crash_log_support
= false;
195 m_pmc_crash_log_size
= 0;
196 printk(BIOS_DEBUG
, "discovery_buf supported: %d, mechanism: %d, CrashDisSts: %d\n",
197 discovery_buf
.conv_bits64
.supported
,
198 discovery_buf
.conv_bits64
.discov_mechanism
,
199 discovery_buf
.conv_bits64
.crash_dis_sts
);
203 printk(BIOS_INFO
, "PMC crashlog feature is supported.\n");
204 m_pmc_crash_log_support
= true;
206 /* Program BAR 0 and enable command register memory space decoding */
207 bar_addr
= get_sram_bar(PCI_DEVFN_SRAM
);
209 printk(BIOS_ERR
, "PCH SRAM not available, crashlog feature can't be enabled.\n");
213 configure_sram(PCI_DEV_SRAM
, bar_addr
);
215 desc_table_addr
= bar_addr
+ discovery_buf
.conv_bits64
.desc_tabl_offset
;
216 m_pmc_crash_log_size
= pmc_cl_gen_descriptor_table(desc_table_addr
,
218 printk(BIOS_DEBUG
, "PMC CrashLog size in discovery mode: 0x%X\n",
219 m_pmc_crash_log_size
);
220 m_pmc_crash_log_present
= m_pmc_crash_log_size
> 0;
225 uintptr_t cl_get_cpu_bar_addr(void)
227 uintptr_t base_addr
= 0;
228 if (cpu_cl_devsc_cap
.discovery_data
.fields
.t_bir_q
== TEL_DVSEC_TBIR_BAR0
) {
229 base_addr
= pci_read_config32(PCI_DEV_TELEMETRY
, PCI_BASE_ADDRESS_0
) &
230 ~PCI_BASE_ADDRESS_MEM_ATTR_MASK
;
231 } else if (cpu_cl_devsc_cap
.discovery_data
.fields
.t_bir_q
== TEL_DVSEC_TBIR_BAR1
) {
232 base_addr
= pci_read_config32(PCI_DEV_TELEMETRY
, PCI_BASE_ADDRESS_1
) &
233 ~PCI_BASE_ADDRESS_MEM_ATTR_MASK
;
235 printk(BIOS_ERR
, "Invalid TEL_CFG_BAR value %d, discovery failure expected.\n",
236 cpu_cl_devsc_cap
.discovery_data
.fields
.t_bir_q
);
242 uintptr_t cl_get_cpu_tmp_bar(void)
244 return get_sram_bar(PCI_DEVFN_SRAM
);
247 bool cl_pmc_sram_has_mmio_access(void)
249 if (pci_read_config16(PCI_DEV_SRAM
, PCI_VENDOR_ID
) == 0xFFFF) {
250 printk(BIOS_ERR
, "PMC SSRAM PCI device disabled. Can be enabled in device tree.\n");
257 static bool cpu_cl_get_capability(tel_crashlog_devsc_cap_t
*cl_devsc_cap
)
259 cl_devsc_cap
->cap_data
.data
= pci_read_config32(PCI_DEV_TELEMETRY
,
260 TEL_DVSEC_OFFSET
+ TEL_DVSEC_PCIE_CAP_ID
);
261 if (cl_devsc_cap
->cap_data
.fields
.pcie_cap_id
!= TELEMETRY_EXTENDED_CAP_ID
) {
262 printk(BIOS_DEBUG
, "Read ID for Telemetry: 0x%x differs from expected: 0x%x\n",
263 cl_devsc_cap
->cap_data
.fields
.pcie_cap_id
, TELEMETRY_EXTENDED_CAP_ID
);
267 /* Walk through the entries until crashLog entry */
268 cl_devsc_cap
->devsc_data
.data_32
[1] = pci_read_config32(PCI_DEV_TELEMETRY
, TEL_DVSEV_ID
);
270 while (cl_devsc_cap
->devsc_data
.fields
.devsc_id
!= CRASHLOG_DVSEC_ID
) {
271 if (cl_devsc_cap
->cap_data
.fields
.next_cap_offset
== 0
272 || cl_devsc_cap
->cap_data
.fields
.next_cap_offset
== 0xFFFF) {
273 printk(BIOS_DEBUG
, "Read invalid pcie_cap_id value: 0x%x\n",
274 cl_devsc_cap
->cap_data
.fields
.pcie_cap_id
);
277 new_offset
= cl_devsc_cap
->cap_data
.fields
.next_cap_offset
;
278 cl_devsc_cap
->cap_data
.data
= pci_read_config32(PCI_DEV_TELEMETRY
,
279 new_offset
+ TEL_DVSEC_PCIE_CAP_ID
);
280 cl_devsc_cap
->devsc_data
.data_32
[1] = pci_read_config32(PCI_DEV_TELEMETRY
,
281 new_offset
+ TEL_DVSEV_ID
);
283 cpu_crash_version
= cl_devsc_cap
->devsc_data
.fields
.devsc_ver
;
285 cl_devsc_cap
->discovery_data
.data
= pci_read_config32(PCI_DEV_TELEMETRY
, new_offset
286 + TEL_DVSEV_DISCOVERY_TABLE_OFFSET
);
291 static u32
get_disc_table_offset(void)
293 u32 offset
= cpu_cl_devsc_cap
.discovery_data
.fields
.discovery_table_offset
;
298 static bool is_crashlog_data_valid(u32 dw0
)
300 return (dw0
!= 0x0 && dw0
!= INVALID_CRASHLOG_RECORD
);
303 static bool cpu_cl_gen_discovery_table(void)
305 uintptr_t bar_addr
= cl_get_cpu_bar_addr();
310 disc_tab_addr
= bar_addr
+ get_disc_table_offset();
311 memset(&cpu_cl_disc_tab
, 0, sizeof(cpu_crashlog_discovery_table_t
));
312 cpu_cl_disc_tab
.header
.data
= get_disc_tab_header();
313 /* Check both 32 bit header data and status register for non-zero values */
314 if ((!is_crashlog_data_valid(cpu_cl_disc_tab
.header
.data
& 0xFFFFFFFF)) &&
315 (!is_crashlog_data_valid((cpu_cl_disc_tab
.header
.data
) >> 32)))
319 cpu_cl_disc_tab
.header
.fields
.count
= CRASHLOG_NODES_COUNT
;
320 printk(BIOS_DEBUG
, "cpu_crashlog_discovery_table buffer count: 0x%x\n",
321 cpu_cl_disc_tab
.header
.fields
.count
);
322 for (int i
= 0; i
< cpu_cl_disc_tab
.header
.fields
.count
; i
++) {
323 cur_offset
= 8 + 24 * i
;
324 u32 cl_buffer_size
= read32p(disc_tab_addr
+ cur_offset
+ 4);
325 /* Check for buffer size */
326 if (!(is_crashlog_data_valid(cl_buffer_size
)))
329 u32 dw0
= read32p(disc_tab_addr
+ cur_offset
);
330 if (dw0
& CRASHLOG_CONSUMED_MASK
) {
331 printk(BIOS_DEBUG
, "cpu crashlog records already consumed."
332 "id: 0x%x dw0: 0x%x\n", i
, dw0
);
336 cpu_cl_disc_tab
.buffers
[i
].data
= read64p(disc_tab_addr
+ cur_offset
);
337 printk(BIOS_DEBUG
, "cpu_crashlog_discovery_table buffer: 0x%x size: "
338 "0x%x offset: 0x%x\n", i
, cpu_cl_disc_tab
.buffers
[i
].fields
.size
,
339 cpu_cl_disc_tab
.buffers
[i
].fields
.offset
);
340 m_cpu_crash_log_size
+= cpu_cl_disc_tab
.buffers
[i
].fields
.size
* sizeof(u32
);
343 if (m_cpu_crash_log_size
> 0)
344 m_cpu_crash_log_present
= true;
346 m_cpu_crash_log_present
= false;
351 bool cpu_cl_discovery(void)
353 memset(&cpu_cl_devsc_cap
, 0, sizeof(tel_crashlog_devsc_cap_t
));
355 if (!cpu_cl_get_capability(&cpu_cl_devsc_cap
)) {
356 printk(BIOS_ERR
, "CPU crashlog capability not found.\n");
357 m_cpu_crash_log_support
= false;
361 m_cpu_crash_log_support
= true;
363 if (!cpu_cl_gen_discovery_table()) {
364 printk(BIOS_ERR
, "CPU crashlog discovery table not valid.\n");
365 m_cpu_crash_log_present
= false;
372 void reset_discovery_buffers(void)
374 memset(&discovery_buf
, 0, sizeof(pmc_ipc_discovery_buf_t
));
375 memset(&descriptor_table
, 0, sizeof(pmc_crashlog_desc_table_t
));
376 memset(&cpu_cl_devsc_cap
, 0, sizeof(tel_crashlog_devsc_cap_t
));
379 int cl_get_total_data_size(void)
381 printk(BIOS_DEBUG
, "crashlog size:pmc-0x%x, cpu-0x%x\n",
382 m_pmc_crash_log_size
, m_cpu_crash_log_size
);
383 return m_pmc_crash_log_size
+ m_cpu_crash_log_size
;
386 static uintptr_t get_control_status_interface(void)
389 return (disc_tab_addr
+ CONTROL_INTERFACE_OFFSET
* sizeof(u32
));
393 int cpu_cl_clear_data(void)
398 static bool wait_and_check(u32 bit_mask
)
403 cpu_cl_disc_tab
.header
.data
= get_disc_tab_header();
404 udelay(CPU_CRASHLOG_WAIT_STALL
);
406 } while (((cpu_cl_disc_tab
.header
.data
& bit_mask
) == 0) &&
407 ((stall_cnt
* CPU_CRASHLOG_WAIT_STALL
) < CPU_CRASHLOG_WAIT_TIMEOUT
));
409 return (cpu_cl_disc_tab
.header
.data
& bit_mask
);
412 void cpu_cl_rearm(void)
414 uintptr_t ctrl_sts_intfc_addr
= get_control_status_interface();
416 if (!ctrl_sts_intfc_addr
) {
417 printk(BIOS_ERR
, "CPU crashlog control and status interface address not valid\n");
421 /* Rearm the CPU crashlog. Crashlog does not get collected if rearming fails */
422 cl_punit_control_interface_t punit_ctrl_intfc
;
423 memset(&punit_ctrl_intfc
, 0, sizeof(cl_punit_control_interface_t
));
424 punit_ctrl_intfc
.fields
.set_re_arm
= 1;
425 write32p(ctrl_sts_intfc_addr
, punit_ctrl_intfc
.data
);
427 if (!wait_and_check(CRASHLOG_RE_ARM_STATUS_MASK
))
428 printk(BIOS_ERR
, "CPU crashlog re_arm not asserted\n");
430 printk(BIOS_DEBUG
, "CPU crashlog re_arm asserted\n");
433 void cpu_cl_cleanup(void)
435 /* Perform any SOC specific cleanup after reading the crashlog data from SRAM */
436 uintptr_t ctrl_sts_intfc_addr
= get_control_status_interface();
438 if (!ctrl_sts_intfc_addr
) {
439 printk(BIOS_ERR
, "CPU crashlog control and status interface address not valid\n");
443 /* If storage-off is supported, turn off the PUNIT SRAM
444 * stroage to save power. This clears crashlog records also.
447 if (!cpu_cl_disc_tab
.header
.fields
.storage_off_support
) {
448 printk(BIOS_INFO
, "CPU crashlog storage_off not supported\n");
452 cl_punit_control_interface_t punit_ctrl_intfc
;
453 memset(&punit_ctrl_intfc
, 0, sizeof(cl_punit_control_interface_t
));
454 punit_ctrl_intfc
.fields
.set_storage_off
= 1;
455 write32p(ctrl_sts_intfc_addr
, punit_ctrl_intfc
.data
);
457 if (!wait_and_check(CRASHLOG_PUNIT_STORAGE_OFF_MASK
))
458 printk(BIOS_ERR
, "CPU crashlog storage_off not asserted\n");
460 printk(BIOS_DEBUG
, "CPU crashlog storage_off asserted\n");
463 pmc_ipc_discovery_buf_t
cl_get_pmc_discovery_buf(void)
465 return discovery_buf
;
468 pmc_crashlog_desc_table_t
cl_get_pmc_descriptor_table(void)
470 return descriptor_table
;
473 int cl_get_pmc_record_size(void)
475 return m_pmc_crash_log_size
;
478 int cl_get_cpu_record_size(void)
480 return m_cpu_crash_log_size
;
483 bool cl_cpu_data_present(void)
485 return m_cpu_crash_log_present
;
488 bool cl_pmc_data_present(void)
490 return m_pmc_crash_log_present
;
493 bool cpu_crashlog_support(void)
495 return m_cpu_crash_log_support
;
498 bool pmc_crashlog_support(void)
500 return m_pmc_crash_log_support
;
503 void update_new_pmc_crashlog_size(u32
*pmc_crash_size
)
505 m_pmc_crash_log_size
= *pmc_crash_size
;
508 cpu_crashlog_discovery_table_t
cl_get_cpu_discovery_table(void)
510 return cpu_cl_disc_tab
;
513 void update_new_cpu_crashlog_size(u32
*cpu_crash_size
)
515 m_cpu_crash_log_size
= *cpu_crash_size
;