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