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