Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/firmware/efi/cper-arm.c
26428 views
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
20
static 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
32
static const char * const arm_err_trans_type_strs[] = {
33
"Instruction",
34
"Data Access",
35
"Generic",
36
};
37
38
static 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
48
static 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
62
static 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
74
static 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
81
static 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
88
static 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
/* If the type is unknown, bail. */
97
if (type > CPER_ARM_MAX_TYPE)
98
return;
99
100
/*
101
* Vendor type errors have error information values that are vendor
102
* specific.
103
*/
104
if (type == CPER_ARM_VENDOR_ERROR)
105
return;
106
107
if (error_info & CPER_ARM_ERR_VALID_TRANSACTION_TYPE) {
108
trans_type = ((error_info >> CPER_ARM_ERR_TRANSACTION_SHIFT)
109
& CPER_ARM_ERR_TRANSACTION_MASK);
110
if (trans_type < ARRAY_SIZE(arm_err_trans_type_strs)) {
111
printk("%stransaction type: %s\n", pfx,
112
arm_err_trans_type_strs[trans_type]);
113
}
114
}
115
116
if (error_info & CPER_ARM_ERR_VALID_OPERATION_TYPE) {
117
op_type = ((error_info >> CPER_ARM_ERR_OPERATION_SHIFT)
118
& CPER_ARM_ERR_OPERATION_MASK);
119
switch (type) {
120
case CPER_ARM_CACHE_ERROR:
121
if (op_type < ARRAY_SIZE(arm_cache_err_op_strs)) {
122
printk("%soperation type: %s\n", pfx,
123
arm_cache_err_op_strs[op_type]);
124
}
125
break;
126
case CPER_ARM_TLB_ERROR:
127
if (op_type < ARRAY_SIZE(arm_tlb_err_op_strs)) {
128
printk("%soperation type: %s\n", pfx,
129
arm_tlb_err_op_strs[op_type]);
130
}
131
break;
132
case CPER_ARM_BUS_ERROR:
133
if (op_type < ARRAY_SIZE(arm_bus_err_op_strs)) {
134
printk("%soperation type: %s\n", pfx,
135
arm_bus_err_op_strs[op_type]);
136
}
137
break;
138
}
139
}
140
141
if (error_info & CPER_ARM_ERR_VALID_LEVEL) {
142
level = ((error_info >> CPER_ARM_ERR_LEVEL_SHIFT)
143
& CPER_ARM_ERR_LEVEL_MASK);
144
switch (type) {
145
case CPER_ARM_CACHE_ERROR:
146
printk("%scache level: %d\n", pfx, level);
147
break;
148
case CPER_ARM_TLB_ERROR:
149
printk("%sTLB level: %d\n", pfx, level);
150
break;
151
case CPER_ARM_BUS_ERROR:
152
printk("%saffinity level at which the bus error occurred: %d\n",
153
pfx, level);
154
break;
155
}
156
}
157
158
if (error_info & CPER_ARM_ERR_VALID_PROC_CONTEXT_CORRUPT) {
159
proc_context_corrupt = ((error_info >> CPER_ARM_ERR_PC_CORRUPT_SHIFT)
160
& CPER_ARM_ERR_PC_CORRUPT_MASK);
161
if (proc_context_corrupt)
162
printk("%sprocessor context corrupted\n", pfx);
163
else
164
printk("%sprocessor context not corrupted\n", pfx);
165
}
166
167
if (error_info & CPER_ARM_ERR_VALID_CORRECTED) {
168
corrected = ((error_info >> CPER_ARM_ERR_CORRECTED_SHIFT)
169
& CPER_ARM_ERR_CORRECTED_MASK);
170
if (corrected)
171
printk("%sthe error has been corrected\n", pfx);
172
else
173
printk("%sthe error has not been corrected\n", pfx);
174
}
175
176
if (error_info & CPER_ARM_ERR_VALID_PRECISE_PC) {
177
precise_pc = ((error_info >> CPER_ARM_ERR_PRECISE_PC_SHIFT)
178
& CPER_ARM_ERR_PRECISE_PC_MASK);
179
if (precise_pc)
180
printk("%sPC is precise\n", pfx);
181
else
182
printk("%sPC is imprecise\n", pfx);
183
}
184
185
if (error_info & CPER_ARM_ERR_VALID_RESTARTABLE_PC) {
186
restartable_pc = ((error_info >> CPER_ARM_ERR_RESTARTABLE_PC_SHIFT)
187
& CPER_ARM_ERR_RESTARTABLE_PC_MASK);
188
if (restartable_pc)
189
printk("%sProgram execution can be restarted reliably at the PC associated with the error.\n", pfx);
190
}
191
192
/* The rest of the fields are specific to bus errors */
193
if (type != CPER_ARM_BUS_ERROR)
194
return;
195
196
if (error_info & CPER_ARM_ERR_VALID_PARTICIPATION_TYPE) {
197
participation_type = ((error_info >> CPER_ARM_ERR_PARTICIPATION_TYPE_SHIFT)
198
& CPER_ARM_ERR_PARTICIPATION_TYPE_MASK);
199
if (participation_type < ARRAY_SIZE(arm_bus_err_part_type_strs)) {
200
printk("%sparticipation type: %s\n", pfx,
201
arm_bus_err_part_type_strs[participation_type]);
202
}
203
}
204
205
if (error_info & CPER_ARM_ERR_VALID_TIME_OUT) {
206
time_out = ((error_info >> CPER_ARM_ERR_TIME_OUT_SHIFT)
207
& CPER_ARM_ERR_TIME_OUT_MASK);
208
if (time_out)
209
printk("%srequest timed out\n", pfx);
210
}
211
212
if (error_info & CPER_ARM_ERR_VALID_ADDRESS_SPACE) {
213
address_space = ((error_info >> CPER_ARM_ERR_ADDRESS_SPACE_SHIFT)
214
& CPER_ARM_ERR_ADDRESS_SPACE_MASK);
215
if (address_space < ARRAY_SIZE(arm_bus_err_addr_space_strs)) {
216
printk("%saddress space: %s\n", pfx,
217
arm_bus_err_addr_space_strs[address_space]);
218
}
219
}
220
221
if (error_info & CPER_ARM_ERR_VALID_MEM_ATTRIBUTES) {
222
mem_attributes = ((error_info >> CPER_ARM_ERR_MEM_ATTRIBUTES_SHIFT)
223
& CPER_ARM_ERR_MEM_ATTRIBUTES_MASK);
224
printk("%smemory access attributes:0x%x\n", pfx, mem_attributes);
225
}
226
227
if (error_info & CPER_ARM_ERR_VALID_ACCESS_MODE) {
228
access_mode = ((error_info >> CPER_ARM_ERR_ACCESS_MODE_SHIFT)
229
& CPER_ARM_ERR_ACCESS_MODE_MASK);
230
if (access_mode)
231
printk("%saccess mode: normal\n", pfx);
232
else
233
printk("%saccess mode: secure\n", pfx);
234
}
235
}
236
237
void cper_print_proc_arm(const char *pfx,
238
const struct cper_sec_proc_arm *proc)
239
{
240
int i, len, max_ctx_type;
241
struct cper_arm_err_info *err_info;
242
struct cper_arm_ctx_info *ctx_info;
243
char newpfx[64], infopfx[64];
244
245
printk("%sMIDR: 0x%016llx\n", pfx, proc->midr);
246
247
len = proc->section_length - (sizeof(*proc) +
248
proc->err_info_num * (sizeof(*err_info)));
249
if (len < 0) {
250
printk("%ssection length: %d\n", pfx, proc->section_length);
251
printk("%ssection length is too small\n", pfx);
252
printk("%sfirmware-generated error record is incorrect\n", pfx);
253
printk("%sERR_INFO_NUM is %d\n", pfx, proc->err_info_num);
254
return;
255
}
256
257
if (proc->validation_bits & CPER_ARM_VALID_MPIDR)
258
printk("%sMultiprocessor Affinity Register (MPIDR): 0x%016llx\n",
259
pfx, proc->mpidr);
260
261
if (proc->validation_bits & CPER_ARM_VALID_AFFINITY_LEVEL)
262
printk("%serror affinity level: %d\n", pfx,
263
proc->affinity_level);
264
265
if (proc->validation_bits & CPER_ARM_VALID_RUNNING_STATE) {
266
printk("%srunning state: 0x%x\n", pfx, proc->running_state);
267
printk("%sPower State Coordination Interface state: %d\n",
268
pfx, proc->psci_state);
269
}
270
271
snprintf(newpfx, sizeof(newpfx), "%s ", pfx);
272
273
err_info = (struct cper_arm_err_info *)(proc + 1);
274
for (i = 0; i < proc->err_info_num; i++) {
275
printk("%sError info structure %d:\n", pfx, i);
276
277
printk("%snum errors: %d\n", pfx, err_info->multiple_error + 1);
278
279
if (err_info->validation_bits & CPER_ARM_INFO_VALID_FLAGS) {
280
if (err_info->flags & CPER_ARM_INFO_FLAGS_FIRST)
281
printk("%sfirst error captured\n", newpfx);
282
if (err_info->flags & CPER_ARM_INFO_FLAGS_LAST)
283
printk("%slast error captured\n", newpfx);
284
if (err_info->flags & CPER_ARM_INFO_FLAGS_PROPAGATED)
285
printk("%spropagated error captured\n",
286
newpfx);
287
if (err_info->flags & CPER_ARM_INFO_FLAGS_OVERFLOW)
288
printk("%soverflow occurred, error info is incomplete\n",
289
newpfx);
290
}
291
292
printk("%serror_type: %d, %s\n", newpfx, err_info->type,
293
err_info->type < ARRAY_SIZE(cper_proc_error_type_strs) ?
294
cper_proc_error_type_strs[err_info->type] : "unknown");
295
if (err_info->validation_bits & CPER_ARM_INFO_VALID_ERR_INFO) {
296
printk("%serror_info: 0x%016llx\n", newpfx,
297
err_info->error_info);
298
snprintf(infopfx, sizeof(infopfx), "%s ", newpfx);
299
cper_print_arm_err_info(infopfx, err_info->type,
300
err_info->error_info);
301
}
302
if (err_info->validation_bits & CPER_ARM_INFO_VALID_VIRT_ADDR)
303
printk("%svirtual fault address: 0x%016llx\n",
304
newpfx, err_info->virt_fault_addr);
305
if (err_info->validation_bits & CPER_ARM_INFO_VALID_PHYSICAL_ADDR)
306
printk("%sphysical fault address: 0x%016llx\n",
307
newpfx, err_info->physical_fault_addr);
308
err_info += 1;
309
}
310
311
ctx_info = (struct cper_arm_ctx_info *)err_info;
312
max_ctx_type = ARRAY_SIZE(arm_reg_ctx_strs) - 1;
313
for (i = 0; i < proc->context_info_num; i++) {
314
int size = ALIGN(sizeof(*ctx_info) + ctx_info->size, 16);
315
316
printk("%sContext info structure %d:\n", pfx, i);
317
if (len < size) {
318
printk("%ssection length is too small\n", newpfx);
319
printk("%sfirmware-generated error record is incorrect\n", pfx);
320
return;
321
}
322
if (ctx_info->type > max_ctx_type) {
323
printk("%sInvalid context type: %d (max: %d)\n",
324
newpfx, ctx_info->type, max_ctx_type);
325
return;
326
}
327
printk("%sregister context type: %s\n", newpfx,
328
arm_reg_ctx_strs[ctx_info->type]);
329
print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4,
330
(ctx_info + 1), ctx_info->size, 0);
331
len -= size;
332
ctx_info = (struct cper_arm_ctx_info *)((long)ctx_info + size);
333
}
334
335
if (len > 0) {
336
printk("%sVendor specific error info has %u bytes:\n", pfx,
337
len);
338
print_hex_dump(newpfx, "", DUMP_PREFIX_OFFSET, 16, 4, ctx_info,
339
len, true);
340
}
341
}
342
343