hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/drivers/firmware/efi/cper.c
....@@ -1,3 +1,4 @@
1
+// SPDX-License-Identifier: GPL-2.0
12 /*
23 * UEFI Common Platform Error Record (CPER) support
34 *
....@@ -9,19 +10,6 @@
910 *
1011 * For more information about CPER, please refer to Appendix N of UEFI
1112 * 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
2513 */
2614
2715 #include <linux/kernel.h>
....@@ -111,7 +99,7 @@
11199 if (!len)
112100 len = snprintf(buf, sizeof(buf), "%s%s", pfx, str);
113101 else
114
- len += snprintf(buf+len, sizeof(buf)-len, ", %s", str);
102
+ len += scnprintf(buf+len, sizeof(buf)-len, ", %s", str);
115103 }
116104 if (len)
117105 printk("%s\n", buf);
....@@ -242,10 +230,20 @@
242230 n += scnprintf(msg + n, len - n, "rank: %d ", mem->rank);
243231 if (mem->validation_bits & CPER_MEM_VALID_BANK)
244232 n += scnprintf(msg + n, len - n, "bank: %d ", mem->bank);
233
+ if (mem->validation_bits & CPER_MEM_VALID_BANK_GROUP)
234
+ n += scnprintf(msg + n, len - n, "bank_group: %d ",
235
+ mem->bank >> CPER_MEM_BANK_GROUP_SHIFT);
236
+ if (mem->validation_bits & CPER_MEM_VALID_BANK_ADDRESS)
237
+ n += scnprintf(msg + n, len - n, "bank_address: %d ",
238
+ mem->bank & CPER_MEM_BANK_ADDRESS_MASK);
245239 if (mem->validation_bits & CPER_MEM_VALID_DEVICE)
246240 n += scnprintf(msg + n, len - n, "device: %d ", mem->device);
247
- if (mem->validation_bits & CPER_MEM_VALID_ROW)
248
- n += scnprintf(msg + n, len - n, "row: %d ", mem->row);
241
+ if (mem->validation_bits & (CPER_MEM_VALID_ROW | CPER_MEM_VALID_ROW_EXT)) {
242
+ u32 row = mem->row;
243
+
244
+ row |= cper_get_mem_extension(mem->validation_bits, mem->extended);
245
+ n += scnprintf(msg + n, len - n, "row: %d ", row);
246
+ }
249247 if (mem->validation_bits & CPER_MEM_VALID_COLUMN)
250248 n += scnprintf(msg + n, len - n, "column: %d ", mem->column);
251249 if (mem->validation_bits & CPER_MEM_VALID_BIT_POSITION)
....@@ -260,6 +258,9 @@
260258 if (mem->validation_bits & CPER_MEM_VALID_TARGET_ID)
261259 scnprintf(msg + n, len - n, "target_id: 0x%016llx ",
262260 mem->target_id);
261
+ if (mem->validation_bits & CPER_MEM_VALID_CHIP_ID)
262
+ scnprintf(msg + n, len - n, "chip_id: %d ",
263
+ mem->extended >> CPER_MEM_CHIP_ID_SHIFT);
263264
264265 msg[n] = '\0';
265266 return n;
....@@ -300,6 +301,7 @@
300301 cmem->requestor_id = mem->requestor_id;
301302 cmem->responder_id = mem->responder_id;
302303 cmem->target_id = mem->target_id;
304
+ cmem->extended = mem->extended;
303305 cmem->rank = mem->rank;
304306 cmem->mem_array_handle = mem->mem_array_handle;
305307 cmem->mem_dev_handle = mem->mem_dev_handle;
....@@ -417,6 +419,58 @@
417419 }
418420 }
419421
422
+static const char * const fw_err_rec_type_strs[] = {
423
+ "IPF SAL Error Record",
424
+ "SOC Firmware Error Record Type1 (Legacy CrashLog Support)",
425
+ "SOC Firmware Error Record Type2",
426
+};
427
+
428
+static void cper_print_fw_err(const char *pfx,
429
+ struct acpi_hest_generic_data *gdata,
430
+ const struct cper_sec_fw_err_rec_ref *fw_err)
431
+{
432
+ void *buf = acpi_hest_get_payload(gdata);
433
+ u32 offset, length = gdata->error_data_length;
434
+
435
+ printk("%s""Firmware Error Record Type: %s\n", pfx,
436
+ fw_err->record_type < ARRAY_SIZE(fw_err_rec_type_strs) ?
437
+ fw_err_rec_type_strs[fw_err->record_type] : "unknown");
438
+ printk("%s""Revision: %d\n", pfx, fw_err->revision);
439
+
440
+ /* Record Type based on UEFI 2.7 */
441
+ if (fw_err->revision == 0) {
442
+ printk("%s""Record Identifier: %08llx\n", pfx,
443
+ fw_err->record_identifier);
444
+ } else if (fw_err->revision == 2) {
445
+ printk("%s""Record Identifier: %pUl\n", pfx,
446
+ &fw_err->record_identifier_guid);
447
+ }
448
+
449
+ /*
450
+ * The FW error record may contain trailing data beyond the
451
+ * structure defined by the specification. As the fields
452
+ * defined (and hence the offset of any trailing data) vary
453
+ * with the revision, set the offset to account for this
454
+ * variation.
455
+ */
456
+ if (fw_err->revision == 0) {
457
+ /* record_identifier_guid not defined */
458
+ offset = offsetof(struct cper_sec_fw_err_rec_ref,
459
+ record_identifier_guid);
460
+ } else if (fw_err->revision == 1) {
461
+ /* record_identifier not defined */
462
+ offset = offsetof(struct cper_sec_fw_err_rec_ref,
463
+ record_identifier);
464
+ } else {
465
+ offset = sizeof(*fw_err);
466
+ }
467
+
468
+ buf += offset;
469
+ length -= offset;
470
+
471
+ print_hex_dump(pfx, "", DUMP_PREFIX_OFFSET, 16, 4, buf, length, true);
472
+}
473
+
420474 static void cper_print_tstamp(const char *pfx,
421475 struct acpi_hest_generic_data_v300 *gdata)
422476 {
....@@ -504,6 +558,16 @@
504558 else
505559 goto err_section_too_small;
506560 #endif
561
+ } else if (guid_equal(sec_type, &CPER_SEC_FW_ERR_REC_REF)) {
562
+ struct cper_sec_fw_err_rec_ref *fw_err = acpi_hest_get_payload(gdata);
563
+
564
+ printk("%ssection_type: Firmware Error Record Reference\n",
565
+ newpfx);
566
+ /* The minimal FW Error Record contains 16 bytes */
567
+ if (gdata->error_data_length >= SZ_16)
568
+ cper_print_fw_err(newpfx, gdata, fw_err);
569
+ else
570
+ goto err_section_too_small;
507571 } else {
508572 const void *err = acpi_hest_get_payload(gdata);
509573