Linux Audio

Check our new training course

Loading...
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * UEFI Common Platform Error Record (CPER) support
  4 *
  5 * Copyright (C) 2010, Intel Corp.
  6 *	Author: Huang Ying <ying.huang@intel.com>
  7 *
  8 * CPER is the format used to describe platform hardware error by
  9 * various tables, such as ERST, BERT and HEST etc.
 10 *
 11 * For more information about CPER, please refer to Appendix N of UEFI
 12 * Specification version 2.4.
 
 
 
 
 
 
 
 
 
 
 
 
 
 13 */
 14
 15#include <linux/kernel.h>
 16#include <linux/module.h>
 17#include <linux/time.h>
 18#include <linux/cper.h>
 19#include <linux/dmi.h>
 20#include <linux/acpi.h>
 21#include <linux/pci.h>
 22#include <linux/aer.h>
 23#include <linux/printk.h>
 24#include <linux/bcd.h>
 25#include <acpi/ghes.h>
 26#include <ras/ras_event.h>
 27#include "cper_cxl.h"
 
 
 
 28
 29/*
 30 * CPER record ID need to be unique even after reboot, because record
 31 * ID is used as index for ERST storage, while CPER records from
 32 * multiple boot may co-exist in ERST.
 33 */
 34u64 cper_next_record_id(void)
 35{
 36	static atomic64_t seq;
 37
 38	if (!atomic64_read(&seq)) {
 39		time64_t time = ktime_get_real_seconds();
 40
 41		/*
 42		 * This code is unlikely to still be needed in year 2106,
 43		 * but just in case, let's use a few more bits for timestamps
 44		 * after y2038 to be sure they keep increasing monotonically
 45		 * for the next few hundred years...
 46		 */
 47		if (time < 0x80000000)
 48			atomic64_set(&seq, (ktime_get_real_seconds()) << 32);
 49		else
 50			atomic64_set(&seq, 0x8000000000000000ull |
 51					   ktime_get_real_seconds() << 24);
 52	}
 53
 54	return atomic64_inc_return(&seq);
 55}
 56EXPORT_SYMBOL_GPL(cper_next_record_id);
 57
 58static const char * const severity_strs[] = {
 59	"recoverable",
 60	"fatal",
 61	"corrected",
 62	"info",
 63};
 64
 65const char *cper_severity_str(unsigned int severity)
 66{
 67	return severity < ARRAY_SIZE(severity_strs) ?
 68		severity_strs[severity] : "unknown";
 69}
 70EXPORT_SYMBOL_GPL(cper_severity_str);
 71
 72/*
 73 * cper_print_bits - print strings for set bits
 74 * @pfx: prefix for each line, including log level and prefix string
 75 * @bits: bit mask
 76 * @strs: string array, indexed by bit position
 77 * @strs_size: size of the string array: @strs
 78 *
 79 * For each set bit in @bits, print the corresponding string in @strs.
 80 * If the output length is longer than 80, multiple line will be
 81 * printed, with @pfx is printed at the beginning of each line.
 82 */
 83void cper_print_bits(const char *pfx, unsigned int bits,
 84		     const char * const strs[], unsigned int strs_size)
 85{
 86	int i, len = 0;
 87	const char *str;
 88	char buf[84];
 89
 90	for (i = 0; i < strs_size; i++) {
 91		if (!(bits & (1U << i)))
 92			continue;
 93		str = strs[i];
 94		if (!str)
 95			continue;
 96		if (len && len + strlen(str) + 2 > 80) {
 97			printk("%s\n", buf);
 98			len = 0;
 99		}
100		if (!len)
101			len = snprintf(buf, sizeof(buf), "%s%s", pfx, str);
102		else
103			len += scnprintf(buf+len, sizeof(buf)-len, ", %s", str);
104	}
105	if (len)
106		printk("%s\n", buf);
107}
108
109static const char * const proc_type_strs[] = {
110	"IA32/X64",
111	"IA64",
112	"ARM",
113};
114
115static const char * const proc_isa_strs[] = {
116	"IA32",
117	"IA64",
118	"X64",
119	"ARM A32/T32",
120	"ARM A64",
121};
122
123const char * const cper_proc_error_type_strs[] = {
124	"cache error",
125	"TLB error",
126	"bus error",
127	"micro-architectural error",
128};
129
130static const char * const proc_op_strs[] = {
131	"unknown or generic",
132	"data read",
133	"data write",
134	"instruction execution",
135};
136
137static const char * const proc_flag_strs[] = {
138	"restartable",
139	"precise IP",
140	"overflow",
141	"corrected",
142};
143
144static void cper_print_proc_generic(const char *pfx,
145				    const struct cper_sec_proc_generic *proc)
146{
147	if (proc->validation_bits & CPER_PROC_VALID_TYPE)
148		printk("%s""processor_type: %d, %s\n", pfx, proc->proc_type,
149		       proc->proc_type < ARRAY_SIZE(proc_type_strs) ?
150		       proc_type_strs[proc->proc_type] : "unknown");
151	if (proc->validation_bits & CPER_PROC_VALID_ISA)
152		printk("%s""processor_isa: %d, %s\n", pfx, proc->proc_isa,
153		       proc->proc_isa < ARRAY_SIZE(proc_isa_strs) ?
154		       proc_isa_strs[proc->proc_isa] : "unknown");
155	if (proc->validation_bits & CPER_PROC_VALID_ERROR_TYPE) {
156		printk("%s""error_type: 0x%02x\n", pfx, proc->proc_error_type);
157		cper_print_bits(pfx, proc->proc_error_type,
158				cper_proc_error_type_strs,
159				ARRAY_SIZE(cper_proc_error_type_strs));
160	}
161	if (proc->validation_bits & CPER_PROC_VALID_OPERATION)
162		printk("%s""operation: %d, %s\n", pfx, proc->operation,
163		       proc->operation < ARRAY_SIZE(proc_op_strs) ?
164		       proc_op_strs[proc->operation] : "unknown");
165	if (proc->validation_bits & CPER_PROC_VALID_FLAGS) {
166		printk("%s""flags: 0x%02x\n", pfx, proc->flags);
167		cper_print_bits(pfx, proc->flags, proc_flag_strs,
168				ARRAY_SIZE(proc_flag_strs));
169	}
170	if (proc->validation_bits & CPER_PROC_VALID_LEVEL)
171		printk("%s""level: %d\n", pfx, proc->level);
172	if (proc->validation_bits & CPER_PROC_VALID_VERSION)
173		printk("%s""version_info: 0x%016llx\n", pfx, proc->cpu_version);
174	if (proc->validation_bits & CPER_PROC_VALID_ID)
175		printk("%s""processor_id: 0x%016llx\n", pfx, proc->proc_id);
176	if (proc->validation_bits & CPER_PROC_VALID_TARGET_ADDRESS)
177		printk("%s""target_address: 0x%016llx\n",
178		       pfx, proc->target_addr);
179	if (proc->validation_bits & CPER_PROC_VALID_REQUESTOR_ID)
180		printk("%s""requestor_id: 0x%016llx\n",
181		       pfx, proc->requestor_id);
182	if (proc->validation_bits & CPER_PROC_VALID_RESPONDER_ID)
183		printk("%s""responder_id: 0x%016llx\n",
184		       pfx, proc->responder_id);
185	if (proc->validation_bits & CPER_PROC_VALID_IP)
186		printk("%s""IP: 0x%016llx\n", pfx, proc->ip);
187}
188
189static const char * const mem_err_type_strs[] = {
190	"unknown",
191	"no error",
192	"single-bit ECC",
193	"multi-bit ECC",
194	"single-symbol chipkill ECC",
195	"multi-symbol chipkill ECC",
196	"master abort",
197	"target abort",
198	"parity error",
199	"watchdog timeout",
200	"invalid address",
201	"mirror Broken",
202	"memory sparing",
203	"scrub corrected error",
204	"scrub uncorrected error",
205	"physical memory map-out event",
206};
207
208const char *cper_mem_err_type_str(unsigned int etype)
209{
210	return etype < ARRAY_SIZE(mem_err_type_strs) ?
211		mem_err_type_strs[etype] : "unknown";
212}
213EXPORT_SYMBOL_GPL(cper_mem_err_type_str);
214
215const char *cper_mem_err_status_str(u64 status)
216{
217	switch ((status >> 8) & 0xff) {
218	case  1:	return "Error detected internal to the component";
219	case  4:	return "Storage error in DRAM memory";
220	case  5:	return "Storage error in TLB";
221	case  6:	return "Storage error in cache";
222	case  7:	return "Error in one or more functional units";
223	case  8:	return "Component failed self test";
224	case  9:	return "Overflow or undervalue of internal queue";
225	case 16:	return "Error detected in the bus";
226	case 17:	return "Virtual address not found on IO-TLB or IO-PDIR";
227	case 18:	return "Improper access error";
228	case 19:	return "Access to a memory address which is not mapped to any component";
229	case 20:	return "Loss of Lockstep";
230	case 21:	return "Response not associated with a request";
231	case 22:	return "Bus parity error - must also set the A, C, or D Bits";
232	case 23:	return "Detection of a protocol error";
233	case 24:	return "Detection of a PATH_ERROR";
234	case 25:	return "Bus operation timeout";
235	case 26:	return "A read was issued to data that has been poisoned";
236	default:	return "Reserved";
237	}
238}
239EXPORT_SYMBOL_GPL(cper_mem_err_status_str);
240
241int cper_mem_err_location(struct cper_mem_err_compact *mem, char *msg)
242{
243	u32 len, n;
244
245	if (!msg)
246		return 0;
247
248	n = 0;
249	len = CPER_REC_LEN;
250	if (mem->validation_bits & CPER_MEM_VALID_NODE)
251		n += scnprintf(msg + n, len - n, "node:%d ", mem->node);
252	if (mem->validation_bits & CPER_MEM_VALID_CARD)
253		n += scnprintf(msg + n, len - n, "card:%d ", mem->card);
254	if (mem->validation_bits & CPER_MEM_VALID_MODULE)
255		n += scnprintf(msg + n, len - n, "module:%d ", mem->module);
256	if (mem->validation_bits & CPER_MEM_VALID_RANK_NUMBER)
257		n += scnprintf(msg + n, len - n, "rank:%d ", mem->rank);
258	if (mem->validation_bits & CPER_MEM_VALID_BANK)
259		n += scnprintf(msg + n, len - n, "bank:%d ", mem->bank);
260	if (mem->validation_bits & CPER_MEM_VALID_BANK_GROUP)
261		n += scnprintf(msg + n, len - n, "bank_group:%d ",
262			       mem->bank >> CPER_MEM_BANK_GROUP_SHIFT);
263	if (mem->validation_bits & CPER_MEM_VALID_BANK_ADDRESS)
264		n += scnprintf(msg + n, len - n, "bank_address:%d ",
265			       mem->bank & CPER_MEM_BANK_ADDRESS_MASK);
266	if (mem->validation_bits & CPER_MEM_VALID_DEVICE)
267		n += scnprintf(msg + n, len - n, "device:%d ", mem->device);
268	if (mem->validation_bits & (CPER_MEM_VALID_ROW | CPER_MEM_VALID_ROW_EXT)) {
269		u32 row = mem->row;
270
271		row |= cper_get_mem_extension(mem->validation_bits, mem->extended);
272		n += scnprintf(msg + n, len - n, "row:%d ", row);
273	}
274	if (mem->validation_bits & CPER_MEM_VALID_COLUMN)
275		n += scnprintf(msg + n, len - n, "column:%d ", mem->column);
276	if (mem->validation_bits & CPER_MEM_VALID_BIT_POSITION)
277		n += scnprintf(msg + n, len - n, "bit_position:%d ",
278			       mem->bit_pos);
279	if (mem->validation_bits & CPER_MEM_VALID_REQUESTOR_ID)
280		n += scnprintf(msg + n, len - n, "requestor_id:0x%016llx ",
281			       mem->requestor_id);
282	if (mem->validation_bits & CPER_MEM_VALID_RESPONDER_ID)
283		n += scnprintf(msg + n, len - n, "responder_id:0x%016llx ",
284			       mem->responder_id);
285	if (mem->validation_bits & CPER_MEM_VALID_TARGET_ID)
286		n += scnprintf(msg + n, len - n, "target_id:0x%016llx ",
287			       mem->target_id);
288	if (mem->validation_bits & CPER_MEM_VALID_CHIP_ID)
289		n += scnprintf(msg + n, len - n, "chip_id:%d ",
290			       mem->extended >> CPER_MEM_CHIP_ID_SHIFT);
291
 
292	return n;
293}
294EXPORT_SYMBOL_GPL(cper_mem_err_location);
295
296int cper_dimm_err_location(struct cper_mem_err_compact *mem, char *msg)
297{
298	u32 len, n;
299	const char *bank = NULL, *device = NULL;
300
301	if (!msg || !(mem->validation_bits & CPER_MEM_VALID_MODULE_HANDLE))
302		return 0;
303
304	len = CPER_REC_LEN;
 
305	dmi_memdev_name(mem->mem_dev_handle, &bank, &device);
306	if (bank && device)
307		n = snprintf(msg, len, "DIMM location: %s %s ", bank, device);
308	else
309		n = snprintf(msg, len,
310			     "DIMM location: not present. DMI handle: 0x%.4x ",
311			     mem->mem_dev_handle);
312
 
313	return n;
314}
315EXPORT_SYMBOL_GPL(cper_dimm_err_location);
316
317void cper_mem_err_pack(const struct cper_sec_mem_err *mem,
318		       struct cper_mem_err_compact *cmem)
319{
320	cmem->validation_bits = mem->validation_bits;
321	cmem->node = mem->node;
322	cmem->card = mem->card;
323	cmem->module = mem->module;
324	cmem->bank = mem->bank;
325	cmem->device = mem->device;
326	cmem->row = mem->row;
327	cmem->column = mem->column;
328	cmem->bit_pos = mem->bit_pos;
329	cmem->requestor_id = mem->requestor_id;
330	cmem->responder_id = mem->responder_id;
331	cmem->target_id = mem->target_id;
332	cmem->extended = mem->extended;
333	cmem->rank = mem->rank;
334	cmem->mem_array_handle = mem->mem_array_handle;
335	cmem->mem_dev_handle = mem->mem_dev_handle;
336}
337EXPORT_SYMBOL_GPL(cper_mem_err_pack);
338
339const char *cper_mem_err_unpack(struct trace_seq *p,
340				struct cper_mem_err_compact *cmem)
341{
342	const char *ret = trace_seq_buffer_ptr(p);
343	char rcd_decode_str[CPER_REC_LEN];
344
345	if (cper_mem_err_location(cmem, rcd_decode_str))
346		trace_seq_printf(p, "%s", rcd_decode_str);
347	if (cper_dimm_err_location(cmem, rcd_decode_str))
348		trace_seq_printf(p, "%s", rcd_decode_str);
349	trace_seq_putc(p, '\0');
350
351	return ret;
352}
353
354static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem,
355	int len)
356{
357	struct cper_mem_err_compact cmem;
358	char rcd_decode_str[CPER_REC_LEN];
359
360	/* Don't trust UEFI 2.1/2.2 structure with bad validation bits */
361	if (len == sizeof(struct cper_sec_mem_err_old) &&
362	    (mem->validation_bits & ~(CPER_MEM_VALID_RANK_NUMBER - 1))) {
363		pr_err(FW_WARN "valid bits set for fields beyond structure\n");
364		return;
365	}
366	if (mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS)
367		printk("%s error_status: %s (0x%016llx)\n",
368		       pfx, cper_mem_err_status_str(mem->error_status),
369		       mem->error_status);
370	if (mem->validation_bits & CPER_MEM_VALID_PA)
371		printk("%s""physical_address: 0x%016llx\n",
372		       pfx, mem->physical_addr);
373	if (mem->validation_bits & CPER_MEM_VALID_PA_MASK)
374		printk("%s""physical_address_mask: 0x%016llx\n",
375		       pfx, mem->physical_addr_mask);
376	cper_mem_err_pack(mem, &cmem);
377	if (cper_mem_err_location(&cmem, rcd_decode_str))
378		printk("%s%s\n", pfx, rcd_decode_str);
379	if (mem->validation_bits & CPER_MEM_VALID_ERROR_TYPE) {
380		u8 etype = mem->error_type;
381		printk("%s""error_type: %d, %s\n", pfx, etype,
382		       cper_mem_err_type_str(etype));
383	}
384	if (cper_dimm_err_location(&cmem, rcd_decode_str))
385		printk("%s%s\n", pfx, rcd_decode_str);
386}
387
388static const char * const pcie_port_type_strs[] = {
389	"PCIe end point",
390	"legacy PCI end point",
391	"unknown",
392	"unknown",
393	"root port",
394	"upstream switch port",
395	"downstream switch port",
396	"PCIe to PCI/PCI-X bridge",
397	"PCI/PCI-X to PCIe bridge",
398	"root complex integrated endpoint device",
399	"root complex event collector",
400};
401
402static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie,
403			    const struct acpi_hest_generic_data *gdata)
404{
405	if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE)
406		printk("%s""port_type: %d, %s\n", pfx, pcie->port_type,
407		       pcie->port_type < ARRAY_SIZE(pcie_port_type_strs) ?
408		       pcie_port_type_strs[pcie->port_type] : "unknown");
409	if (pcie->validation_bits & CPER_PCIE_VALID_VERSION)
410		printk("%s""version: %d.%d\n", pfx,
411		       pcie->version.major, pcie->version.minor);
412	if (pcie->validation_bits & CPER_PCIE_VALID_COMMAND_STATUS)
413		printk("%s""command: 0x%04x, status: 0x%04x\n", pfx,
414		       pcie->command, pcie->status);
415	if (pcie->validation_bits & CPER_PCIE_VALID_DEVICE_ID) {
416		const __u8 *p;
417		printk("%s""device_id: %04x:%02x:%02x.%x\n", pfx,
418		       pcie->device_id.segment, pcie->device_id.bus,
419		       pcie->device_id.device, pcie->device_id.function);
420		printk("%s""slot: %d\n", pfx,
421		       pcie->device_id.slot >> CPER_PCIE_SLOT_SHIFT);
422		printk("%s""secondary_bus: 0x%02x\n", pfx,
423		       pcie->device_id.secondary_bus);
424		printk("%s""vendor_id: 0x%04x, device_id: 0x%04x\n", pfx,
425		       pcie->device_id.vendor_id, pcie->device_id.device_id);
426		p = pcie->device_id.class_code;
427		printk("%s""class_code: %02x%02x%02x\n", pfx, p[2], p[1], p[0]);
428	}
429	if (pcie->validation_bits & CPER_PCIE_VALID_SERIAL_NUMBER)
430		printk("%s""serial number: 0x%04x, 0x%04x\n", pfx,
431		       pcie->serial_number.lower, pcie->serial_number.upper);
432	if (pcie->validation_bits & CPER_PCIE_VALID_BRIDGE_CONTROL_STATUS)
433		printk(
434	"%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n",
435	pfx, pcie->bridge.secondary_status, pcie->bridge.control);
436
437	/*
438	 * Print all valid AER info. Record may be from BERT (boot-time) or GHES (run-time).
439	 *
440	 * Fatal errors call __ghes_panic() before AER handler prints this.
441	 */
442	if (pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) {
443		struct aer_capability_regs *aer;
444
445		aer = (struct aer_capability_regs *)pcie->aer_info;
446		printk("%saer_cor_status: 0x%08x, aer_cor_mask: 0x%08x\n",
447		       pfx, aer->cor_status, aer->cor_mask);
448		printk("%saer_uncor_status: 0x%08x, aer_uncor_mask: 0x%08x\n",
449		       pfx, aer->uncor_status, aer->uncor_mask);
450		printk("%saer_uncor_severity: 0x%08x\n",
451		       pfx, aer->uncor_severity);
452		printk("%sTLP Header: %08x %08x %08x %08x\n", pfx,
453		       aer->header_log.dw[0], aer->header_log.dw[1],
454		       aer->header_log.dw[2], aer->header_log.dw[3]);
455	}
456}
457
458static const char * const fw_err_rec_type_strs[] = {
459	"IPF SAL Error Record",
460	"SOC Firmware Error Record Type1 (Legacy CrashLog Support)",
461	"SOC Firmware Error Record Type2",
462};
463
464static void cper_print_fw_err(const char *pfx,
465			      struct acpi_hest_generic_data *gdata,
466			      const struct cper_sec_fw_err_rec_ref *fw_err)
467{
468	void *buf = acpi_hest_get_payload(gdata);
469	u32 offset, length = gdata->error_data_length;
470
471	printk("%s""Firmware Error Record Type: %s\n", pfx,
472	       fw_err->record_type < ARRAY_SIZE(fw_err_rec_type_strs) ?
473	       fw_err_rec_type_strs[fw_err->record_type] : "unknown");
474	printk("%s""Revision: %d\n", pfx, fw_err->revision);
475
476	/* Record Type based on UEFI 2.7 */
477	if (fw_err->revision == 0) {
478		printk("%s""Record Identifier: %08llx\n", pfx,
479		       fw_err->record_identifier);
480	} else if (fw_err->revision == 2) {
481		printk("%s""Record Identifier: %pUl\n", pfx,
482		       &fw_err->record_identifier_guid);
483	}
484
485	/*
486	 * The FW error record may contain trailing data beyond the
487	 * structure defined by the specification. As the fields
488	 * defined (and hence the offset of any trailing data) vary
489	 * with the revision, set the offset to account for this
490	 * variation.
491	 */
492	if (fw_err->revision == 0) {
493		/* record_identifier_guid not defined */
494		offset = offsetof(struct cper_sec_fw_err_rec_ref,
495				  record_identifier_guid);
496	} else if (fw_err->revision == 1) {
497		/* record_identifier not defined */
498		offset = offsetof(struct cper_sec_fw_err_rec_ref,
499				  record_identifier);
500	} else {
501		offset = sizeof(*fw_err);
502	}
503
504	buf += offset;
505	length -= offset;
506
507	print_hex_dump(pfx, "", DUMP_PREFIX_OFFSET, 16, 4, buf, length, true);
508}
509
510static void cper_print_tstamp(const char *pfx,
511				   struct acpi_hest_generic_data_v300 *gdata)
512{
513	__u8 hour, min, sec, day, mon, year, century, *timestamp;
514
515	if (gdata->validation_bits & ACPI_HEST_GEN_VALID_TIMESTAMP) {
516		timestamp = (__u8 *)&(gdata->time_stamp);
517		sec       = bcd2bin(timestamp[0]);
518		min       = bcd2bin(timestamp[1]);
519		hour      = bcd2bin(timestamp[2]);
520		day       = bcd2bin(timestamp[4]);
521		mon       = bcd2bin(timestamp[5]);
522		year      = bcd2bin(timestamp[6]);
523		century   = bcd2bin(timestamp[7]);
524
525		printk("%s%ststamp: %02d%02d-%02d-%02d %02d:%02d:%02d\n", pfx,
526		       (timestamp[3] & 0x1 ? "precise " : "imprecise "),
527		       century, year, mon, day, hour, min, sec);
528	}
529}
530
531struct ignore_section {
532	guid_t guid;
533	const char *name;
534};
535
536static const struct ignore_section ignore_sections[] = {
537	{ .guid = CPER_SEC_CXL_GEN_MEDIA_GUID, .name = "CXL General Media Event" },
538	{ .guid = CPER_SEC_CXL_DRAM_GUID, .name = "CXL DRAM Event" },
539	{ .guid = CPER_SEC_CXL_MEM_MODULE_GUID, .name = "CXL Memory Module Event" },
540};
541
542static void
543cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata,
544			   int sec_no)
545{
546	guid_t *sec_type = (guid_t *)gdata->section_type;
547	__u16 severity;
548	char newpfx[64];
549
550	if (acpi_hest_get_version(gdata) >= 3)
551		cper_print_tstamp(pfx, (struct acpi_hest_generic_data_v300 *)gdata);
552
553	severity = gdata->error_severity;
554	printk("%s""Error %d, type: %s\n", pfx, sec_no,
555	       cper_severity_str(severity));
556	if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID)
557		printk("%s""fru_id: %pUl\n", pfx, gdata->fru_id);
558	if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT)
559		printk("%s""fru_text: %.20s\n", pfx, gdata->fru_text);
560
561	snprintf(newpfx, sizeof(newpfx), "%s ", pfx);
562
563	for (int i = 0; i < ARRAY_SIZE(ignore_sections); i++) {
564		if (guid_equal(sec_type, &ignore_sections[i].guid)) {
565			printk("%ssection_type: %s\n", newpfx, ignore_sections[i].name);
566			return;
567		}
568	}
569
570	if (guid_equal(sec_type, &CPER_SEC_PROC_GENERIC)) {
571		struct cper_sec_proc_generic *proc_err = acpi_hest_get_payload(gdata);
572
573		printk("%s""section_type: general processor error\n", newpfx);
574		if (gdata->error_data_length >= sizeof(*proc_err))
575			cper_print_proc_generic(newpfx, proc_err);
576		else
577			goto err_section_too_small;
578	} else if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) {
579		struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);
580
581		printk("%s""section_type: memory error\n", newpfx);
582		if (gdata->error_data_length >=
583		    sizeof(struct cper_sec_mem_err_old))
584			cper_print_mem(newpfx, mem_err,
585				       gdata->error_data_length);
586		else
587			goto err_section_too_small;
588	} else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
589		struct cper_sec_pcie *pcie = acpi_hest_get_payload(gdata);
590
591		printk("%s""section_type: PCIe error\n", newpfx);
592		if (gdata->error_data_length >= sizeof(*pcie))
593			cper_print_pcie(newpfx, pcie, gdata);
594		else
595			goto err_section_too_small;
596#if defined(CONFIG_ARM64) || defined(CONFIG_ARM)
597	} else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) {
598		struct cper_sec_proc_arm *arm_err = acpi_hest_get_payload(gdata);
599
600		printk("%ssection_type: ARM processor error\n", newpfx);
601		if (gdata->error_data_length >= sizeof(*arm_err))
602			cper_print_proc_arm(newpfx, arm_err);
603		else
604			goto err_section_too_small;
605#endif
606#if defined(CONFIG_UEFI_CPER_X86)
607	} else if (guid_equal(sec_type, &CPER_SEC_PROC_IA)) {
608		struct cper_sec_proc_ia *ia_err = acpi_hest_get_payload(gdata);
609
610		printk("%ssection_type: IA32/X64 processor error\n", newpfx);
611		if (gdata->error_data_length >= sizeof(*ia_err))
612			cper_print_proc_ia(newpfx, ia_err);
613		else
614			goto err_section_too_small;
615#endif
616	} else if (guid_equal(sec_type, &CPER_SEC_FW_ERR_REC_REF)) {
617		struct cper_sec_fw_err_rec_ref *fw_err = acpi_hest_get_payload(gdata);
618
619		printk("%ssection_type: Firmware Error Record Reference\n",
620		       newpfx);
621		/* The minimal FW Error Record contains 16 bytes */
622		if (gdata->error_data_length >= SZ_16)
623			cper_print_fw_err(newpfx, gdata, fw_err);
624		else
625			goto err_section_too_small;
626	} else if (guid_equal(sec_type, &CPER_SEC_CXL_PROT_ERR)) {
627		struct cper_sec_prot_err *prot_err = acpi_hest_get_payload(gdata);
628
629		printk("%ssection_type: CXL Protocol Error\n", newpfx);
630		if (gdata->error_data_length >= sizeof(*prot_err))
631			cper_print_prot_err(newpfx, prot_err);
632		else
633			goto err_section_too_small;
634	} else {
635		const void *err = acpi_hest_get_payload(gdata);
636
637		printk("%ssection type: unknown, %pUl\n", newpfx, sec_type);
638		printk("%ssection length: %#x\n", newpfx,
639		       gdata->error_data_length);
640		print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, err,
641			       gdata->error_data_length, true);
642	}
643
644	return;
645
646err_section_too_small:
647	pr_err(FW_WARN "error section length is too small\n");
648}
649
650void cper_estatus_print(const char *pfx,
651			const struct acpi_hest_generic_status *estatus)
652{
653	struct acpi_hest_generic_data *gdata;
654	int sec_no = 0;
655	char newpfx[64];
656	__u16 severity;
657
658	severity = estatus->error_severity;
659	if (severity == CPER_SEV_CORRECTED)
660		printk("%s%s\n", pfx,
661		       "It has been corrected by h/w "
662		       "and requires no further action");
663	printk("%s""event severity: %s\n", pfx, cper_severity_str(severity));
664	snprintf(newpfx, sizeof(newpfx), "%s ", pfx);
665
666	apei_estatus_for_each_section(estatus, gdata) {
667		cper_estatus_print_section(newpfx, gdata, sec_no);
668		sec_no++;
669	}
670}
671EXPORT_SYMBOL_GPL(cper_estatus_print);
672
673int cper_estatus_check_header(const struct acpi_hest_generic_status *estatus)
674{
675	if (estatus->data_length &&
676	    estatus->data_length < sizeof(struct acpi_hest_generic_data))
677		return -EINVAL;
678	if (estatus->raw_data_length &&
679	    estatus->raw_data_offset < sizeof(*estatus) + estatus->data_length)
680		return -EINVAL;
681
682	return 0;
683}
684EXPORT_SYMBOL_GPL(cper_estatus_check_header);
685
686int cper_estatus_check(const struct acpi_hest_generic_status *estatus)
687{
688	struct acpi_hest_generic_data *gdata;
689	unsigned int data_len, record_size;
690	int rc;
691
692	rc = cper_estatus_check_header(estatus);
693	if (rc)
694		return rc;
695
696	data_len = estatus->data_length;
697
698	apei_estatus_for_each_section(estatus, gdata) {
699		if (acpi_hest_get_size(gdata) > data_len)
 
700			return -EINVAL;
701
702		record_size = acpi_hest_get_record_size(gdata);
703		if (record_size > data_len)
704			return -EINVAL;
705
706		data_len -= record_size;
707	}
708	if (data_len)
709		return -EINVAL;
710
711	return 0;
712}
713EXPORT_SYMBOL_GPL(cper_estatus_check);
v4.17
 
  1/*
  2 * UEFI Common Platform Error Record (CPER) support
  3 *
  4 * Copyright (C) 2010, Intel Corp.
  5 *	Author: Huang Ying <ying.huang@intel.com>
  6 *
  7 * CPER is the format used to describe platform hardware error by
  8 * various tables, such as ERST, BERT and HEST etc.
  9 *
 10 * For more information about CPER, please refer to Appendix N of UEFI
 11 * Specification version 2.4.
 12 *
 13 * This program is free software; you can redistribute it and/or
 14 * modify it under the terms of the GNU General Public License version
 15 * 2 as published by the Free Software Foundation.
 16 *
 17 * This program is distributed in the hope that it will be useful,
 18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 20 * GNU General Public License for more details.
 21 *
 22 * You should have received a copy of the GNU General Public License
 23 * along with this program; if not, write to the Free Software
 24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 25 */
 26
 27#include <linux/kernel.h>
 28#include <linux/module.h>
 29#include <linux/time.h>
 30#include <linux/cper.h>
 31#include <linux/dmi.h>
 32#include <linux/acpi.h>
 33#include <linux/pci.h>
 34#include <linux/aer.h>
 35#include <linux/printk.h>
 36#include <linux/bcd.h>
 37#include <acpi/ghes.h>
 38#include <ras/ras_event.h>
 39
 40#define INDENT_SP	" "
 41
 42static char rcd_decode_str[CPER_REC_LEN];
 43
 44/*
 45 * CPER record ID need to be unique even after reboot, because record
 46 * ID is used as index for ERST storage, while CPER records from
 47 * multiple boot may co-exist in ERST.
 48 */
 49u64 cper_next_record_id(void)
 50{
 51	static atomic64_t seq;
 52
 53	if (!atomic64_read(&seq))
 54		atomic64_set(&seq, ((u64)get_seconds()) << 32);
 
 
 
 
 
 
 
 
 
 
 
 
 
 55
 56	return atomic64_inc_return(&seq);
 57}
 58EXPORT_SYMBOL_GPL(cper_next_record_id);
 59
 60static const char * const severity_strs[] = {
 61	"recoverable",
 62	"fatal",
 63	"corrected",
 64	"info",
 65};
 66
 67const char *cper_severity_str(unsigned int severity)
 68{
 69	return severity < ARRAY_SIZE(severity_strs) ?
 70		severity_strs[severity] : "unknown";
 71}
 72EXPORT_SYMBOL_GPL(cper_severity_str);
 73
 74/*
 75 * cper_print_bits - print strings for set bits
 76 * @pfx: prefix for each line, including log level and prefix string
 77 * @bits: bit mask
 78 * @strs: string array, indexed by bit position
 79 * @strs_size: size of the string array: @strs
 80 *
 81 * For each set bit in @bits, print the corresponding string in @strs.
 82 * If the output length is longer than 80, multiple line will be
 83 * printed, with @pfx is printed at the beginning of each line.
 84 */
 85void cper_print_bits(const char *pfx, unsigned int bits,
 86		     const char * const strs[], unsigned int strs_size)
 87{
 88	int i, len = 0;
 89	const char *str;
 90	char buf[84];
 91
 92	for (i = 0; i < strs_size; i++) {
 93		if (!(bits & (1U << i)))
 94			continue;
 95		str = strs[i];
 96		if (!str)
 97			continue;
 98		if (len && len + strlen(str) + 2 > 80) {
 99			printk("%s\n", buf);
100			len = 0;
101		}
102		if (!len)
103			len = snprintf(buf, sizeof(buf), "%s%s", pfx, str);
104		else
105			len += snprintf(buf+len, sizeof(buf)-len, ", %s", str);
106	}
107	if (len)
108		printk("%s\n", buf);
109}
110
111static const char * const proc_type_strs[] = {
112	"IA32/X64",
113	"IA64",
114	"ARM",
115};
116
117static const char * const proc_isa_strs[] = {
118	"IA32",
119	"IA64",
120	"X64",
121	"ARM A32/T32",
122	"ARM A64",
123};
124
125const char * const cper_proc_error_type_strs[] = {
126	"cache error",
127	"TLB error",
128	"bus error",
129	"micro-architectural error",
130};
131
132static const char * const proc_op_strs[] = {
133	"unknown or generic",
134	"data read",
135	"data write",
136	"instruction execution",
137};
138
139static const char * const proc_flag_strs[] = {
140	"restartable",
141	"precise IP",
142	"overflow",
143	"corrected",
144};
145
146static void cper_print_proc_generic(const char *pfx,
147				    const struct cper_sec_proc_generic *proc)
148{
149	if (proc->validation_bits & CPER_PROC_VALID_TYPE)
150		printk("%s""processor_type: %d, %s\n", pfx, proc->proc_type,
151		       proc->proc_type < ARRAY_SIZE(proc_type_strs) ?
152		       proc_type_strs[proc->proc_type] : "unknown");
153	if (proc->validation_bits & CPER_PROC_VALID_ISA)
154		printk("%s""processor_isa: %d, %s\n", pfx, proc->proc_isa,
155		       proc->proc_isa < ARRAY_SIZE(proc_isa_strs) ?
156		       proc_isa_strs[proc->proc_isa] : "unknown");
157	if (proc->validation_bits & CPER_PROC_VALID_ERROR_TYPE) {
158		printk("%s""error_type: 0x%02x\n", pfx, proc->proc_error_type);
159		cper_print_bits(pfx, proc->proc_error_type,
160				cper_proc_error_type_strs,
161				ARRAY_SIZE(cper_proc_error_type_strs));
162	}
163	if (proc->validation_bits & CPER_PROC_VALID_OPERATION)
164		printk("%s""operation: %d, %s\n", pfx, proc->operation,
165		       proc->operation < ARRAY_SIZE(proc_op_strs) ?
166		       proc_op_strs[proc->operation] : "unknown");
167	if (proc->validation_bits & CPER_PROC_VALID_FLAGS) {
168		printk("%s""flags: 0x%02x\n", pfx, proc->flags);
169		cper_print_bits(pfx, proc->flags, proc_flag_strs,
170				ARRAY_SIZE(proc_flag_strs));
171	}
172	if (proc->validation_bits & CPER_PROC_VALID_LEVEL)
173		printk("%s""level: %d\n", pfx, proc->level);
174	if (proc->validation_bits & CPER_PROC_VALID_VERSION)
175		printk("%s""version_info: 0x%016llx\n", pfx, proc->cpu_version);
176	if (proc->validation_bits & CPER_PROC_VALID_ID)
177		printk("%s""processor_id: 0x%016llx\n", pfx, proc->proc_id);
178	if (proc->validation_bits & CPER_PROC_VALID_TARGET_ADDRESS)
179		printk("%s""target_address: 0x%016llx\n",
180		       pfx, proc->target_addr);
181	if (proc->validation_bits & CPER_PROC_VALID_REQUESTOR_ID)
182		printk("%s""requestor_id: 0x%016llx\n",
183		       pfx, proc->requestor_id);
184	if (proc->validation_bits & CPER_PROC_VALID_RESPONDER_ID)
185		printk("%s""responder_id: 0x%016llx\n",
186		       pfx, proc->responder_id);
187	if (proc->validation_bits & CPER_PROC_VALID_IP)
188		printk("%s""IP: 0x%016llx\n", pfx, proc->ip);
189}
190
191static const char * const mem_err_type_strs[] = {
192	"unknown",
193	"no error",
194	"single-bit ECC",
195	"multi-bit ECC",
196	"single-symbol chipkill ECC",
197	"multi-symbol chipkill ECC",
198	"master abort",
199	"target abort",
200	"parity error",
201	"watchdog timeout",
202	"invalid address",
203	"mirror Broken",
204	"memory sparing",
205	"scrub corrected error",
206	"scrub uncorrected error",
207	"physical memory map-out event",
208};
209
210const char *cper_mem_err_type_str(unsigned int etype)
211{
212	return etype < ARRAY_SIZE(mem_err_type_strs) ?
213		mem_err_type_strs[etype] : "unknown";
214}
215EXPORT_SYMBOL_GPL(cper_mem_err_type_str);
216
217static int cper_mem_err_location(struct cper_mem_err_compact *mem, char *msg)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
218{
219	u32 len, n;
220
221	if (!msg)
222		return 0;
223
224	n = 0;
225	len = CPER_REC_LEN - 1;
226	if (mem->validation_bits & CPER_MEM_VALID_NODE)
227		n += scnprintf(msg + n, len - n, "node: %d ", mem->node);
228	if (mem->validation_bits & CPER_MEM_VALID_CARD)
229		n += scnprintf(msg + n, len - n, "card: %d ", mem->card);
230	if (mem->validation_bits & CPER_MEM_VALID_MODULE)
231		n += scnprintf(msg + n, len - n, "module: %d ", mem->module);
232	if (mem->validation_bits & CPER_MEM_VALID_RANK_NUMBER)
233		n += scnprintf(msg + n, len - n, "rank: %d ", mem->rank);
234	if (mem->validation_bits & CPER_MEM_VALID_BANK)
235		n += scnprintf(msg + n, len - n, "bank: %d ", mem->bank);
 
 
 
 
 
 
236	if (mem->validation_bits & CPER_MEM_VALID_DEVICE)
237		n += scnprintf(msg + n, len - n, "device: %d ", mem->device);
238	if (mem->validation_bits & CPER_MEM_VALID_ROW)
239		n += scnprintf(msg + n, len - n, "row: %d ", mem->row);
 
 
 
 
240	if (mem->validation_bits & CPER_MEM_VALID_COLUMN)
241		n += scnprintf(msg + n, len - n, "column: %d ", mem->column);
242	if (mem->validation_bits & CPER_MEM_VALID_BIT_POSITION)
243		n += scnprintf(msg + n, len - n, "bit_position: %d ",
244			       mem->bit_pos);
245	if (mem->validation_bits & CPER_MEM_VALID_REQUESTOR_ID)
246		n += scnprintf(msg + n, len - n, "requestor_id: 0x%016llx ",
247			       mem->requestor_id);
248	if (mem->validation_bits & CPER_MEM_VALID_RESPONDER_ID)
249		n += scnprintf(msg + n, len - n, "responder_id: 0x%016llx ",
250			       mem->responder_id);
251	if (mem->validation_bits & CPER_MEM_VALID_TARGET_ID)
252		scnprintf(msg + n, len - n, "target_id: 0x%016llx ",
253			  mem->target_id);
 
 
 
254
255	msg[n] = '\0';
256	return n;
257}
 
