]> Git Repo - linux.git/blob - drivers/firmware/efi/cper.c
enetc: Migrate to PHYLINK and PCS_LYNX
[linux.git] / drivers / firmware / efi / cper.c
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/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
28 static char rcd_decode_str[CPER_REC_LEN];
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 static const char * const proc_type_strs[] = {
111         "IA32/X64",
112         "IA64",
113         "ARM",
114 };
115
116 static const char * const proc_isa_strs[] = {
117         "IA32",
118         "IA64",
119         "X64",
120         "ARM A32/T32",
121         "ARM A64",
122 };
123
124 const char * const cper_proc_error_type_strs[] = {
125         "cache error",
126         "TLB error",
127         "bus error",
128         "micro-architectural error",
129 };
130
131 static const char * const proc_op_strs[] = {
132         "unknown or generic",
133         "data read",
134         "data write",
135         "instruction execution",
136 };
137
138 static const char * const proc_flag_strs[] = {
139         "restartable",
140         "precise IP",
141         "overflow",
142         "corrected",
143 };
144
145 static void cper_print_proc_generic(const char *pfx,
146                                     const struct cper_sec_proc_generic *proc)
147 {
148         if (proc->validation_bits & CPER_PROC_VALID_TYPE)
149                 printk("%s""processor_type: %d, %s\n", pfx, proc->proc_type,
150                        proc->proc_type < ARRAY_SIZE(proc_type_strs) ?
151                        proc_type_strs[proc->proc_type] : "unknown");
152         if (proc->validation_bits & CPER_PROC_VALID_ISA)
153                 printk("%s""processor_isa: %d, %s\n", pfx, proc->proc_isa,
154                        proc->proc_isa < ARRAY_SIZE(proc_isa_strs) ?
155                        proc_isa_strs[proc->proc_isa] : "unknown");
156         if (proc->validation_bits & CPER_PROC_VALID_ERROR_TYPE) {
157                 printk("%s""error_type: 0x%02x\n", pfx, proc->proc_error_type);
158                 cper_print_bits(pfx, proc->proc_error_type,
159                                 cper_proc_error_type_strs,
160                                 ARRAY_SIZE(cper_proc_error_type_strs));
161         }
162         if (proc->validation_bits & CPER_PROC_VALID_OPERATION)
163                 printk("%s""operation: %d, %s\n", pfx, proc->operation,
164                        proc->operation < ARRAY_SIZE(proc_op_strs) ?
165                        proc_op_strs[proc->operation] : "unknown");
166         if (proc->validation_bits & CPER_PROC_VALID_FLAGS) {
167                 printk("%s""flags: 0x%02x\n", pfx, proc->flags);
168                 cper_print_bits(pfx, proc->flags, proc_flag_strs,
169                                 ARRAY_SIZE(proc_flag_strs));
170         }
171         if (proc->validation_bits & CPER_PROC_VALID_LEVEL)
172                 printk("%s""level: %d\n", pfx, proc->level);
173         if (proc->validation_bits & CPER_PROC_VALID_VERSION)
174                 printk("%s""version_info: 0x%016llx\n", pfx, proc->cpu_version);
175         if (proc->validation_bits & CPER_PROC_VALID_ID)
176                 printk("%s""processor_id: 0x%016llx\n", pfx, proc->proc_id);
177         if (proc->validation_bits & CPER_PROC_VALID_TARGET_ADDRESS)
178                 printk("%s""target_address: 0x%016llx\n",
179                        pfx, proc->target_addr);
180         if (proc->validation_bits & CPER_PROC_VALID_REQUESTOR_ID)
181                 printk("%s""requestor_id: 0x%016llx\n",
182                        pfx, proc->requestor_id);
183         if (proc->validation_bits & CPER_PROC_VALID_RESPONDER_ID)
184                 printk("%s""responder_id: 0x%016llx\n",
185                        pfx, proc->responder_id);
186         if (proc->validation_bits & CPER_PROC_VALID_IP)
187                 printk("%s""IP: 0x%016llx\n", pfx, proc->ip);
188 }
189
190 static const char * const mem_err_type_strs[] = {
191         "unknown",
192         "no error",
193         "single-bit ECC",
194         "multi-bit ECC",
195         "single-symbol chipkill ECC",
196         "multi-symbol chipkill ECC",
197         "master abort",
198         "target abort",
199         "parity error",
200         "watchdog timeout",
201         "invalid address",
202         "mirror Broken",
203         "memory sparing",
204         "scrub corrected error",
205         "scrub uncorrected error",
206         "physical memory map-out event",
207 };
208
209 const char *cper_mem_err_type_str(unsigned int etype)
210 {
211         return etype < ARRAY_SIZE(mem_err_type_strs) ?
212                 mem_err_type_strs[etype] : "unknown";
213 }
214 EXPORT_SYMBOL_GPL(cper_mem_err_type_str);
215
216 static int cper_mem_err_location(struct cper_mem_err_compact *mem, char *msg)
217 {
218         u32 len, n;
219
220         if (!msg)
221                 return 0;
222
223         n = 0;
224         len = CPER_REC_LEN - 1;
225         if (mem->validation_bits & CPER_MEM_VALID_NODE)
226                 n += scnprintf(msg + n, len - n, "node: %d ", mem->node);
227         if (mem->validation_bits & CPER_MEM_VALID_CARD)
228                 n += scnprintf(msg + n, len - n, "card: %d ", mem->card);
229         if (mem->validation_bits & CPER_MEM_VALID_MODULE)
230                 n += scnprintf(msg + n, len - n, "module: %d ", mem->module);
231         if (mem->validation_bits & CPER_MEM_VALID_RANK_NUMBER)
232                 n += scnprintf(msg + n, len - n, "rank: %d ", mem->rank);
233         if (mem->validation_bits & CPER_MEM_VALID_BANK)
234                 n += scnprintf(msg + n, len - n, "bank: %d ", mem->bank);
235         if (mem->validation_bits & CPER_MEM_VALID_DEVICE)
236                 n += scnprintf(msg + n, len - n, "device: %d ", mem->device);
237         if (mem->validation_bits & CPER_MEM_VALID_ROW)
238                 n += scnprintf(msg + n, len - n, "row: %d ", mem->row);
239         if (mem->validation_bits & CPER_MEM_VALID_COLUMN)
240                 n += scnprintf(msg + n, len - n, "column: %d ", mem->column);
241         if (mem->validation_bits & CPER_MEM_VALID_BIT_POSITION)
242                 n += scnprintf(msg + n, len - n, "bit_position: %d ",
243                                mem->bit_pos);
244         if (mem->validation_bits & CPER_MEM_VALID_REQUESTOR_ID)
245                 n += scnprintf(msg + n, len - n, "requestor_id: 0x%016llx ",
246                                mem->requestor_id);
247         if (mem->validation_bits & CPER_MEM_VALID_RESPONDER_ID)
248                 n += scnprintf(msg + n, len - n, "responder_id: 0x%016llx ",
249                                mem->responder_id);
250         if (mem->validation_bits & CPER_MEM_VALID_TARGET_ID)
251                 scnprintf(msg + n, len - n, "target_id: 0x%016llx ",
252                           mem->target_id);
253
254         msg[n] = '\0';
255         return n;
256 }
257
258 static int cper_dimm_err_location(struct cper_mem_err_compact *mem, char *msg)
259 {
260         u32 len, n;
261         const char *bank = NULL, *device = NULL;
262
263         if (!msg || !(mem->validation_bits & CPER_MEM_VALID_MODULE_HANDLE))
264                 return 0;
265
266         n = 0;
267         len = CPER_REC_LEN - 1;
268         dmi_memdev_name(mem->mem_dev_handle, &bank, &device);
269         if (bank && device)
270                 n = snprintf(msg, len, "DIMM location: %s %s ", bank, device);
271         else
272                 n = snprintf(msg, len,
273                              "DIMM location: not present. DMI handle: 0x%.4x ",
274                              mem->mem_dev_handle);
275
276         msg[n] = '\0';
277         return n;
278 }
279
280 void cper_mem_err_pack(const struct cper_sec_mem_err *mem,
281                        struct cper_mem_err_compact *cmem)
282 {
283         cmem->validation_bits = mem->validation_bits;
284         cmem->node = mem->node;
285         cmem->card = mem->card;
286         cmem->module = mem->module;
287         cmem->bank = mem->bank;
288         cmem->device = mem->device;
289         cmem->row = mem->row;
290         cmem->column = mem->column;
291         cmem->bit_pos = mem->bit_pos;
292         cmem->requestor_id = mem->requestor_id;
293         cmem->responder_id = mem->responder_id;
294         cmem->target_id = mem->target_id;
295         cmem->rank = mem->rank;
296         cmem->mem_array_handle = mem->mem_array_handle;
297         cmem->mem_dev_handle = mem->mem_dev_handle;
298 }
299
300 const char *cper_mem_err_unpack(struct trace_seq *p,
301                                 struct cper_mem_err_compact *cmem)
302 {
303         const char *ret = trace_seq_buffer_ptr(p);
304
305         if (cper_mem_err_location(cmem, rcd_decode_str))
306                 trace_seq_printf(p, "%s", rcd_decode_str);
307         if (cper_dimm_err_location(cmem, rcd_decode_str))
308                 trace_seq_printf(p, "%s", rcd_decode_str);
309         trace_seq_putc(p, '\0');
310
311         return ret;
312 }
313
314 static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem,
315         int len)
316 {
317         struct cper_mem_err_compact cmem;
318
319         /* Don't trust UEFI 2.1/2.2 structure with bad validation bits */
320         if (len == sizeof(struct cper_sec_mem_err_old) &&
321             (mem->validation_bits & ~(CPER_MEM_VALID_RANK_NUMBER - 1))) {
322                 pr_err(FW_WARN "valid bits set for fields beyond structure\n");
323                 return;
324         }
325         if (mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS)
326                 printk("%s""error_status: 0x%016llx\n", pfx, mem->error_status);
327         if (mem->validation_bits & CPER_MEM_VALID_PA)
328                 printk("%s""physical_address: 0x%016llx\n",
329                        pfx, mem->physical_addr);
330         if (mem->validation_bits & CPER_MEM_VALID_PA_MASK)
331                 printk("%s""physical_address_mask: 0x%016llx\n",
332                        pfx, mem->physical_addr_mask);
333         cper_mem_err_pack(mem, &cmem);
334         if (cper_mem_err_location(&cmem, rcd_decode_str))
335                 printk("%s%s\n", pfx, rcd_decode_str);
336         if (mem->validation_bits & CPER_MEM_VALID_ERROR_TYPE) {
337                 u8 etype = mem->error_type;
338                 printk("%s""error_type: %d, %s\n", pfx, etype,
339                        cper_mem_err_type_str(etype));
340         }
341         if (cper_dimm_err_location(&cmem, rcd_decode_str))
342                 printk("%s%s\n", pfx, rcd_decode_str);
343 }
344
345 static const char * const pcie_port_type_strs[] = {
346         "PCIe end point",
347         "legacy PCI end point",
348         "unknown",
349         "unknown",
350         "root port",
351         "upstream switch port",
352         "downstream switch port",
353         "PCIe to PCI/PCI-X bridge",
354         "PCI/PCI-X to PCIe bridge",
355         "root complex integrated endpoint device",
356         "root complex event collector",
357 };
358
359 static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie,
360                             const struct acpi_hest_generic_data *gdata)
361 {
362         if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE)
363                 printk("%s""port_type: %d, %s\n", pfx, pcie->port_type,
364                        pcie->port_type < ARRAY_SIZE(pcie_port_type_strs) ?
365                        pcie_port_type_strs[pcie->port_type] : "unknown");
366         if (pcie->validation_bits & CPER_PCIE_VALID_VERSION)
367                 printk("%s""version: %d.%d\n", pfx,
368                        pcie->version.major, pcie->version.minor);
369         if (pcie->validation_bits & CPER_PCIE_VALID_COMMAND_STATUS)
370                 printk("%s""command: 0x%04x, status: 0x%04x\n", pfx,
371                        pcie->command, pcie->status);
372         if (pcie->validation_bits & CPER_PCIE_VALID_DEVICE_ID) {
373                 const __u8 *p;
374                 printk("%s""device_id: %04x:%02x:%02x.%x\n", pfx,
375                        pcie->device_id.segment, pcie->device_id.bus,
376                        pcie->device_id.device, pcie->device_id.function);
377                 printk("%s""slot: %d\n", pfx,
378                        pcie->device_id.slot >> CPER_PCIE_SLOT_SHIFT);
379                 printk("%s""secondary_bus: 0x%02x\n", pfx,
380                        pcie->device_id.secondary_bus);
381                 printk("%s""vendor_id: 0x%04x, device_id: 0x%04x\n", pfx,
382                        pcie->device_id.vendor_id, pcie->device_id.device_id);
383                 p = pcie->device_id.class_code;
384                 printk("%s""class_code: %02x%02x%02x\n", pfx, p[2], p[1], p[0]);
385         }
386         if (pcie->validation_bits & CPER_PCIE_VALID_SERIAL_NUMBER)
387                 printk("%s""serial number: 0x%04x, 0x%04x\n", pfx,
388                        pcie->serial_number.lower, pcie->serial_number.upper);
389         if (pcie->validation_bits & CPER_PCIE_VALID_BRIDGE_CONTROL_STATUS)
390                 printk(
391         "%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n",
392         pfx, pcie->bridge.secondary_status, pcie->bridge.control);
393
394         /* Fatal errors call __ghes_panic() before AER handler prints this */
395         if ((pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) &&
396             (gdata->error_severity & CPER_SEV_FATAL)) {
397                 struct aer_capability_regs *aer;
398
399                 aer = (struct aer_capability_regs *)pcie->aer_info;
400                 printk("%saer_uncor_status: 0x%08x, aer_uncor_mask: 0x%08x\n",
401                        pfx, aer->uncor_status, aer->uncor_mask);
402                 printk("%saer_uncor_severity: 0x%08x\n",
403                        pfx, aer->uncor_severity);
404                 printk("%sTLP Header: %08x %08x %08x %08x\n", pfx,
405                        aer->header_log.dw0, aer->header_log.dw1,
406                        aer->header_log.dw2, aer->header_log.dw3);
407         }
408 }
409
410 static const char * const fw_err_rec_type_strs[] = {
411         "IPF SAL Error Record",
412         "SOC Firmware Error Record Type1 (Legacy CrashLog Support)",
413         "SOC Firmware Error Record Type2",
414 };
415
416 static void cper_print_fw_err(const char *pfx,
417                               struct acpi_hest_generic_data *gdata,
418                               const struct cper_sec_fw_err_rec_ref *fw_err)
419 {
420         void *buf = acpi_hest_get_payload(gdata);
421         u32 offset, length = gdata->error_data_length;
422
423         printk("%s""Firmware Error Record Type: %s\n", pfx,
424                fw_err->record_type < ARRAY_SIZE(fw_err_rec_type_strs) ?
425                fw_err_rec_type_strs[fw_err->record_type] : "unknown");
426         printk("%s""Revision: %d\n", pfx, fw_err->revision);
427
428         /* Record Type based on UEFI 2.7 */
429         if (fw_err->revision == 0) {
430                 printk("%s""Record Identifier: %08llx\n", pfx,
431                        fw_err->record_identifier);
432         } else if (fw_err->revision == 2) {
433                 printk("%s""Record Identifier: %pUl\n", pfx,
434                        &fw_err->record_identifier_guid);
435         }
436
437         /*
438          * The FW error record may contain trailing data beyond the
439          * structure defined by the specification. As the fields
440          * defined (and hence the offset of any trailing data) vary
441          * with the revision, set the offset to account for this
442          * variation.
443          */
444         if (fw_err->revision == 0) {
445                 /* record_identifier_guid not defined */
446                 offset = offsetof(struct cper_sec_fw_err_rec_ref,
447                                   record_identifier_guid);
448         } else if (fw_err->revision == 1) {
449                 /* record_identifier not defined */
450                 offset = offsetof(struct cper_sec_fw_err_rec_ref,
451                                   record_identifier);
452         } else {
453                 offset = sizeof(*fw_err);
454         }
455
456         buf += offset;
457         length -= offset;
458
459         print_hex_dump(pfx, "", DUMP_PREFIX_OFFSET, 16, 4, buf, length, true);
460 }
461
462 static void cper_print_tstamp(const char *pfx,
463                                    struct acpi_hest_generic_data_v300 *gdata)
464 {
465         __u8 hour, min, sec, day, mon, year, century, *timestamp;
466
467         if (gdata->validation_bits & ACPI_HEST_GEN_VALID_TIMESTAMP) {
468                 timestamp = (__u8 *)&(gdata->time_stamp);
469                 sec       = bcd2bin(timestamp[0]);
470                 min       = bcd2bin(timestamp[1]);
471                 hour      = bcd2bin(timestamp[2]);
472                 day       = bcd2bin(timestamp[4]);
473                 mon       = bcd2bin(timestamp[5]);
474                 year      = bcd2bin(timestamp[6]);
475                 century   = bcd2bin(timestamp[7]);
476
477                 printk("%s%ststamp: %02d%02d-%02d-%02d %02d:%02d:%02d\n", pfx,
478                        (timestamp[3] & 0x1 ? "precise " : "imprecise "),
479                        century, year, mon, day, hour, min, sec);
480         }
481 }
482
483 static void
484 cper_estatus_print_section(const char *pfx, struct acpi_hest_generic_data *gdata,
485                            int sec_no)
486 {
487         guid_t *sec_type = (guid_t *)gdata->section_type;
488         __u16 severity;
489         char newpfx[64];
490
491         if (acpi_hest_get_version(gdata) >= 3)
492                 cper_print_tstamp(pfx, (struct acpi_hest_generic_data_v300 *)gdata);
493
494         severity = gdata->error_severity;
495         printk("%s""Error %d, type: %s\n", pfx, sec_no,
496                cper_severity_str(severity));
497         if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID)
498                 printk("%s""fru_id: %pUl\n", pfx, gdata->fru_id);
499         if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT)
500                 printk("%s""fru_text: %.20s\n", pfx, gdata->fru_text);
501
502         snprintf(newpfx, sizeof(newpfx), "%s ", pfx);
503         if (guid_equal(sec_type, &CPER_SEC_PROC_GENERIC)) {
504                 struct cper_sec_proc_generic *proc_err = acpi_hest_get_payload(gdata);
505
506                 printk("%s""section_type: general processor error\n", newpfx);
507                 if (gdata->error_data_length >= sizeof(*proc_err))
508                         cper_print_proc_generic(newpfx, proc_err);
509                 else
510                         goto err_section_too_small;
511         } else if (guid_equal(sec_type, &CPER_SEC_PLATFORM_MEM)) {
512                 struct cper_sec_mem_err *mem_err = acpi_hest_get_payload(gdata);
513
514                 printk("%s""section_type: memory error\n", newpfx);
515                 if (gdata->error_data_length >=
516                     sizeof(struct cper_sec_mem_err_old))
517                         cper_print_mem(newpfx, mem_err,
518                                        gdata->error_data_length);
519                 else
520                         goto err_section_too_small;
521         } else if (guid_equal(sec_type, &CPER_SEC_PCIE)) {
522                 struct cper_sec_pcie *pcie = acpi_hest_get_payload(gdata);
523
524                 printk("%s""section_type: PCIe error\n", newpfx);
525                 if (gdata->error_data_length >= sizeof(*pcie))
526                         cper_print_pcie(newpfx, pcie, gdata);
527                 else
528                         goto err_section_too_small;
529 #if defined(CONFIG_ARM64) || defined(CONFIG_ARM)
530         } else if (guid_equal(sec_type, &CPER_SEC_PROC_ARM)) {
531                 struct cper_sec_proc_arm *arm_err = acpi_hest_get_payload(gdata);
532
533                 printk("%ssection_type: ARM processor error\n", newpfx);
534                 if (gdata->error_data_length >= sizeof(*arm_err))
535                         cper_print_proc_arm(newpfx, arm_err);
536                 else
537                         goto err_section_too_small;
538 #endif
539 #if defined(CONFIG_UEFI_CPER_X86)
540         } else if (guid_equal(sec_type, &CPER_SEC_PROC_IA)) {
541                 struct cper_sec_proc_ia *ia_err = acpi_hest_get_payload(gdata);
542
543                 printk("%ssection_type: IA32/X64 processor error\n", newpfx);
544                 if (gdata->error_data_length >= sizeof(*ia_err))
545                         cper_print_proc_ia(newpfx, ia_err);
546                 else
547                         goto err_section_too_small;
548 #endif
549         } else if (guid_equal(sec_type, &CPER_SEC_FW_ERR_REC_REF)) {
550                 struct cper_sec_fw_err_rec_ref *fw_err = acpi_hest_get_payload(gdata);
551
552                 printk("%ssection_type: Firmware Error Record Reference\n",
553                        newpfx);
554                 /* The minimal FW Error Record contains 16 bytes */
555                 if (gdata->error_data_length >= SZ_16)
556                         cper_print_fw_err(newpfx, gdata, fw_err);
557                 else
558                         goto err_section_too_small;
559         } else {
560                 const void *err = acpi_hest_get_payload(gdata);
561
562                 printk("%ssection type: unknown, %pUl\n", newpfx, sec_type);
563                 printk("%ssection length: %#x\n", newpfx,
564                        gdata->error_data_length);
565                 print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, err,
566                                gdata->error_data_length, true);
567         }
568
569         return;
570
571 err_section_too_small:
572         pr_err(FW_WARN "error section length is too small\n");
573 }
574
575 void cper_estatus_print(const char *pfx,
576                         const struct acpi_hest_generic_status *estatus)
577 {
578         struct acpi_hest_generic_data *gdata;
579         int sec_no = 0;
580         char newpfx[64];
581         __u16 severity;
582
583         severity = estatus->error_severity;
584         if (severity == CPER_SEV_CORRECTED)
585                 printk("%s%s\n", pfx,
586                        "It has been corrected by h/w "
587                        "and requires no further action");
588         printk("%s""event severity: %s\n", pfx, cper_severity_str(severity));
589         snprintf(newpfx, sizeof(newpfx), "%s ", pfx);
590
591         apei_estatus_for_each_section(estatus, gdata) {
592                 cper_estatus_print_section(newpfx, gdata, sec_no);
593                 sec_no++;
594         }
595 }
596 EXPORT_SYMBOL_GPL(cper_estatus_print);
597
598 int cper_estatus_check_header(const struct acpi_hest_generic_status *estatus)
599 {
600         if (estatus->data_length &&
601             estatus->data_length < sizeof(struct acpi_hest_generic_data))
602                 return -EINVAL;
603         if (estatus->raw_data_length &&
604             estatus->raw_data_offset < sizeof(*estatus) + estatus->data_length)
605                 return -EINVAL;
606
607         return 0;
608 }
609 EXPORT_SYMBOL_GPL(cper_estatus_check_header);
610
611 int cper_estatus_check(const struct acpi_hest_generic_status *estatus)
612 {
613         struct acpi_hest_generic_data *gdata;
614         unsigned int data_len, record_size;
615         int rc;
616
617         rc = cper_estatus_check_header(estatus);
618         if (rc)
619                 return rc;
620
621         data_len = estatus->data_length;
622
623         apei_estatus_for_each_section(estatus, gdata) {
624                 if (sizeof(struct acpi_hest_generic_data) > data_len)
625                         return -EINVAL;
626
627                 record_size = acpi_hest_get_record_size(gdata);
628                 if (record_size > data_len)
629                         return -EINVAL;
630
631                 data_len -= record_size;
632         }
633         if (data_len)
634                 return -EINVAL;
635
636         return 0;
637 }
638 EXPORT_SYMBOL_GPL(cper_estatus_check);
This page took 0.065294 seconds and 4 git commands to generate.