18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * UEFI Common Platform Error Record (CPER) support 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2010, Intel Corp. 68c2ecf20Sopenharmony_ci * Author: Huang Ying <ying.huang@intel.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * CPER is the format used to describe platform hardware error by 98c2ecf20Sopenharmony_ci * various tables, such as ERST, BERT and HEST etc. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * For more information about CPER, please refer to Appendix N of UEFI 128c2ecf20Sopenharmony_ci * Specification version 2.4. 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/kernel.h> 168c2ecf20Sopenharmony_ci#include <linux/module.h> 178c2ecf20Sopenharmony_ci#include <linux/time.h> 188c2ecf20Sopenharmony_ci#include <linux/cper.h> 198c2ecf20Sopenharmony_ci#include <linux/dmi.h> 208c2ecf20Sopenharmony_ci#include <linux/acpi.h> 218c2ecf20Sopenharmony_ci#include <linux/pci.h> 228c2ecf20Sopenharmony_ci#include <linux/aer.h> 238c2ecf20Sopenharmony_ci#include <linux/printk.h> 248c2ecf20Sopenharmony_ci#include <linux/bcd.h> 258c2ecf20Sopenharmony_ci#include <acpi/ghes.h> 268c2ecf20Sopenharmony_ci#include <ras/ras_event.h> 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/* 298c2ecf20Sopenharmony_ci * CPER record ID need to be unique even after reboot, because record 308c2ecf20Sopenharmony_ci * ID is used as index for ERST storage, while CPER records from 318c2ecf20Sopenharmony_ci * multiple boot may co-exist in ERST. 328c2ecf20Sopenharmony_ci */ 338c2ecf20Sopenharmony_ciu64 cper_next_record_id(void) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci static atomic64_t seq; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci if (!atomic64_read(&seq)) { 388c2ecf20Sopenharmony_ci time64_t time = ktime_get_real_seconds(); 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci /* 418c2ecf20Sopenharmony_ci * This code is unlikely to still be needed in year 2106, 428c2ecf20Sopenharmony_ci * but just in case, let's use a few more bits for timestamps 438c2ecf20Sopenharmony_ci * after y2038 to be sure they keep increasing monotonically 448c2ecf20Sopenharmony_ci * for the next few hundred years... 458c2ecf20Sopenharmony_ci */ 468c2ecf20Sopenharmony_ci if (time < 0x80000000) 478c2ecf20Sopenharmony_ci atomic64_set(&seq, (ktime_get_real_seconds()) << 32); 488c2ecf20Sopenharmony_ci else 498c2ecf20Sopenharmony_ci atomic64_set(&seq, 0x8000000000000000ull | 508c2ecf20Sopenharmony_ci ktime_get_real_seconds() << 24); 518c2ecf20Sopenharmony_ci } 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci return atomic64_inc_return(&seq); 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cper_next_record_id); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic const char * const severity_strs[] = { 588c2ecf20Sopenharmony_ci "recoverable", 598c2ecf20Sopenharmony_ci "fatal", 608c2ecf20Sopenharmony_ci "corrected", 618c2ecf20Sopenharmony_ci "info", 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ciconst char *cper_severity_str(unsigned int severity) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci return severity < ARRAY_SIZE(severity_strs) ? 678c2ecf20Sopenharmony_ci severity_strs[severity] : "unknown"; 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cper_severity_str); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci/* 728c2ecf20Sopenharmony_ci * cper_print_bits - print strings for set bits 738c2ecf20Sopenharmony_ci * @pfx: prefix for each line, including log level and prefix string 748c2ecf20Sopenharmony_ci * @bits: bit mask 758c2ecf20Sopenharmony_ci * @strs: string array, indexed by bit position 768c2ecf20Sopenharmony_ci * @strs_size: size of the string array: @strs 778c2ecf20Sopenharmony_ci * 788c2ecf20Sopenharmony_ci * For each set bit in @bits, print the corresponding string in @strs. 798c2ecf20Sopenharmony_ci * If the output length is longer than 80, multiple line will be 808c2ecf20Sopenharmony_ci * printed, with @pfx is printed at the beginning of each line. 818c2ecf20Sopenharmony_ci */ 828c2ecf20Sopenharmony_civoid cper_print_bits(const char *pfx, unsigned int bits, 838c2ecf20Sopenharmony_ci const char * const strs[], unsigned int strs_size) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci int i, len = 0; 868c2ecf20Sopenharmony_ci const char *str; 878c2ecf20Sopenharmony_ci char buf[84]; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci for (i = 0; i < strs_size; i++) { 908c2ecf20Sopenharmony_ci if (!(bits & (1U << i))) 918c2ecf20Sopenharmony_ci continue; 928c2ecf20Sopenharmony_ci str = strs[i]; 938c2ecf20Sopenharmony_ci if (!str) 948c2ecf20Sopenharmony_ci continue; 958c2ecf20Sopenharmony_ci if (len && len + strlen(str) + 2 > 80) { 968c2ecf20Sopenharmony_ci printk("%s\n", buf); 978c2ecf20Sopenharmony_ci len = 0; 988c2ecf20Sopenharmony_ci } 998c2ecf20Sopenharmony_ci if (!len) 1008c2ecf20Sopenharmony_ci len = snprintf(buf, sizeof(buf), "%s%s", pfx, str); 1018c2ecf20Sopenharmony_ci else 1028c2ecf20Sopenharmony_ci len += scnprintf(buf+len, sizeof(buf)-len, ", %s", str); 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci if (len) 1058c2ecf20Sopenharmony_ci printk("%s\n", buf); 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic const char * const proc_type_strs[] = { 1098c2ecf20Sopenharmony_ci "IA32/X64", 1108c2ecf20Sopenharmony_ci "IA64", 1118c2ecf20Sopenharmony_ci "ARM", 1128c2ecf20Sopenharmony_ci}; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic const char * const proc_isa_strs[] = { 1158c2ecf20Sopenharmony_ci "IA32", 1168c2ecf20Sopenharmony_ci "IA64", 1178c2ecf20Sopenharmony_ci "X64", 1188c2ecf20Sopenharmony_ci "ARM A32/T32", 1198c2ecf20Sopenharmony_ci "ARM A64", 1208c2ecf20Sopenharmony_ci}; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ciconst char * const cper_proc_error_type_strs[] = { 1238c2ecf20Sopenharmony_ci "cache error", 1248c2ecf20Sopenharmony_ci "TLB error", 1258c2ecf20Sopenharmony_ci "bus error", 1268c2ecf20Sopenharmony_ci "micro-architectural error", 1278c2ecf20Sopenharmony_ci}; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic const char * const proc_op_strs[] = { 1308c2ecf20Sopenharmony_ci "unknown or generic", 1318c2ecf20Sopenharmony_ci "data read", 1328c2ecf20Sopenharmony_ci "data write", 1338c2ecf20Sopenharmony_ci "instruction execution", 1348c2ecf20Sopenharmony_ci}; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic const char * const proc_flag_strs[] = { 1378c2ecf20Sopenharmony_ci "restartable", 1388c2ecf20Sopenharmony_ci "precise IP", 1398c2ecf20Sopenharmony_ci "overflow", 1408c2ecf20Sopenharmony_ci "corrected", 1418c2ecf20Sopenharmony_ci}; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic void cper_print_proc_generic(const char *pfx, 1448c2ecf20Sopenharmony_ci const struct cper_sec_proc_generic *proc) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci if (proc->validation_bits & CPER_PROC_VALID_TYPE) 1478c2ecf20Sopenharmony_ci printk("%s""processor_type: %d, %s\n", pfx, proc->proc_type, 1488c2ecf20Sopenharmony_ci proc->proc_type < ARRAY_SIZE(proc_type_strs) ? 1498c2ecf20Sopenharmony_ci proc_type_strs[proc->proc_type] : "unknown"); 1508c2ecf20Sopenharmony_ci if (proc->validation_bits & CPER_PROC_VALID_ISA) 1518c2ecf20Sopenharmony_ci printk("%s""processor_isa: %d, %s\n", pfx, proc->proc_isa, 1528c2ecf20Sopenharmony_ci proc->proc_isa < ARRAY_SIZE(proc_isa_strs) ? 1538c2ecf20Sopenharmony_ci proc_isa_strs[proc->proc_isa] : "unknown"); 1548c2ecf20Sopenharmony_ci if (proc->validation_bits & CPER_PROC_VALID_ERROR_TYPE) { 1558c2ecf20Sopenharmony_ci printk("%s""error_type: 0x%02x\n", pfx, proc->proc_error_type); 1568c2ecf20Sopenharmony_ci cper_print_bits(pfx, proc->proc_error_type, 1578c2ecf20Sopenharmony_ci cper_proc_error_type_strs, 1588c2ecf20Sopenharmony_ci ARRAY_SIZE(cper_proc_error_type_strs)); 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci if (proc->validation_bits & CPER_PROC_VALID_OPERATION) 1618c2ecf20Sopenharmony_ci printk("%s""operation: %d, %s\n", pfx, proc->operation, 1628c2ecf20Sopenharmony_ci proc->operation < ARRAY_SIZE(proc_op_strs) ? 1638c2ecf20Sopenharmony_ci proc_op_strs[proc->operation] : "unknown"); 1648c2ecf20Sopenharmony_ci if (proc->validation_bits & CPER_PROC_VALID_FLAGS) { 1658c2ecf20Sopenharmony_ci printk("%s""flags: 0x%02x\n", pfx, proc->flags); 1668c2ecf20Sopenharmony_ci cper_print_bits(pfx, proc->flags, proc_flag_strs, 1678c2ecf20Sopenharmony_ci ARRAY_SIZE(proc_flag_strs)); 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci if (proc->validation_bits & CPER_PROC_VALID_LEVEL) 1708c2ecf20Sopenharmony_ci printk("%s""level: %d\n", pfx, proc->level); 1718c2ecf20Sopenharmony_ci if (proc->validation_bits & CPER_PROC_VALID_VERSION) 1728c2ecf20Sopenharmony_ci printk("%s""version_info: 0x%016llx\n", pfx, proc->cpu_version); 1738c2ecf20Sopenharmony_ci if (proc->validation_bits & CPER_PROC_VALID_ID) 1748c2ecf20Sopenharmony_ci printk("%s""processor_id: 0x%016llx\n", pfx, proc->proc_id); 1758c2ecf20Sopenharmony_ci if (proc->validation_bits & CPER_PROC_VALID_TARGET_ADDRESS) 1768c2ecf20Sopenharmony_ci printk("%s""target_address: 0x%016llx\n", 1778c2ecf20Sopenharmony_ci pfx, proc->target_addr); 1788c2ecf20Sopenharmony_ci if (proc->validation_bits & CPER_PROC_VALID_REQUESTOR_ID) 1798c2ecf20Sopenharmony_ci printk("%s""requestor_id: 0x%016llx\n", 1808c2ecf20Sopenharmony_ci pfx, proc->requestor_id); 1818c2ecf20Sopenharmony_ci if (proc->validation_bits & CPER_PROC_VALID_RESPONDER_ID) 1828c2ecf20Sopenharmony_ci printk("%s""responder_id: 0x%016llx\n", 1838c2ecf20Sopenharmony_ci pfx, proc->responder_id); 1848c2ecf20Sopenharmony_ci if (proc->validation_bits & CPER_PROC_VALID_IP) 1858c2ecf20Sopenharmony_ci printk("%s""IP: 0x%016llx\n", pfx, proc->ip); 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic const char * const mem_err_type_strs[] = { 1898c2ecf20Sopenharmony_ci "unknown", 1908c2ecf20Sopenharmony_ci "no error", 1918c2ecf20Sopenharmony_ci "single-bit ECC", 1928c2ecf20Sopenharmony_ci "multi-bit ECC", 1938c2ecf20Sopenharmony_ci "single-symbol chipkill ECC", 1948c2ecf20Sopenharmony_ci "multi-symbol chipkill ECC", 1958c2ecf20Sopenharmony_ci "master abort", 1968c2ecf20Sopenharmony_ci "target abort", 1978c2ecf20Sopenharmony_ci "parity error", 1988c2ecf20Sopenharmony_ci "watchdog timeout", 1998c2ecf20Sopenharmony_ci "invalid address", 2008c2ecf20Sopenharmony_ci "mirror Broken", 2018c2ecf20Sopenharmony_ci "memory sparing", 2028c2ecf20Sopenharmony_ci "scrub corrected error", 2038c2ecf20Sopenharmony_ci "scrub uncorrected error", 2048c2ecf20Sopenharmony_ci "physical memory map-out event", 2058c2ecf20Sopenharmony_ci}; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ciconst char *cper_mem_err_type_str(unsigned int etype) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci return etype < ARRAY_SIZE(mem_err_type_strs) ? 2108c2ecf20Sopenharmony_ci mem_err_type_strs[etype] : "unknown"; 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cper_mem_err_type_str); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic int cper_mem_err_location(struct cper_mem_err_compact *mem, char *msg) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci u32 len, n; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci if (!msg) 2198c2ecf20Sopenharmony_ci return 0; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci n = 0; 2228c2ecf20Sopenharmony_ci len = CPER_REC_LEN - 1; 2238c2ecf20Sopenharmony_ci if (mem->validation_bits & CPER_MEM_VALID_NODE) 2248c2ecf20Sopenharmony_ci n += scnprintf(msg + n, len - n, "node: %d ", mem->node); 2258c2ecf20Sopenharmony_ci if (mem->validation_bits & CPER_MEM_VALID_CARD) 2268c2ecf20Sopenharmony_ci n += scnprintf(msg + n, len - n, "card: %d ", mem->card); 2278c2ecf20Sopenharmony_ci if (mem->validation_bits & CPER_MEM_VALID_MODULE) 2288c2ecf20Sopenharmony_ci n += scnprintf(msg + n, len - n, "module: %d ", mem->module); 2298c2ecf20Sopenharmony_ci if (mem->validation_bits & CPER_MEM_VALID_RANK_NUMBER) 2308c2ecf20Sopenharmony_ci n += scnprintf(msg + n, len - n, "rank: %d ", mem->rank); 2318c2ecf20Sopenharmony_ci if (mem->validation_bits & CPER_MEM_VALID_BANK) 2328c2ecf20Sopenharmony_ci n += scnprintf(msg + n, len - n, "bank: %d ", mem->bank); 2338c2ecf20Sopenharmony_ci if (mem->validation_bits & CPER_MEM_VALID_BANK_GROUP) 2348c2ecf20Sopenharmony_ci n += scnprintf(msg + n, len - n, "bank_group: %d ", 2358c2ecf20Sopenharmony_ci mem->bank >> CPER_MEM_BANK_GROUP_SHIFT); 2368c2ecf20Sopenharmony_ci if (mem->validation_bits & CPER_MEM_VALID_BANK_ADDRESS) 2378c2ecf20Sopenharmony_ci n += scnprintf(msg + n, len - n, "bank_address: %d ", 2388c2ecf20Sopenharmony_ci mem->bank & CPER_MEM_BANK_ADDRESS_MASK); 2398c2ecf20Sopenharmony_ci if (mem->validation_bits & CPER_MEM_VALID_DEVICE) 2408c2ecf20Sopenharmony_ci n += scnprintf(msg + n, len - n, "device: %d ", mem->device); 2418c2ecf20Sopenharmony_ci if (mem->validation_bits & (CPER_MEM_VALID_ROW | CPER_MEM_VALID_ROW_EXT)) { 2428c2ecf20Sopenharmony_ci u32 row = mem->row; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci row |= cper_get_mem_extension(mem->validation_bits, mem->extended); 2458c2ecf20Sopenharmony_ci n += scnprintf(msg + n, len - n, "row: %d ", row); 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci if (mem->validation_bits & CPER_MEM_VALID_COLUMN) 2488c2ecf20Sopenharmony_ci n += scnprintf(msg + n, len - n, "column: %d ", mem->column); 2498c2ecf20Sopenharmony_ci if (mem->validation_bits & CPER_MEM_VALID_BIT_POSITION) 2508c2ecf20Sopenharmony_ci n += scnprintf(msg + n, len - n, "bit_position: %d ", 2518c2ecf20Sopenharmony_ci mem->bit_pos); 2528c2ecf20Sopenharmony_ci if (mem->validation_bits & CPER_MEM_VALID_REQUESTOR_ID) 2538c2ecf20Sopenharmony_ci n += scnprintf(msg + n, len - n, "requestor_id: 0x%016llx ", 2548c2ecf20Sopenharmony_ci mem->requestor_id); 2558c2ecf20Sopenharmony_ci if (mem->validation_bits & CPER_MEM_VALID_RESPONDER_ID) 2568c2ecf20Sopenharmony_ci n += scnprintf(msg + n, len - n, "responder_id: 0x%016llx ", 2578c2ecf20Sopenharmony_ci mem->responder_id); 2588c2ecf20Sopenharmony_ci if (mem->validation_bits & CPER_MEM_VALID_TARGET_ID) 2598c2ecf20Sopenharmony_ci scnprintf(msg + n, len - n, "target_id: 0x%016llx ", 2608c2ecf20Sopenharmony_ci mem->target_id); 2618c2ecf20Sopenharmony_ci if (mem->validation_bits & CPER_MEM_VALID_CHIP_ID) 2628c2ecf20Sopenharmony_ci scnprintf(msg + n, len - n, "chip_id: %d ", 2638c2ecf20Sopenharmony_ci mem->extended >> CPER_MEM_CHIP_ID_SHIFT); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci msg[n] = '\0'; 2668c2ecf20Sopenharmony_ci return n; 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic int cper_dimm_err_location(struct cper_mem_err_compact *mem, char *msg) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci u32 len, n; 2728c2ecf20Sopenharmony_ci const char *bank = NULL, *device = NULL; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci if (!msg || !(mem->validation_bits & CPER_MEM_VALID_MODULE_HANDLE)) 2758c2ecf20Sopenharmony_ci return 0; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci len = CPER_REC_LEN; 2788c2ecf20Sopenharmony_ci dmi_memdev_name(mem->mem_dev_handle, &bank, &device); 2798c2ecf20Sopenharmony_ci if (bank && device) 2808c2ecf20Sopenharmony_ci n = snprintf(msg, len, "DIMM location: %s %s ", bank, device); 2818c2ecf20Sopenharmony_ci else 2828c2ecf20Sopenharmony_ci n = snprintf(msg, len, 2838c2ecf20Sopenharmony_ci "DIMM location: not present. DMI handle: 0x%.4x ", 2848c2ecf20Sopenharmony_ci mem->mem_dev_handle); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci return n; 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_civoid cper_mem_err_pack(const struct cper_sec_mem_err *mem, 2908c2ecf20Sopenharmony_ci struct cper_mem_err_compact *cmem) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci cmem->validation_bits = mem->validation_bits; 2938c2ecf20Sopenharmony_ci cmem->node = mem->node; 2948c2ecf20Sopenharmony_ci cmem->card = mem->card; 2958c2ecf20Sopenharmony_ci cmem->module = mem->module; 2968c2ecf20Sopenharmony_ci cmem->bank = mem->bank; 2978c2ecf20Sopenharmony_ci cmem->device = mem->device; 2988c2ecf20Sopenharmony_ci cmem->row = mem->row; 2998c2ecf20Sopenharmony_ci cmem->column = mem->column; 3008c2ecf20Sopenharmony_ci cmem->bit_pos = mem->bit_pos; 3018c2ecf20Sopenharmony_ci cmem->requestor_id = mem->requestor_id; 3028c2ecf20Sopenharmony_ci cmem->responder_id = mem->responder_id; 3038c2ecf20Sopenharmony_ci cmem->target_id = mem->target_id; 3048c2ecf20Sopenharmony_ci cmem->extended = mem->extended; 3058c2ecf20Sopenharmony_ci cmem->rank = mem->rank; 3068c2ecf20Sopenharmony_ci cmem->mem_array_handle = mem->mem_array_handle; 3078c2ecf20Sopenharmony_ci cmem->mem_dev_handle = mem->mem_dev_handle; 3088c2ecf20Sopenharmony_ci} 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ciconst char *cper_mem_err_unpack(struct trace_seq *p, 3118c2ecf20Sopenharmony_ci struct cper_mem_err_compact *cmem) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci const char *ret = trace_seq_buffer_ptr(p); 3148c2ecf20Sopenharmony_ci char rcd_decode_str[CPER_REC_LEN]; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci if (cper_mem_err_location(cmem, rcd_decode_str)) 3178c2ecf20Sopenharmony_ci trace_seq_printf(p, "%s", rcd_decode_str); 3188c2ecf20Sopenharmony_ci if (cper_dimm_err_location(cmem, rcd_decode_str)) 3198c2ecf20Sopenharmony_ci trace_seq_printf(p, "%s", rcd_decode_str); 3208c2ecf20Sopenharmony_ci trace_seq_putc(p, '\0'); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci return ret; 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem, 3268c2ecf20Sopenharmony_ci int len) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci struct cper_mem_err_compact cmem; 3298c2ecf20Sopenharmony_ci char rcd_decode_str[CPER_REC_LEN]; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci /* Don't trust UEFI 2.1/2.2 structure with bad validation bits */ 3328c2ecf20Sopenharmony_ci if (len == sizeof(struct cper_sec_mem_err_old) && 3338c2ecf20Sopenharmony_ci (mem->validation_bits & ~(CPER_MEM_VALID_RANK_NUMBER - 1))) { 3348c2ecf20Sopenharmony_ci pr_err(FW_WARN "valid bits set for fields beyond structure\n"); 3358c2ecf20Sopenharmony_ci return; 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci if (mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS) 3388c2ecf20Sopenharmony_ci printk("%s""error_status: 0x%016llx\n", pfx, mem->error_status); 3398c2ecf20Sopenharmony_ci if (mem->validation_bits & CPER_MEM_VALID_PA) 3408c2ecf20Sopenharmony_ci printk("%s""physical_address: 0x%016llx\n", 3418c2ecf20Sopenharmony_ci pfx, mem->physical_addr); 3428c2ecf20Sopenharmony_ci if (mem->validation_bits & CPER_MEM_VALID_PA_MASK) 3438c2ecf20Sopenharmony_ci printk("%s""physical_address_mask: 0x%016llx\n", 3448c2ecf20Sopenharmony_ci pfx, mem->physical_addr_mask); 3458c2ecf20Sopenharmony_ci cper_mem_err_pack(mem, &cmem); 3468c2ecf20Sopenharmony_ci if (cper_mem_err_location(&cmem, rcd_decode_str)) 3478c2ecf20Sopenharmony_ci printk("%s%s\n", pfx, rcd_decode_str); 3488c2ecf20Sopenharmony_ci if (mem->validation_bits & CPER_MEM_VALID_ERROR_TYPE) { 3498c2ecf20Sopenharmony_ci u8 etype = mem->error_type; 3508c2ecf20Sopenharmony_ci printk("%s""error_type: %d, %s\n", pfx, etype, 3518c2ecf20Sopenharmony_ci cper_mem_err_type_str(etype)); 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci if (cper_dimm_err_location(&cmem, rcd_decode_str)) 3548c2ecf20Sopenharmony_ci printk("%s%s\n", pfx, rcd_decode_str); 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cistatic const char * const pcie_port_type_strs[] = { 3588c2ecf20Sopenharmony_ci "PCIe end point", 3598c2ecf20Sopenharmony_ci "legacy PCI end point", 3608c2ecf20Sopenharmony_ci "unknown", 3618c2ecf20Sopenharmony_ci "unknown", 3628c2ecf20Sopenharmony_ci "root port", 3638c2ecf20Sopenharmony_ci "upstream switch port", 3648c2ecf20Sopenharmony_ci "downstream switch port", 3658c2ecf20Sopenharmony_ci "PCIe to PCI/PCI-X bridge", 3668c2ecf20Sopenharmony_ci "PCI/PCI-X to PCIe bridge", 3678c2ecf20Sopenharmony_ci "root complex integrated endpoint device", 3688c2ecf20Sopenharmony_ci "root complex event collector", 3698c2ecf20Sopenharmony_ci}; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_cistatic void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie, 3728c2ecf20Sopenharmony_ci const struct acpi_hest_generic_data *gdata) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE) 3758c2ecf20Sopenharmony_ci printk("%s""port_type: %d, %s\n", pfx, pcie->port_type, 3768c2ecf20Sopenharmony_ci pcie->port_type < ARRAY_SIZE(pcie_port_type_strs) ? 3778c2ecf20Sopenharmony_ci pcie_port_type_strs[pcie->port_type] : "unknown"); 3788c2ecf20Sopenharmony_ci if (pcie->validation_bits & CPER_PCIE_VALID_VERSION) 3798c2ecf20Sopenharmony_ci printk("%s""version: %d.%d\n", pfx, 3808c2ecf20Sopenharmony_ci pcie->version.major, pcie->version.minor); 3818c2ecf20Sopenharmony_ci if (pcie->validation_bits & CPER_PCIE_VALID_COMMAND_STATUS) 3828c2ecf20Sopenharmony_ci printk("%s""command: 0x%04x, status: 0x%04x\n", pfx, 3838c2ecf20Sopenharmony_ci pcie->command, pcie->status); 3848c2ecf20Sopenharmony_ci if (pcie->validation_bits & CPER_PCIE_VALID_DEVICE_ID) { 3858c2ecf20Sopenharmony_ci const __u8 *p; 3868c2ecf20Sopenharmony_ci printk("%s""device_id: %04x:%02x:%02x.%x\n", pfx, 3878c2ecf20Sopenharmony_ci pcie->device_id.segment, pcie->device_id.bus, 3888c2ecf20Sopenharmony_ci pcie->device_id.device, pcie->device_id.function); 3898c2ecf20Sopenharmony_ci printk("%s""slot: %d\n", pfx, 3908c2ecf20Sopenharmony_ci pcie->device_id.slot >> CPER_PCIE_SLOT_SHIFT); 3918c2ecf20Sopenharmony_ci printk("%s""secondary_bus: 0x%02x\n", pfx, 3928c2ecf20Sopenharmony_ci pcie->device_id.secondary_bus); 3938c2ecf20Sopenharmony_ci printk("%s""vendor_id: 0x%04x, device_id: 0x%04x\n", pfx, 3948c2ecf20Sopenharmony_ci pcie->device_id.vendor_id, pcie->device_id.device_id); 3958c2ecf20Sopenharmony_ci p = pcie->device_id.class_code; 3968c2ecf20Sopenharmony_ci printk("%s""class_code: %02x%02x%02x\n", pfx, p[2], p[1], p[0]); 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci if (pcie->validation_bits & CPER_PCIE_VALID_SERIAL_NUMBER) 3998c2ecf20Sopenharmony_ci printk("%s""serial number: 0x%04x, 0x%04x\n", pfx, 4008c2ecf20Sopenharmony_ci pcie->serial_number.lower, pcie->serial_number.upper); 4018c2ecf20Sopenharmony_ci if (pcie->validation_bits & CPER_PCIE_VALID_BRIDGE_CONTROL_STATUS) 4028c2ecf20Sopenharmony_ci printk( 4038c2ecf20Sopenharmony_ci "%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n", 4048c2ecf20Sopenharmony_ci pfx, pcie->bridge.secondary_status, pcie->bridge.control); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci /* Fatal errors call __ghes_panic() before AER handler prints this */ 4078c2ecf20Sopenharmony_ci if ((pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) && 4088c2ecf20Sopenharmony_ci (gdata->error_severity & CPER_SEV_FATAL)) { 4098c2ecf20Sopenharmony_ci struct aer_capability_regs *aer; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci aer = (struct aer_capability_regs *)pcie->aer_info; 4128c2ecf20Sopenharmony_ci printk("%saer_uncor_status: 0x%08x, aer_uncor_mask: 0x%08x\n", 4138c2ecf20Sopenharmony_ci pfx, aer->uncor_status, aer->uncor_mask); 4148c2ecf20Sopenharmony_ci printk("%saer_uncor_severity: 0x%08x\n", 4158c2ecf20Sopenharmony_ci pfx, aer->uncor_severity); 4168c2ecf20Sopenharmony_ci printk("%sTLP Header: %08x %08x %08x %08x\n", pfx, 4178c2ecf20Sopenharmony_ci aer->header_log.dw0, aer->header_log.dw1, 4188c2ecf20Sopenharmony_ci aer->header_log.dw2, aer->header_log.dw3); 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_cistatic const char * const fw_err_rec_type_strs[] = { 4238c2ecf20Sopenharmony_ci "IPF SAL Error Record", 4248c2ecf20Sopenharmony_ci "SOC Firmware Error Record Type1 (Legacy CrashLog Support)", 4258c2ecf20Sopenharmony_ci "SOC Firmware Error Record Type2", 4268c2ecf20Sopenharmony_ci}; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_cistatic void cper_print_fw_err(const char *pfx, 4298c2ecf20Sopenharmony_ci struct acpi_hest_generic_data *gdata, 4308c2ecf20Sopenharmony_ci const struct cper_sec_fw_err_rec_ref *fw_err) 4318c2ecf20Sopenharmony_ci{ 4328c2ecf20Sopenharmony_ci void *buf = acpi_hest_get_payload(gdata); 4338c2ecf20Sopenharmony_ci u32 offset, length = gdata->error_data_length; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci printk("%s""Firmware Error Record Type: %s\n", pfx, 4368c2ecf20Sopenharmony_ci fw_err->record_type < ARRAY_SIZE(fw_err_rec_type_strs) ? 4378c2ecf20Sopenharmony_ci fw_err_rec_type_strs[fw_err->record_type] : "unknown"); 4388c2ecf20Sopenharmony_ci printk("%s""Revision: %d\n", pfx, fw_err->revision); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci /* Record Type based on UEFI 2.7 */ 4418c2ecf20Sopenharmony_ci if (fw_err->revision == 0) { 4428c2ecf20Sopenharmony_ci printk("%s""Record Identifier: %08llx\n", pfx, 4438c2ecf20Sopenharmony_ci fw_err->record_identifier); 4448c2ecf20Sopenharmony_ci } else if (fw_err->revision == 2) { 4458c2ecf20Sopenharmony_ci printk("%s""Record Identifier: %pUl\n", pfx, 4468c2ecf20Sopenharmony_ci &fw_err->record_identifier_guid); 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci /* 4508c2ecf20Sopenharmony_ci * The FW error record may contain trailing data beyond the 4518c2ecf20Sopenharmony_ci * structure defined by the specification. As the fields 4528c2ecf20Sopenharmony_ci * defined (and hence the offset of any trailing data) vary 4538c2ecf20Sopenharmony_ci * with the revision, set the offset to account for this 4548c2ecf20Sopenharmony_ci * variation. 4558c2ecf20Sopenharmony_ci */ 4568c2ecf20Sopenharmony_ci if (fw_err->revision == 0) { 4578c2ecf20Sopenharmony_ci /* record_identifier_guid not defined */ 4588c2ecf20Sopenharmony_ci offset = offsetof(struct cper_sec_fw_err_rec_ref, 4598c2ecf20Sopenharmony_ci record_identifier_guid); 4608c2ecf20Sopenharmony_ci } else if (fw_err->revision == 1) { 4618c2ecf20Sopenharmony_ci /* record_identifier not defined */ 4628c2ecf20Sopenharmony_ci offset = offsetof(struct cper_sec_fw_err_rec_ref, 4638c2ecf20Sopenharmony_ci record_identifier); 4648c2ecf20Sopenharmony_ci } else { 4658c2ecf20Sopenharmony_ci offset = sizeof(*fw_err); 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci buf += offset; 4698c2ecf20Sopenharmony_ci length -= offset; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci print_hex_dump(pfx, "", DUMP_PREFIX_OFFSET, 16, 4, buf, length, true); 4728c2ecf20Sopenharmony_ci} 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_cistatic void cper_print_tstamp(const char *pfx, 4758c2ecf20Sopenharmony_ci struct acpi_hest_generic_data_v300 *gdata) 4768c2ecf20Sopenharmony_ci{ 4778c2ecf20Sopenharmony_ci __u8 hour, min, sec, day, mon, year, century, *timestamp; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci if (gdata->validation_bits & ACPI_HEST_GEN_VALID_TIMESTAMP) { 4808c2ecf20Sopenharmony_ci timestamp = (__u8 *)&(gdata->time_stamp); 4818c2ecf20Sopenharmony_ci sec = bcd2bin(timestamp[0]); 4828c2ecf20Sopenharmony_ci min = bcd2bin(timestamp[1]); 4838c2ecf20Sopenharmony_ci hour = bcd2bin(timestamp[2]); 4848c2ecf20Sopenharmony_ci day = bcd2bin(timestamp[4]); 4858c2ecf20Sopenharmony_ci mon = bcd2bin(timestamp[5]); 4868c2ecf20Sopenharmony_ci year = bcd2bin(timestamp[6]); 4878c2ecf20Sopenharmony_ci century = bcd2bin(timestamp[7]); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci printk("%s%ststamp: %02d%02d-%02d-%02d %02d:%02d:%02d\n", pfx, 4908c2ecf20Sopenharmony_ci (timestamp[3] & 0x1 ? "precise " : "imprecise "), 4918c2ecf20Sopenharmony_ci century, year, mon, day, hour, min, sec); 4928c2ecf20Sopenharmony_ci } 4938c2ecf20Sopenharmony_ci} 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_cistatic void 4968c2ecf20Sopenharmony_cicper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata, 4978c2ecf20Sopenharmony_ci int sec_no) 4988c2ecf20Sopenharmony_ci{ 4998c2ecf20Sopenharmony_ci guid_t *sec_type = (guid_t *)gdata->section_type; 5008c2ecf20Sopenharmony_ci __u16 severity; 5018c2ecf20Sopenharmony_ci char newpfx[64]; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci if (acpi_hest_get_version(gdata) >= 3) 5048c2ecf20Sopenharmony_ci cper_print_tstamp(pfx, (struct acpi_hest_generic_data_v300 *)gdata); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci severity = gdata->error_severity; 5078c2ecf20Sopenharmony_ci printk("%s""Error %d, type: %s\n", pfx, sec_no, 5088c2ecf20Sopenharmony_ci cper_severity_str(severity)); 5098c2ecf20Sopenharmony_ci if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID) 5108c2ecf20Sopenharmony_ci printk("%s""fru_id: %pUl\n", pfx, gdata->fru_id); 5118c2ecf20Sopenharmony_ci if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT) 5128c2ecf20Sopenharmony_ci printk("%s""fru_text: %.20s\n", pfx, gdata->fru_text); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci snprintf(newpfx, sizeof(newpfx), "%s ", pfx); 5158c2ecf20Sopenharmony_ci if (guid_equal(sec_type, &CPER_SEC_PROC_GENERIC)) { 5168c2ecf20Sopenharmony_ci struct cper_sec_proc_generic *proc_err = acpi_hest_get_payload(gdata); 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci printk("%s""section_type: general processor error\n", newpfx); 5198c2ecf20Sopenharmony_ci if (gdata->error_data_length >= sizeof(*proc_err)) 5208c2ecf20Sopenharmony_ci cper_print_proc_generic(newpfx, proc_err); 5218c2ecf20Sopenharmony_ci else 5228c2ecf20Sopenharmony_ci goto err_section_too_small; 5238c2ecf20Sopenharmony_ci } else if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) { 5248c2ecf20Sopenharmony_ci struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci printk("%s""section_type: memory error\n", newpfx); 5278c2ecf20Sopenharmony_ci if (gdata->error_data_length >= 5288c2ecf20Sopenharmony_ci sizeof(struct cper_sec_mem_err_old)) 5298c2ecf20Sopenharmony_ci cper_print_mem(newpfx, mem_err, 5308c2ecf20Sopenharmony_ci gdata->error_data_length); 5318c2ecf20Sopenharmony_ci else 5328c2ecf20Sopenharmony_ci goto err_section_too_small; 5338c2ecf20Sopenharmony_ci } else if (guid_equal(sec_type, &CPER_SEC_PCIE)) { 5348c2ecf20Sopenharmony_ci struct cper_sec_pcie *pcie = acpi_hest_get_payload(gdata); 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci printk("%s""section_type: PCIe error\n", newpfx); 5378c2ecf20Sopenharmony_ci if (gdata->error_data_length >= sizeof(*pcie)) 5388c2ecf20Sopenharmony_ci cper_print_pcie(newpfx, pcie, gdata); 5398c2ecf20Sopenharmony_ci else 5408c2ecf20Sopenharmony_ci goto err_section_too_small; 5418c2ecf20Sopenharmony_ci#if defined(CONFIG_ARM64) || defined(CONFIG_ARM) 5428c2ecf20Sopenharmony_ci } else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) { 5438c2ecf20Sopenharmony_ci struct cper_sec_proc_arm *arm_err = acpi_hest_get_payload(gdata); 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci printk("%ssection_type: ARM processor error\n", newpfx); 5468c2ecf20Sopenharmony_ci if (gdata->error_data_length >= sizeof(*arm_err)) 5478c2ecf20Sopenharmony_ci cper_print_proc_arm(newpfx, arm_err); 5488c2ecf20Sopenharmony_ci else 5498c2ecf20Sopenharmony_ci goto err_section_too_small; 5508c2ecf20Sopenharmony_ci#endif 5518c2ecf20Sopenharmony_ci#if defined(CONFIG_UEFI_CPER_X86) 5528c2ecf20Sopenharmony_ci } else if (guid_equal(sec_type, &CPER_SEC_PROC_IA)) { 5538c2ecf20Sopenharmony_ci struct cper_sec_proc_ia *ia_err = acpi_hest_get_payload(gdata); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci printk("%ssection_type: IA32/X64 processor error\n", newpfx); 5568c2ecf20Sopenharmony_ci if (gdata->error_data_length >= sizeof(*ia_err)) 5578c2ecf20Sopenharmony_ci cper_print_proc_ia(newpfx, ia_err); 5588c2ecf20Sopenharmony_ci else 5598c2ecf20Sopenharmony_ci goto err_section_too_small; 5608c2ecf20Sopenharmony_ci#endif 5618c2ecf20Sopenharmony_ci } else if (guid_equal(sec_type, &CPER_SEC_FW_ERR_REC_REF)) { 5628c2ecf20Sopenharmony_ci struct cper_sec_fw_err_rec_ref *fw_err = acpi_hest_get_payload(gdata); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci printk("%ssection_type: Firmware Error Record Reference\n", 5658c2ecf20Sopenharmony_ci newpfx); 5668c2ecf20Sopenharmony_ci /* The minimal FW Error Record contains 16 bytes */ 5678c2ecf20Sopenharmony_ci if (gdata->error_data_length >= SZ_16) 5688c2ecf20Sopenharmony_ci cper_print_fw_err(newpfx, gdata, fw_err); 5698c2ecf20Sopenharmony_ci else 5708c2ecf20Sopenharmony_ci goto err_section_too_small; 5718c2ecf20Sopenharmony_ci } else { 5728c2ecf20Sopenharmony_ci const void *err = acpi_hest_get_payload(gdata); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci printk("%ssection type: unknown, %pUl\n", newpfx, sec_type); 5758c2ecf20Sopenharmony_ci printk("%ssection length: %#x\n", newpfx, 5768c2ecf20Sopenharmony_ci gdata->error_data_length); 5778c2ecf20Sopenharmony_ci print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, err, 5788c2ecf20Sopenharmony_ci gdata->error_data_length, true); 5798c2ecf20Sopenharmony_ci } 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci return; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_cierr_section_too_small: 5848c2ecf20Sopenharmony_ci pr_err(FW_WARN "error section length is too small\n"); 5858c2ecf20Sopenharmony_ci} 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_civoid cper_estatus_print(const char *pfx, 5888c2ecf20Sopenharmony_ci const struct acpi_hest_generic_status *estatus) 5898c2ecf20Sopenharmony_ci{ 5908c2ecf20Sopenharmony_ci struct acpi_hest_generic_data *gdata; 5918c2ecf20Sopenharmony_ci int sec_no = 0; 5928c2ecf20Sopenharmony_ci char newpfx[64]; 5938c2ecf20Sopenharmony_ci __u16 severity; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci severity = estatus->error_severity; 5968c2ecf20Sopenharmony_ci if (severity == CPER_SEV_CORRECTED) 5978c2ecf20Sopenharmony_ci printk("%s%s\n", pfx, 5988c2ecf20Sopenharmony_ci "It has been corrected by h/w " 5998c2ecf20Sopenharmony_ci "and requires no further action"); 6008c2ecf20Sopenharmony_ci printk("%s""event severity: %s\n", pfx, cper_severity_str(severity)); 6018c2ecf20Sopenharmony_ci snprintf(newpfx, sizeof(newpfx), "%s ", pfx); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci apei_estatus_for_each_section(estatus, gdata) { 6048c2ecf20Sopenharmony_ci cper_estatus_print_section(newpfx, gdata, sec_no); 6058c2ecf20Sopenharmony_ci sec_no++; 6068c2ecf20Sopenharmony_ci } 6078c2ecf20Sopenharmony_ci} 6088c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cper_estatus_print); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ciint cper_estatus_check_header(const struct acpi_hest_generic_status *estatus) 6118c2ecf20Sopenharmony_ci{ 6128c2ecf20Sopenharmony_ci if (estatus->data_length && 6138c2ecf20Sopenharmony_ci estatus->data_length < sizeof(struct acpi_hest_generic_data)) 6148c2ecf20Sopenharmony_ci return -EINVAL; 6158c2ecf20Sopenharmony_ci if (estatus->raw_data_length && 6168c2ecf20Sopenharmony_ci estatus->raw_data_offset < sizeof(*estatus) + estatus->data_length) 6178c2ecf20Sopenharmony_ci return -EINVAL; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci return 0; 6208c2ecf20Sopenharmony_ci} 6218c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cper_estatus_check_header); 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ciint cper_estatus_check(const struct acpi_hest_generic_status *estatus) 6248c2ecf20Sopenharmony_ci{ 6258c2ecf20Sopenharmony_ci struct acpi_hest_generic_data *gdata; 6268c2ecf20Sopenharmony_ci unsigned int data_len, record_size; 6278c2ecf20Sopenharmony_ci int rc; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci rc = cper_estatus_check_header(estatus); 6308c2ecf20Sopenharmony_ci if (rc) 6318c2ecf20Sopenharmony_ci return rc; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci data_len = estatus->data_length; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci apei_estatus_for_each_section(estatus, gdata) { 6368c2ecf20Sopenharmony_ci if (sizeof(struct acpi_hest_generic_data) > data_len) 6378c2ecf20Sopenharmony_ci return -EINVAL; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci record_size = acpi_hest_get_record_size(gdata); 6408c2ecf20Sopenharmony_ci if (record_size > data_len) 6418c2ecf20Sopenharmony_ci return -EINVAL; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci data_len -= record_size; 6448c2ecf20Sopenharmony_ci } 6458c2ecf20Sopenharmony_ci if (data_len) 6468c2ecf20Sopenharmony_ci return -EINVAL; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci return 0; 6498c2ecf20Sopenharmony_ci} 6508c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cper_estatus_check); 651