258
259static int cper_dimm_err_location(struct cper_mem_err_compact *mem, char *msg)
260{
261	u32 len, n;
262	const char *bank = NULL, *device = NULL;
263
264	if (!msg || !(mem->validation_bits & CPER_MEM_VALID_MODULE_HANDLE))
265		return 0;
266
267	n = 0;
268	len = CPER_REC_LEN - 1;
269	dmi_memdev_name(mem->mem_dev_handle, &bank, &device);
270	if (bank && device)
271		n = snprintf(msg, len, "DIMM location: %s %s ", bank, device);
272	else
273		n = snprintf(msg, len,
274			     "DIMM location: not present. DMI handle: 0x%.4x ",
275			     mem->mem_dev_handle);
276
277	msg[n] = '\0';
278	return n;
279}
 
280
281void cper_mem_err_pack(const struct cper_sec_mem_err *mem,
282		       struct cper_mem_err_compact *cmem)
283{
284	cmem->validation_bits = mem->validation_bits;
285	cmem->node = mem->node;
286	cmem->card = mem->card;
287	cmem->module = mem->module;
288	cmem->bank = mem->bank;
289	cmem->device = mem->device;
290	cmem->row = mem->row;
291	cmem->column = mem->column;
292	cmem->bit_pos = mem->bit_pos;
293	cmem->requestor_id = mem->requestor_id;
294	cmem->responder_id = mem->responder_id;
295	cmem->target_id = mem->target_id;
 
296	cmem->rank = mem->rank;
297	cmem->mem_array_handle = mem->mem_array_handle;
298	cmem->mem_dev_handle = mem->mem_dev_handle;
299}
 
