Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

efi/cper: align ARM CPER type with UEFI 2.9A/2.10 specs

Up to UEFI spec 2.9, the type byte of CPER struct for ARM processor
was defined simply as:

Type at byte offset 4:

- Cache error
- TLB Error
- Bus Error
- Micro-architectural Error
All other values are reserved

Yet, there was no information about how this would be encoded.

Spec 2.9A errata corrected it by defining:

- Bit 1 - Cache Error
- Bit 2 - TLB Error
- Bit 3 - Bus Error
- Bit 4 - Micro-architectural Error
All other values are reserved

That actually aligns with the values already defined on older
versions at N.2.4.1. Generic Processor Error Section.

Spec 2.10 also preserve the same encoding as 2.9A.

Adjust CPER and GHES handling code for both generic and ARM
processors to properly handle UEFI 2.9A and 2.10 encoding.

Link: https://uefi.org/specs/UEFI/2.10/Apx_N_Common_Platform_Error_Record.html#arm-processor-error-information
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Acked-by: Borislav Petkov (AMD) <bp@alien8.de>
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>

authored by

Mauro Carvalho Chehab and committed by
Ard Biesheuvel
96b01053 a976d790

+39 -37
+10 -6
drivers/acpi/apei/ghes.c
··· 22 22 #include <linux/moduleparam.h> 23 23 #include <linux/init.h> 24 24 #include <linux/acpi.h> 25 + #include <linux/bitfield.h> 25 26 #include <linux/io.h> 26 27 #include <linux/interrupt.h> 27 28 #include <linux/timer.h> ··· 557 556 { 558 557 struct cper_sec_proc_arm *err = acpi_hest_get_payload(gdata); 559 558 int flags = sync ? MF_ACTION_REQUIRED : 0; 559 + char error_type[120]; 560 560 bool queued = false; 561 561 int sec_sev, i; 562 562 char *p; ··· 570 568 p = (char *)(err + 1); 571 569 for (i = 0; i < err->err_info_num; i++) { 572 570 struct cper_arm_err_info *err_info = (struct cper_arm_err_info *)p; 573 - bool is_cache = (err_info->type == CPER_ARM_CACHE_ERROR); 571 + bool is_cache = err_info->type & CPER_ARM_CACHE_ERROR; 574 572 bool has_pa = (err_info->validation_bits & CPER_ARM_INFO_VALID_PHYSICAL_ADDR); 575 - const char *error_type = "unknown error"; 576 573 577 574 /* 578 575 * The field (err_info->error_info & BIT(26)) is fixed to set to ··· 585 584 continue; 586 585 } 587 586 588 - if (err_info->type < ARRAY_SIZE(cper_proc_error_type_strs)) 589 - error_type = cper_proc_error_type_strs[err_info->type]; 587 + cper_bits_to_str(error_type, sizeof(error_type), 588 + FIELD_GET(CPER_ARM_ERR_TYPE_MASK, err_info->type), 589 + cper_proc_error_type_strs, 590 + ARRAY_SIZE(cper_proc_error_type_strs)); 590 591 591 592 pr_warn_ratelimited(FW_WARN GHES_PFX 592 - "Unhandled processor error type: %s\n", 593 - error_type); 593 + "Unhandled processor error type 0x%02x: %s%s\n", 594 + err_info->type, error_type, 595 + (err_info->type & ~CPER_ARM_ERR_TYPE_MASK) ? " with reserved bit(s)" : ""); 594 596 p += err_info->length; 595 597 } 596 598
+24 -26
drivers/firmware/efi/cper-arm.c
··· 93 93 bool proc_context_corrupt, corrected, precise_pc, restartable_pc; 94 94 bool time_out, access_mode; 95 95 96 - /* If the type is unknown, bail. */ 97 - if (type > CPER_ARM_MAX_TYPE) 98 - return; 99 - 100 96 /* 101 97 * Vendor type errors have error information values that are vendor 102 98 * specific. 103 99 */ 104 - if (type == CPER_ARM_VENDOR_ERROR) 100 + if (type & CPER_ARM_VENDOR_ERROR) 105 101 return; 106 102 107 103 if (error_info & CPER_ARM_ERR_VALID_TRANSACTION_TYPE) { ··· 112 116 if (error_info & CPER_ARM_ERR_VALID_OPERATION_TYPE) { 113 117 op_type = ((error_info >> CPER_ARM_ERR_OPERATION_SHIFT) 114 118 & CPER_ARM_ERR_OPERATION_MASK); 115 - switch (type) { 116 - case CPER_ARM_CACHE_ERROR: 119 + if (type & CPER_ARM_CACHE_ERROR) { 117 120 if (op_type < ARRAY_SIZE(arm_cache_err_op_strs)) { 118 - printk("%soperation type: %s\n", pfx, 121 + printk("%scache error, operation type: %s\n", pfx, 119 122 arm_cache_err_op_strs[op_type]); 120 123 } 121 - break; 122 - case CPER_ARM_TLB_ERROR: 124 + } 125 + if (type & CPER_ARM_TLB_ERROR) { 123 126 if (op_type < ARRAY_SIZE(arm_tlb_err_op_strs)) { 124 - printk("%soperation type: %s\n", pfx, 127 + printk("%sTLB error, operation type: %s\n", pfx, 125 128 arm_tlb_err_op_strs[op_type]); 126 129 } 127 - break; 128 - case CPER_ARM_BUS_ERROR: 130 + } 131 + if (type & CPER_ARM_BUS_ERROR) { 129 132 if (op_type < ARRAY_SIZE(arm_bus_err_op_strs)) { 130 - printk("%soperation type: %s\n", pfx, 133 + printk("%sbus error, operation type: %s\n", pfx, 131 134 arm_bus_err_op_strs[op_type]); 132 135 } 133 - break; 134 136 } 135 137 } 136 138 137 139 if (error_info & CPER_ARM_ERR_VALID_LEVEL) { 138 140 level = ((error_info >> CPER_ARM_ERR_LEVEL_SHIFT) 139 141 & CPER_ARM_ERR_LEVEL_MASK); 140 - switch (type) { 141 - case CPER_ARM_CACHE_ERROR: 142 + if (type & CPER_ARM_CACHE_ERROR) 142 143 printk("%scache level: %d\n", pfx, level); 143 - break; 144 - case CPER_ARM_TLB_ERROR: 144 + 145 + if (type & CPER_ARM_TLB_ERROR) 145 146 printk("%sTLB level: %d\n", pfx, level); 146 - break; 147 - case CPER_ARM_BUS_ERROR: 147 + 148 + if (type & CPER_ARM_BUS_ERROR) 148 149 printk("%saffinity level at which the bus error occurred: %d\n", 149 150 pfx, level); 150 - break; 151 - } 152 151 } 153 152 154 153 if (error_info & CPER_ARM_ERR_VALID_PROC_CONTEXT_CORRUPT) { ··· 232 241 struct cper_arm_err_info *err_info; 233 242 struct cper_arm_ctx_info *ctx_info; 234 243 char newpfx[64], infopfx[ARRAY_SIZE(newpfx) + 1]; 244 + char error_type[120]; 235 245 236 246 printk("%sMIDR: 0x%016llx\n", pfx, proc->midr); 237 247 ··· 281 289 newpfx); 282 290 } 283 291 284 - printk("%serror_type: %d, %s\n", newpfx, err_info->type, 285 - err_info->type < ARRAY_SIZE(cper_proc_error_type_strs) ? 286 - cper_proc_error_type_strs[err_info->type] : "unknown"); 292 + cper_bits_to_str(error_type, sizeof(error_type), 293 + FIELD_GET(CPER_ARM_ERR_TYPE_MASK, err_info->type), 294 + cper_proc_error_type_strs, 295 + ARRAY_SIZE(cper_proc_error_type_strs)); 296 + 297 + printk("%serror_type: 0x%02x: %s%s\n", newpfx, err_info->type, 298 + error_type, 299 + (err_info->type & ~CPER_ARM_ERR_TYPE_MASK) ? " with reserved bit(s)" : ""); 300 + 287 301 if (err_info->validation_bits & CPER_ARM_INFO_VALID_ERR_INFO) { 288 302 printk("%serror_info: 0x%016llx\n", newpfx, 289 303 err_info->error_info);
+5 -5
include/linux/cper.h
··· 297 297 #define CPER_ARM_INFO_FLAGS_PROPAGATED BIT(2) 298 298 #define CPER_ARM_INFO_FLAGS_OVERFLOW BIT(3) 299 299 300 - #define CPER_ARM_CACHE_ERROR 0 301 - #define CPER_ARM_TLB_ERROR 1 302 - #define CPER_ARM_BUS_ERROR 2 303 - #define CPER_ARM_VENDOR_ERROR 3 304 - #define CPER_ARM_MAX_TYPE CPER_ARM_VENDOR_ERROR 300 + #define CPER_ARM_ERR_TYPE_MASK GENMASK(4,1) 301 + #define CPER_ARM_CACHE_ERROR BIT(1) 302 + #define CPER_ARM_TLB_ERROR BIT(2) 303 + #define CPER_ARM_BUS_ERROR BIT(3) 304 + #define CPER_ARM_VENDOR_ERROR BIT(4) 305 305 306 306 #define CPER_ARM_ERR_VALID_TRANSACTION_TYPE BIT(0) 307 307 #define CPER_ARM_ERR_VALID_OPERATION_TYPE BIT(1)