File Index
Files and directories
Sign in
FILE

cper-arm.c

File preview with syntax highlighting.

linux-6.19.14/drivers/firmware/efi/cper-arm.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * UEFI Common Platform Error Record (CPER) support
  4 *
  5 * Copyright (C) 2017, The Linux Foundation. All rights reserved.
  6 */
  7
  8#include <linux/kernel.h>
  9#include <linux/module.h>
 10#include <linux/time.h>
 11#include <linux/cper.h>
 12#include <linux/dmi.h>
 13#include <linux/acpi.h>
 14#include <linux/pci.h>
 15#include <linux/printk.h>
 16#include <linux/bcd.h>
 17#include <acpi/ghes.h>
 18#include <ras/ras_event.h>
 19
 20static const char * const arm_reg_ctx_strs[] = {
 21	"AArch32 general purpose registers",
 22	"AArch32 EL1 context registers",
 23	"AArch32 EL2 context registers",
 24	"AArch32 secure context registers",
 25	"AArch64 general purpose registers",
 26	"AArch64 EL1 context registers",
 27	"AArch64 EL2 context registers",
 28	"AArch64 EL3 context registers",
 29	"Misc. system register structure",
 30};
 31
 32static const char * const arm_err_trans_type_strs[] = {
 33	"Instruction",
 34	"Data Access",
 35	"Generic",
 36};
 37
 38static const char * const arm_bus_err_op_strs[] = {
 39	"Generic error (type cannot be determined)",
 40	"Generic read (type of instruction or data request cannot be determined)",
 41	"Generic write (type of instruction of data request cannot be determined)",
 42	"Data read",
 43	"Data write",
 44	"Instruction fetch",
 45	"Prefetch",
 46};
 47
 48static const char * const arm_cache_err_op_strs[] = {
 49	"Generic error (type cannot be determined)",
 50	"Generic read (type of instruction or data request cannot be determined)",
 51	"Generic write (type of instruction of data request cannot be determined)",
 52	"Data read",
 53	"Data write",
 54	"Instruction fetch",
 55	"Prefetch",
 56	"Eviction",
 57	"Snooping (processor initiated a cache snoop that resulted in an error)",
 58	"Snooped (processor raised a cache error caused by another processor or device snooping its cache)",
 59	"Management",
 60};
 61
 62static const char * const arm_tlb_err_op_strs[] = {
 63	"Generic error (type cannot be determined)",
 64	"Generic read (type of instruction or data request cannot be determined)",
 65	"Generic write (type of instruction of data request cannot be determined)",
 66	"Data read",
 67	"Data write",
 68	"Instruction fetch",
 69	"Prefetch",
 70	"Local management operation (processor initiated a TLB management operation that resulted in an error)",
 71	"External management operation (processor raised a TLB error caused by another processor or device broadcasting TLB operations)",
 72};
 73
 74static const char * const arm_bus_err_part_type_strs[] = {
 75	"Local processor originated request",
 76	"Local processor responded to request",
 77	"Local processor observed",
 78	"Generic",
 79};
 80
 81static const char * const arm_bus_err_addr_space_strs[] = {
 82	"External Memory Access",
 83	"Internal Memory Access",
 84	"Unknown",
 85	"Device Memory Access",
 86};
 87
 88static void cper_print_arm_err_info(const char *pfx, u32 type,
 89				    u64 error_info)
 90{
 91	u8 trans_type, op_type, level, participation_type, address_space;
 92	u16 mem_attributes;
 93	bool proc_context_corrupt, corrected, precise_pc, restartable_pc;
 94	bool time_out, access_mode;
 95
 96	/*
 97	 * Vendor type errors have error information values that are vendor
 98	 * specific.
 99	 */
100	if (type & CPER_ARM_VENDOR_ERROR)
101		return;
102
103	if (error_info & CPER_ARM_ERR_VALID_TRANSACTION_TYPE) {
104		trans_type = ((error_info >> CPER_ARM_ERR_TRANSACTION_SHIFT)
105			      & CPER_ARM_ERR_TRANSACTION_MASK);
106		if (trans_type < ARRAY_SIZE(arm_err_trans_type_strs)) {
107			printk("%stransaction type: %s\n", pfx,
108			       arm_err_trans_type_strs[trans_type]);
109		}
110	}
111
112	if (error_info & CPER_ARM_ERR_VALID_OPERATION_TYPE) {
113		op_type = ((error_info >> CPER_ARM_ERR_OPERATION_SHIFT)
114			   & CPER_ARM_ERR_OPERATION_MASK);
115		if (type & CPER_ARM_CACHE_ERROR) {
116			if (op_type < ARRAY_SIZE(arm_cache_err_op_strs)) {
117				printk("%scache error, operation type: %s\n", pfx,
118				       arm_cache_err_op_strs[op_type]);
119			}
120		}
121		if (type & CPER_ARM_TLB_ERROR) {
122			if (op_type < ARRAY_SIZE(arm_tlb_err_op_strs)) {
123				printk("%sTLB error, operation type: %s\n", pfx,
124				       arm_tlb_err_op_strs[op_type]);
125			}
126		}
127		if (type & CPER_ARM_BUS_ERROR) {
128			if (op_type < ARRAY_SIZE(arm_bus_err_op_strs)) {
129				printk("%sbus error, operation type: %s\n", pfx,
130				       arm_bus_err_op_strs[op_type]);
131			}
132		}
133	}
134
135	if (error_info & CPER_ARM_ERR_VALID_LEVEL) {
136		level = ((error_info >> CPER_ARM_ERR_LEVEL_SHIFT)
137			 & CPER_ARM_ERR_LEVEL_MASK);
138		if (type & CPER_ARM_CACHE_ERROR)
139			printk("%scache level: %d\n", pfx, level);
140
141		if (type & CPER_ARM_TLB_ERROR)
142			printk("%sTLB level: %d\n", pfx, level);
143
144		if (type & CPER_ARM_BUS_ERROR)
145			printk("%saffinity level at which the bus error occurred: %d\n",
146			       pfx, level);
147	}
148
149	if (error_info & CPER_ARM_ERR_VALID_PROC_CONTEXT_CORRUPT) {
150		proc_context_corrupt = ((error_info >> CPER_ARM_ERR_PC_CORRUPT_SHIFT)
151					& CPER_ARM_ERR_PC_CORRUPT_MASK);
152		if (proc_context_corrupt)
153			printk("%sprocessor context corrupted\n", pfx);
154		else
155			printk("%sprocessor context not corrupted\n", pfx);
156	}
157
158	if (error_info & CPER_ARM_ERR_VALID_CORRECTED) {
159		corrected = ((error_info >> CPER_ARM_ERR_CORRECTED_SHIFT)
160			     & CPER_ARM_ERR_CORRECTED_MASK);
161		if (corrected)
162			printk("%sthe error has been corrected\n", pfx);
163		else
164			printk("%sthe error has not been corrected\n", pfx);
165	}
166
167	if (error_info & CPER_ARM_ERR_VALID_PRECISE_PC) {
168		precise_pc = ((error_info >> CPER_ARM_ERR_PRECISE_PC_SHIFT)
169			      & CPER_ARM_ERR_PRECISE_PC_MASK);
170		if (precise_pc)
171			printk("%sPC is precise\n", pfx);
172		else
173			printk("%sPC is imprecise\n", pfx);
174	}
175
176	if (error_info & CPER_ARM_ERR_VALID_RESTARTABLE_PC) {
177		restartable_pc = ((error_info >> CPER_ARM_ERR_RESTARTABLE_PC_SHIFT)
178				  & CPER_ARM_ERR_RESTARTABLE_PC_MASK);
179		if (restartable_pc)
180			printk("%sProgram execution can be restarted reliably at the PC associated with the error.\n", pfx);
181	}
182
183	/* The rest of the fields are specific to bus errors */
184	if (type != CPER_ARM_BUS_ERROR)
185		return;
186
187	if (error_info & CPER_ARM_ERR_VALID_PARTICIPATION_TYPE) {
188		participation_type = ((error_info >> CPER_ARM_ERR_PARTICIPATION_TYPE_SHIFT)
189				      & CPER_ARM_ERR_PARTICIPATION_TYPE_MASK);
190		if (participation_type < ARRAY_SIZE(arm_bus_err_part_type_strs)) {
191			printk("%sparticipation type: %s\n", pfx,
192			       arm_bus_err_part_type_strs[participation_type]);
193		}
194	}
195
196	if (error_info & CPER_ARM_ERR_VALID_TIME_OUT) {
197		time_out = ((error_info >> CPER_ARM_ERR_TIME_OUT_SHIFT)
198			    & CPER_ARM_ERR_TIME_OUT_MASK);
199		if (time_out)
200			printk("%srequest timed out\n", pfx);
201	}
202
203	if (error_info & CPER_ARM_ERR_VALID_ADDRESS_SPACE) {
204		address_space = ((error_info >> CPER_ARM_ERR_ADDRESS_SPACE_SHIFT)
205				 & CPER_ARM_ERR_ADDRESS_SPACE_MASK);
206		if (address_space < ARRAY_SIZE(arm_bus_err_addr_space_strs)) {
207			printk("%saddress space: %s\n", pfx,
208			       arm_bus_err_addr_space_strs[address_space]);
209		}
210	}
211
212	if (error_info & CPER_ARM_ERR_VALID_MEM_ATTRIBUTES) {
213		mem_attributes = ((error_info >> CPER_ARM_ERR_MEM_ATTRIBUTES_SHIFT)
214				  & CPER_ARM_ERR_MEM_ATTRIBUTES_MASK);
215		printk("%smemory access attributes:0x%x\n", pfx, mem_attributes);
216	}
217
218	if (error_info & CPER_ARM_ERR_VALID_ACCESS_MODE) {
219		access_mode = ((error_info >> CPER_ARM_ERR_ACCESS_MODE_SHIFT)
220			       & CPER_ARM_ERR_ACCESS_MODE_MASK);
221		if (access_mode)
222			printk("%saccess mode: normal\n", pfx);
223		else
224			printk("%saccess mode: secure\n", pfx);
225	}
226}
227
228void cper_print_proc_arm(const char *pfx,
229			 const struct cper_sec_proc_arm *proc,
230			 u32 length)
231{
232	int i, len, max_ctx_type;
233	struct cper_arm_err_info *err_info;
234	struct cper_arm_ctx_info *ctx_info;
235	char newpfx[64], infopfx[ARRAY_SIZE(newpfx) + 1];
236	char error_type[120];
237
238	printk("%sMIDR: 0x%016llx\n", pfx, proc->midr);
239
240	len = proc->section_length - (sizeof(*proc) +
241		proc->err_info_num * (sizeof(*err_info)));
242
243	if (len < 0 || proc->section_length > length) {
244		printk("%ssection length: %d, CPER size: %d\n",
245		       pfx, proc->section_length, length);
246		printk("%ssection length is too %s\n", pfx,
247		       (len < 0) ? "small" : "big");
248		printk("%sfirmware-generated error record is incorrect\n", pfx);
249		printk("%sERR_INFO_NUM is %d\n", pfx, proc->err_info_num);
250		return;
251	}
252
253	if (proc->validation_bits & CPER_ARM_VALID_MPIDR)
254		printk("%sMultiprocessor Affinity Register (MPIDR): 0x%016llx\n",
255			pfx, proc->mpidr);
256
257	if (proc->validation_bits & CPER_ARM_VALID_AFFINITY_LEVEL)
258		printk("%serror affinity level: %d\n", pfx,
259			proc->affinity_level);
260
261	if (proc->validation_bits & CPER_ARM_VALID_RUNNING_STATE) {
262		printk("%srunning state: 0x%x\n", pfx, proc->running_state);
263		printk("%sPower State Coordination Interface state: %d\n",
264			pfx, proc->psci_state);
265	}
266
267	snprintf(newpfx, sizeof(newpfx), "%s ", pfx);
268
269	err_info = (struct cper_arm_err_info *)(proc + 1);
270	for (i = 0; i < proc->err_info_num; i++) {
271		printk("%sError info structure %d:\n", pfx, i);
272
273		printk("%snum errors: %d\n", pfx, err_info->multiple_error + 1);
274
275		if (err_info->validation_bits & CPER_ARM_INFO_VALID_FLAGS) {
276			if (err_info->flags & CPER_ARM_INFO_FLAGS_FIRST)
277				printk("%sfirst error captured\n", newpfx);
278			if (err_info->flags & CPER_ARM_INFO_FLAGS_LAST)
279				printk("%slast error captured\n", newpfx);
280			if (err_info->flags & CPER_ARM_INFO_FLAGS_PROPAGATED)
281				printk("%spropagated error captured\n",
282				       newpfx);
283			if (err_info->flags & CPER_ARM_INFO_FLAGS_OVERFLOW)
284				printk("%soverflow occurred, error info is incomplete\n",
285				       newpfx);
286		}
287
288		cper_bits_to_str(error_type, sizeof(error_type),
289				 FIELD_GET(CPER_ARM_ERR_TYPE_MASK, err_info->type),
290				 cper_proc_error_type_strs,
291				 ARRAY_SIZE(cper_proc_error_type_strs));
292
293		printk("%serror_type: 0x%02x: %s%s\n", newpfx, err_info->type,
294		       error_type,
295		       (err_info->type & ~CPER_ARM_ERR_TYPE_MASK) ? " with reserved bit(s)" : "");
296
297		if (err_info->validation_bits & CPER_ARM_INFO_VALID_ERR_INFO) {
298			printk("%serror_info: 0x%016llx\n", newpfx,
299			       err_info->error_info);
300			snprintf(infopfx, sizeof(infopfx), "%s ", newpfx);
301			cper_print_arm_err_info(infopfx, err_info->type,
302						err_info->error_info);
303		}
304		if (err_info->validation_bits & CPER_ARM_INFO_VALID_VIRT_ADDR)
305			printk("%svirtual fault address: 0x%016llx\n",
306				newpfx, err_info->virt_fault_addr);
307		if (err_info->validation_bits & CPER_ARM_INFO_VALID_PHYSICAL_ADDR)
308			printk("%sphysical fault address: 0x%016llx\n",
309				newpfx, err_info->physical_fault_addr);
310		err_info += 1;
311	}
312
313	ctx_info = (struct cper_arm_ctx_info *)err_info;
314	max_ctx_type = ARRAY_SIZE(arm_reg_ctx_strs) - 1;
315	for (i = 0; i < proc->context_info_num; i++) {
316		int size = ALIGN(sizeof(*ctx_info) + ctx_info->size, 16);
317
318		printk("%sContext info structure %d:\n", pfx, i);
319		if (len < size) {
320			printk("%ssection length is too small\n", newpfx);
321			printk("%sfirmware-generated error record is incorrect\n", pfx);
322			return;
323		}
324		if (ctx_info->type > max_ctx_type) {
325			printk("%sInvalid context type: %d (max: %d)\n",
326				newpfx, ctx_info->type, max_ctx_type);
327			return;
328		}
329		printk("%sregister context type: %s\n", newpfx,
330			arm_reg_ctx_strs[ctx_info->type]);
331		print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4,
332				(ctx_info + 1), ctx_info->size, 0);
333		len -= size;
334		ctx_info = (struct cper_arm_ctx_info *)((long)ctx_info + size);
335	}
336
337	if (len > 0) {
338		printk("%sVendor specific error info has %u bytes:\n", pfx,
339		       len);
340		print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, ctx_info,
341				len, true);
342	}
343}
~/ Read-only file preview.