300
301const char *cper_mem_err_unpack(struct trace_seq *p,
302				struct cper_mem_err_compact *cmem)
303{
304	const char *ret = trace_seq_buffer_ptr(p);
 
305
306	if (cper_mem_err_location(cmem, rcd_decode_str))
307		trace_seq_printf(p, "%s", rcd_decode_str);
308	if (cper_dimm_err_location(cmem, rcd_decode_str))
309		trace_seq_printf(p, "%s", rcd_decode_str);
310	trace_seq_putc(p, '\0');
311
312	return ret;
313}
314
315static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem,
316	int len)
317{
318	struct cper_mem_err_compact cmem;
 
319
320	/* Don't trust UEFI 2.1/2.2 structure with bad validation bits */
321	if (len == sizeof(struct cper_sec_mem_err_old) &&
322	    (mem->validation_bits & ~(CPER_MEM_VALID_RANK_NUMBER - 1))) {
323		pr_err(FW_WARN "valid bits set for fields beyond structure\n");
324		return;
325	}
326	if (mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS)
327		printk("%s""error_status: 0x%016llx\n", pfx, mem->error_status);
 
 
328	if (mem->validation_bits & CPER_MEM_VALID_PA)
329		printk("%s""physical_address: 0x%016llx\n",
330		       pfx, mem->physical_addr);
331	if (mem->validation_bits & CPER_MEM_VALID_PA_MASK)
332		printk("%s""physical_address_mask: 0x%016llx\n",
333		       pfx, mem->physical_addr_mask);
334	cper_mem_err_pack(mem, &cmem);
335	if (cper_mem_err_location(&cmem, rcd_decode_str))
336		printk("%s%s\n", pfx, rcd_decode_str);
337	if (mem->validation_bits & CPER_MEM_VALID_ERROR_TYPE) {
338		u8 etype = mem->error_type;
339		printk("%s""error_type: %d, %s\n", pfx, etype,
340		       cper_mem_err_type_str(etype));
341	}
342	if (cper_dimm_err_location(&cmem, rcd_decode_str))
343		printk("%s%s\n", pfx, rcd_decode_str);
344}
345
346static const char * const pcie_port_type_strs[] = {
347	"PCIe end point",
348	"legacy PCI end point",
349	"unknown",
350	"unknown",
351	"root port",
352	"upstream switch port",
353	"downstream switch port",
354	"PCIe to PCI/PCI-X bridge",
355	"PCI/PCI-X to PCIe bridge",
356	"root complex integrated endpoint device",
357	"root complex event collector",
358};
359
360static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie,
361			    const struct acpi_hest_generic_data *gdata)
362{
363	if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE)
364		printk("%s""port_type: %d, %s\n", pfx, pcie->port_type,
365		       pcie->port_type < ARRAY_SIZE(pcie_port_type_strs) ?
366		       pcie_port_type_strs[pcie->port_type] : "unknown");
367	if (pcie->validation_bits & CPER_PCIE_VALID_VERSION)
368		printk("%s""version: %d.%d\n", pfx,
369		       pcie->version.major, pcie->version.minor);
370	if (pcie->validation_bits & CPER_PCIE_VALID_COMMAND_STATUS)
371		printk("%s""command: 0x%04x, status: 0x%04x\n", pfx,
372		       pcie->command, pcie->status);
373	if (pcie->validation_bits & CPER_PCIE_VALID_DEVICE_ID) {
374		const __u8 *p;
375		printk("%s""device_id: %04x:%02x:%02x.%x\n", pfx,
376		       pcie->device_id.segment, pcie->device_id.bus,
377		       pcie->device_id.device, pcie->device_id.function);
378		printk("%s""slot: %d\n", pfx,
379		       pcie->device_id.slot >> CPER_PCIE_SLOT_SHIFT);
380		printk("%s""secondary_bus: 0x%02x\n", pfx,
381		       pcie->device_id.secondary_bus);
382		printk("%s""vendor_id: 0x%04x, device_id: 0x%04x\n", pfx,
383		       pcie->device_id.vendor_id, pcie->device_id.device_id);
384		p = pcie->device_id.class_code;
385		printk("%s""class_code: %02x%02x%02x\n", pfx, p[0], p[1], p[2]);
386	}
387	if (pcie->validation_bits & CPER_PCIE_VALID_SERIAL_NUMBER)
388		printk("%s""serial number: 0x%04x, 0x%04x\n", pfx,
389		       pcie->serial_number.lower, pcie->serial_number.upper);
390	if (pcie->validation_bits & CPER_PCIE_VALID_BRIDGE_CONTROL_STATUS)
391		printk(
392	"%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n",
393	pfx, pcie->bridge.secondary_status, pcie->bridge.control);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
394}
395
396static void cper_print_tstamp(const char *pfx,
397				   struct acpi_hest_generic_data_v300 *gdata)
398{
399	__u8 hour, min, sec, day, mon, year, century, *timestamp;
400
401	if (gdata->validation_bits & ACPI_HEST_GEN_VALID_TIMESTAMP) {
402		timestamp = (__u8 *)&(gdata->time_stamp);
403		sec       = bcd2bin(timestamp[0]);
404		min       = bcd2bin(timestamp[1]);
405		hour      = bcd2bin(timestamp[2]);
406		day       = bcd2bin(timestamp[4]);
407		mon       = bcd2bin(timestamp[5]);
408		year      = bcd2bin(timestamp[6]);
409		century   = bcd2bin(timestamp[7]);
410
411		printk("%s%ststamp: %02d%02d-%02d-%02d %02d:%02d:%02d\n", pfx,
412		       (timestamp[3] & 0x1 ? "precise " : "imprecise "),
413		       century, year, mon, day, hour, min, sec);
414	}
415}
416
 
 
 
 
 
 
 
 
 
 
 
417static void
418cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata,
419			   int sec_no)
420{
421	guid_t *sec_type = (guid_t *)gdata->section_type;
422	__u16 severity;
423	char newpfx[64];
424
425	if (acpi_hest_get_version(gdata) >= 3)
426		cper_print_tstamp(pfx, (struct acpi_hest_generic_data_v300 *)gdata);
427
428	severity = gdata->error_severity;
429	printk("%s""Error %d, type: %s\n", pfx, sec_no,
430	       cper_severity_str(severity));
431	if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID)
432		printk("%s""fru_id: %pUl\n", pfx, gdata->fru_id);
433	if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT)
434		printk("%s""fru_text: %.20s\n", pfx, gdata->fru_text);
435
436	snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP);
 
 
 
 
 
 
 
 
437	if (guid_equal(sec_type, &CPER_SEC_PROC_GENERIC)) {
438		struct cper_sec_proc_generic *proc_err = acpi_hest_get_payload(gdata);
439
440		printk("%s""section_type: general processor error\n", newpfx);
441		if (gdata->error_data_length >= sizeof(*proc_err))
442			cper_print_proc_generic(newpfx, proc_err);
443		else
444			goto err_section_too_small;
445	} else if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) {
446		struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);
447
448		printk("%s""section_type: memory error\n", newpfx);
449		if (gdata->error_data_length >=
450		    sizeof(struct cper_sec_mem_err_old))
451			cper_print_mem(newpfx, mem_err,
452				       gdata->error_data_length);
453		else
454			goto err_section_too_small;
455	} else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
456		struct cper_sec_pcie *pcie = acpi_hest_get_payload(gdata);
457
458		printk("%s""section_type: PCIe error\n", newpfx);
459		if (gdata->error_data_length >= sizeof(*pcie))
460			cper_print_pcie(newpfx, pcie, gdata);
461		else
462			goto err_section_too_small;
463#if defined(CONFIG_ARM64) || defined(CONFIG_ARM)
464	} else if (!uuid_le_cmp(*sec_type, CPER_SEC_PROC_ARM)) {
465		struct cper_sec_proc_arm *arm_err = acpi_hest_get_payload(gdata);
466
467		printk("%ssection_type: ARM processor error\n", newpfx);
468		if (gdata->error_data_length >= sizeof(*arm_err))
469			cper_print_proc_arm(newpfx, arm_err);
470		else
471			goto err_section_too_small;
472#endif
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
473	} else {
474		const void *err = acpi_hest_get_payload(gdata);
475
476		printk("%ssection type: unknown, %pUl\n", newpfx, sec_type);
477		printk("%ssection length: %#x\n", newpfx,
478		       gdata->error_data_length);
479		print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, err,
480			       gdata->error_data_length, true);
481	}
482
483	return;
484
485err_section_too_small:
486	pr_err(FW_WARN "error section length is too small\n");
487}
488
489void cper_estatus_print(const char *pfx,
490			const struct acpi_hest_generic_status *estatus)
491{
492	struct acpi_hest_generic_data *gdata;
493	int sec_no = 0;
494	char newpfx[64];
495	__u16 severity;
496
497	severity = estatus->error_severity;
498	if (severity == CPER_SEV_CORRECTED)
499		printk("%s%s\n", pfx,
500		       "It has been corrected by h/w "
501		       "and requires no further action");
502	printk("%s""event severity: %s\n", pfx, cper_severity_str(severity));
503	snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP);
504
505	apei_estatus_for_each_section(estatus, gdata) {
506		cper_estatus_print_section(newpfx, gdata, sec_no);
507		sec_no++;
508	}
509}
510EXPORT_SYMBOL_GPL(cper_estatus_print);
511
512int cper_estatus_check_header(const struct acpi_hest_generic_status *estatus)
513{
514	if (estatus->data_length &&
515	    estatus->data_length < sizeof(struct acpi_hest_generic_data))
516		return -EINVAL;
517	if (estatus->raw_data_length &&
518	    estatus->raw_data_offset < sizeof(*estatus) + estatus->data_length)
519		return -EINVAL;
520
521	return 0;
522}
523EXPORT_SYMBOL_GPL(cper_estatus_check_header);
524
525int cper_estatus_check(const struct acpi_hest_generic_status *estatus)
526{
527	struct acpi_hest_generic_data *gdata;
528	unsigned int data_len, gedata_len;
529	int rc;
530
531	rc = cper_estatus_check_header(estatus);
532	if (rc)
533		return rc;
 
534	data_len = estatus->data_length;
535
536	apei_estatus_for_each_section(estatus, gdata) {
537		gedata_len = acpi_hest_get_error_length(gdata);
538		if (gedata_len > data_len - acpi_hest_get_size(gdata))
539			return -EINVAL;
540		data_len -= acpi_hest_get_record_size(gdata);
 
 
 
 
 
541	}
542	if (data_len)
543		return -EINVAL;
544
545	return 0;
546}
547EXPORT_SYMBOL_GPL(cper_estatus_check);