ac33a9fed3414c66dea3e29b562842b434eaced0
[firefly-linux-kernel-4.4.55.git] / drivers / firmware / efi / cper.c
1 /*
2  * UEFI Common Platform Error Record (CPER) support
3  *
4  * Copyright (C) 2010, Intel Corp.
5  *      Author: Huang Ying <ying.huang@intel.com>
6  *
7  * CPER is the format used to describe platform hardware error by
8  * various tables, such as ERST, BERT and HEST etc.
9  *
10  * For more information about CPER, please refer to Appendix N of UEFI
11  * 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
25  */
26
27 #include <linux/kernel.h>
28 #include <linux/module.h>
29 #include <linux/time.h>
30 #include <linux/cper.h>
31 #include <linux/dmi.h>
32 #include <linux/acpi.h>
33 #include <linux/pci.h>
34 #include <linux/aer.h>
35
36 #define INDENT_SP       " "
37
38 static char rcd_decode_str[CPER_REC_LEN];
39
40 /*
41  * CPER record ID need to be unique even after reboot, because record
42  * ID is used as index for ERST storage, while CPER records from
43  * multiple boot may co-exist in ERST.
44  */
45 u64 cper_next_record_id(void)
46 {
47         static atomic64_t seq;
48
49         if (!atomic64_read(&seq))
50                 atomic64_set(&seq, ((u64)get_seconds()) << 32);
51
52         return atomic64_inc_return(&seq);
53 }
54 EXPORT_SYMBOL_GPL(cper_next_record_id);
55
56 static const char * const severity_strs[] = {
57         "recoverable",
58         "fatal",
59         "corrected",
60         "info",
61 };
62
63 const char *cper_severity_str(unsigned int severity)
64 {
65         return severity < ARRAY_SIZE(severity_strs) ?
66                 severity_strs[severity] : "unknown";
67 }
68 EXPORT_SYMBOL_GPL(cper_severity_str);
69
70 /*
71  * cper_print_bits - print strings for set bits
72  * @pfx: prefix for each line, including log level and prefix string
73  * @bits: bit mask
74  * @strs: string array, indexed by bit position
75  * @strs_size: size of the string array: @strs
76  *
77  * For each set bit in @bits, print the corresponding string in @strs.
78  * If the output length is longer than 80, multiple line will be
79  * printed, with @pfx is printed at the beginning of each line.
80  */
81 void cper_print_bits(const char *pfx, unsigned int bits,
82                      const char * const strs[], unsigned int strs_size)
83 {
84         int i, len = 0;
85         const char *str;
86         char buf[84];
87
88         for (i = 0; i < strs_size; i++) {
89                 if (!(bits & (1U << i)))
90                         continue;
91                 str = strs[i];
92                 if (!str)
93                         continue;
94                 if (len && len + strlen(str) + 2 > 80) {
95                         printk("%s\n", buf);
96                         len = 0;
97                 }
98                 if (!len)
99                         len = snprintf(buf, sizeof(buf), "%s%s", pfx, str);
100                 else
101                         len += snprintf(buf+len, sizeof(buf)-len, ", %s", str);
102         }
103         if (len)
104                 printk("%s\n", buf);
105 }
106
107 static const char * const proc_type_strs[] = {
108         "IA32/X64",
109         "IA64",
110 };
111
112 static const char * const proc_isa_strs[] = {
113         "IA32",
114         "IA64",
115         "X64",
116 };
117
118 static const char * const proc_error_type_strs[] = {
119         "cache error",
120         "TLB error",
121         "bus error",
122         "micro-architectural error",
123 };
124
125 static const char * const proc_op_strs[] = {
126         "unknown or generic",
127         "data read",
128         "data write",
129         "instruction execution",
130 };
131
132 static const char * const proc_flag_strs[] = {
133         "restartable",
134         "precise IP",
135         "overflow",
136         "corrected",
137 };
138
139 static void cper_print_proc_generic(const char *pfx,
140                                     const struct cper_sec_proc_generic *proc)
141 {
142         if (proc->validation_bits & CPER_PROC_VALID_TYPE)
143                 printk("%s""processor_type: %d, %s\n", pfx, proc->proc_type,
144                        proc->proc_type < ARRAY_SIZE(proc_type_strs) ?
145                        proc_type_strs[proc->proc_type] : "unknown");
146         if (proc->validation_bits & CPER_PROC_VALID_ISA)
147                 printk("%s""processor_isa: %d, %s\n", pfx, proc->proc_isa,
148                        proc->proc_isa < ARRAY_SIZE(proc_isa_strs) ?
149                        proc_isa_strs[proc->proc_isa] : "unknown");
150         if (proc->validation_bits & CPER_PROC_VALID_ERROR_TYPE) {
151                 printk("%s""error_type: 0x%02x\n", pfx, proc->proc_error_type);
152                 cper_print_bits(pfx, proc->proc_error_type,
153                                 proc_error_type_strs,
154                                 ARRAY_SIZE(proc_error_type_strs));
155         }
156         if (proc->validation_bits & CPER_PROC_VALID_OPERATION)
157                 printk("%s""operation: %d, %s\n", pfx, proc->operation,
158                        proc->operation < ARRAY_SIZE(proc_op_strs) ?
159                        proc_op_strs[proc->operation] : "unknown");
160         if (proc->validation_bits & CPER_PROC_VALID_FLAGS) {
161                 printk("%s""flags: 0x%02x\n", pfx, proc->flags);
162                 cper_print_bits(pfx, proc->flags, proc_flag_strs,
163                                 ARRAY_SIZE(proc_flag_strs));
164         }
165         if (proc->validation_bits & CPER_PROC_VALID_LEVEL)
166                 printk("%s""level: %d\n", pfx, proc->level);
167         if (proc->validation_bits & CPER_PROC_VALID_VERSION)
168                 printk("%s""version_info: 0x%016llx\n", pfx, proc->cpu_version);
169         if (proc->validation_bits & CPER_PROC_VALID_ID)
170                 printk("%s""processor_id: 0x%016llx\n", pfx, proc->proc_id);
171         if (proc->validation_bits & CPER_PROC_VALID_TARGET_ADDRESS)
172                 printk("%s""target_address: 0x%016llx\n",
173                        pfx, proc->target_addr);
174         if (proc->validation_bits & CPER_PROC_VALID_REQUESTOR_ID)
175                 printk("%s""requestor_id: 0x%016llx\n",
176                        pfx, proc->requestor_id);
177         if (proc->validation_bits & CPER_PROC_VALID_RESPONDER_ID)
178                 printk("%s""responder_id: 0x%016llx\n",
179                        pfx, proc->responder_id);
180         if (proc->validation_bits & CPER_PROC_VALID_IP)
181                 printk("%s""IP: 0x%016llx\n", pfx, proc->ip);
182 }
183
184 static const char * const mem_err_type_strs[] = {
185         "unknown",
186         "no error",
187         "single-bit ECC",
188         "multi-bit ECC",
189         "single-symbol chipkill ECC",
190         "multi-symbol chipkill ECC",
191         "master abort",
192         "target abort",
193         "parity error",
194         "watchdog timeout",
195         "invalid address",
196         "mirror Broken",
197         "memory sparing",
198         "scrub corrected error",
199         "scrub uncorrected error",
200         "physical memory map-out event",
201 };
202
203 const char *cper_mem_err_type_str(unsigned int etype)
204 {
205         return etype < ARRAY_SIZE(mem_err_type_strs) ?
206                 mem_err_type_strs[etype] : "unknown";
207 }
208 EXPORT_SYMBOL_GPL(cper_mem_err_type_str);
209
210 static int cper_mem_err_location(const struct cper_sec_mem_err *mem, char *msg)
211 {
212         u32 len, n;
213
214         if (!msg)
215                 return 0;
216
217         n = 0;
218         len = CPER_REC_LEN - 1;
219         if (mem->validation_bits & CPER_MEM_VALID_NODE)
220                 n += scnprintf(msg + n, len - n, "node: %d ", mem->node);
221         if (mem->validation_bits & CPER_MEM_VALID_CARD)
222                 n += scnprintf(msg + n, len - n, "card: %d ", mem->card);
223         if (mem->validation_bits & CPER_MEM_VALID_MODULE)
224                 n += scnprintf(msg + n, len - n, "module: %d ", mem->module);
225         if (mem->validation_bits & CPER_MEM_VALID_RANK_NUMBER)
226                 n += scnprintf(msg + n, len - n, "rank: %d ", mem->rank);
227         if (mem->validation_bits & CPER_MEM_VALID_BANK)
228                 n += scnprintf(msg + n, len - n, "bank: %d ", mem->bank);
229         if (mem->validation_bits & CPER_MEM_VALID_DEVICE)
230                 n += scnprintf(msg + n, len - n, "device: %d ", mem->device);
231         if (mem->validation_bits & CPER_MEM_VALID_ROW)
232                 n += scnprintf(msg + n, len - n, "row: %d ", mem->row);
233         if (mem->validation_bits & CPER_MEM_VALID_COLUMN)
234                 n += scnprintf(msg + n, len - n, "column: %d ", mem->column);
235         if (mem->validation_bits & CPER_MEM_VALID_BIT_POSITION)
236                 n += scnprintf(msg + n, len - n, "bit_position: %d ",
237                                mem->bit_pos);
238         if (mem->validation_bits & CPER_MEM_VALID_REQUESTOR_ID)
239                 n += scnprintf(msg + n, len - n, "requestor_id: 0x%016llx ",
240                                mem->requestor_id);
241         if (mem->validation_bits & CPER_MEM_VALID_RESPONDER_ID)
242                 n += scnprintf(msg + n, len - n, "responder_id: 0x%016llx ",
243                                mem->responder_id);
244         if (mem->validation_bits & CPER_MEM_VALID_TARGET_ID)
245                 scnprintf(msg + n, len - n, "target_id: 0x%016llx ",
246                           mem->target_id);
247
248         msg[n] = '\0';
249         return n;
250 }
251
252 static int cper_dimm_err_location(const struct cper_sec_mem_err *mem, char *msg)
253 {
254         u32 len, n;
255         const char *bank = NULL, *device = NULL;
256
257         if (!msg || !(mem->validation_bits & CPER_MEM_VALID_MODULE_HANDLE))
258                 return 0;
259
260         n = 0;
261         len = CPER_REC_LEN - 1;
262         dmi_memdev_name(mem->mem_dev_handle, &bank, &device);
263         if (bank && device)
264                 n = snprintf(msg, len, "DIMM location: %s %s ", bank, device);
265         else
266                 n = snprintf(msg, len,
267                              "DIMM location: not present. DMI handle: 0x%.4x ",
268                              mem->mem_dev_handle);
269
270         msg[n] = '\0';
271         return n;
272 }
273
274 static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem)
275 {
276         if (mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS)
277                 printk("%s""error_status: 0x%016llx\n", pfx, mem->error_status);
278         if (mem->validation_bits & CPER_MEM_VALID_PA)
279                 printk("%s""physical_address: 0x%016llx\n",
280                        pfx, mem->physical_addr);
281         if (mem->validation_bits & CPER_MEM_VALID_PA_MASK)
282                 printk("%s""physical_address_mask: 0x%016llx\n",
283                        pfx, mem->physical_addr_mask);
284         if (cper_mem_err_location(mem, rcd_decode_str))
285                 printk("%s%s\n", pfx, rcd_decode_str);
286         if (mem->validation_bits & CPER_MEM_VALID_ERROR_TYPE) {
287                 u8 etype = mem->error_type;
288                 printk("%s""error_type: %d, %s\n", pfx, etype,
289                        cper_mem_err_type_str(etype));
290         }
291         if (cper_dimm_err_location(mem, rcd_decode_str))
292                 printk("%s%s\n", pfx, rcd_decode_str);
293 }
294
295 static const char * const pcie_port_type_strs[] = {
296         "PCIe end point",
297         "legacy PCI end point",
298         "unknown",
299         "unknown",
300         "root port",
301         "upstream switch port",
302         "downstream switch port",
303         "PCIe to PCI/PCI-X bridge",
304         "PCI/PCI-X to PCIe bridge",
305         "root complex integrated endpoint device",
306         "root complex event collector",
307 };
308
309 static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie,
310                             const struct acpi_generic_data *gdata)
311 {
312         if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE)
313                 printk("%s""port_type: %d, %s\n", pfx, pcie->port_type,
314                        pcie->port_type < ARRAY_SIZE(pcie_port_type_strs) ?
315                        pcie_port_type_strs[pcie->port_type] : "unknown");
316         if (pcie->validation_bits & CPER_PCIE_VALID_VERSION)
317                 printk("%s""version: %d.%d\n", pfx,
318                        pcie->version.major, pcie->version.minor);
319         if (pcie->validation_bits & CPER_PCIE_VALID_COMMAND_STATUS)
320                 printk("%s""command: 0x%04x, status: 0x%04x\n", pfx,
321                        pcie->command, pcie->status);
322         if (pcie->validation_bits & CPER_PCIE_VALID_DEVICE_ID) {
323                 const __u8 *p;
324                 printk("%s""device_id: %04x:%02x:%02x.%x\n", pfx,
325                        pcie->device_id.segment, pcie->device_id.bus,
326                        pcie->device_id.device, pcie->device_id.function);
327                 printk("%s""slot: %d\n", pfx,
328                        pcie->device_id.slot >> CPER_PCIE_SLOT_SHIFT);
329                 printk("%s""secondary_bus: 0x%02x\n", pfx,
330                        pcie->device_id.secondary_bus);
331                 printk("%s""vendor_id: 0x%04x, device_id: 0x%04x\n", pfx,
332                        pcie->device_id.vendor_id, pcie->device_id.device_id);
333                 p = pcie->device_id.class_code;
334                 printk("%s""class_code: %02x%02x%02x\n", pfx, p[0], p[1], p[2]);
335         }
336         if (pcie->validation_bits & CPER_PCIE_VALID_SERIAL_NUMBER)
337                 printk("%s""serial number: 0x%04x, 0x%04x\n", pfx,
338                        pcie->serial_number.lower, pcie->serial_number.upper);
339         if (pcie->validation_bits & CPER_PCIE_VALID_BRIDGE_CONTROL_STATUS)
340                 printk(
341         "%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n",
342         pfx, pcie->bridge.secondary_status, pcie->bridge.control);
343 }
344
345 static void cper_estatus_print_section(
346         const char *pfx, const struct acpi_generic_data *gdata, int sec_no)
347 {
348         uuid_le *sec_type = (uuid_le *)gdata->section_type;
349         __u16 severity;
350         char newpfx[64];
351
352         severity = gdata->error_severity;
353         printk("%s""Error %d, type: %s\n", pfx, sec_no,
354                cper_severity_str(severity));
355         if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID)
356                 printk("%s""fru_id: %pUl\n", pfx, (uuid_le *)gdata->fru_id);
357         if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT)
358                 printk("%s""fru_text: %.20s\n", pfx, gdata->fru_text);
359
360         snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP);
361         if (!uuid_le_cmp(*sec_type, CPER_SEC_PROC_GENERIC)) {
362                 struct cper_sec_proc_generic *proc_err = (void *)(gdata + 1);
363                 printk("%s""section_type: general processor error\n", newpfx);
364                 if (gdata->error_data_length >= sizeof(*proc_err))
365                         cper_print_proc_generic(newpfx, proc_err);
366                 else
367                         goto err_section_too_small;
368         } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PLATFORM_MEM)) {
369                 struct cper_sec_mem_err *mem_err = (void *)(gdata + 1);
370                 printk("%s""section_type: memory error\n", newpfx);
371                 if (gdata->error_data_length >= sizeof(*mem_err))
372                         cper_print_mem(newpfx, mem_err);
373                 else
374                         goto err_section_too_small;
375         } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PCIE)) {
376                 struct cper_sec_pcie *pcie = (void *)(gdata + 1);
377                 printk("%s""section_type: PCIe error\n", newpfx);
378                 if (gdata->error_data_length >= sizeof(*pcie))
379                         cper_print_pcie(newpfx, pcie, gdata);
380                 else
381                         goto err_section_too_small;
382         } else
383                 printk("%s""section type: unknown, %pUl\n", newpfx, sec_type);
384
385         return;
386
387 err_section_too_small:
388         pr_err(FW_WARN "error section length is too small\n");
389 }
390
391 void cper_estatus_print(const char *pfx,
392                         const struct acpi_generic_status *estatus)
393 {
394         struct acpi_generic_data *gdata;
395         unsigned int data_len, gedata_len;
396         int sec_no = 0;
397         char newpfx[64];
398         __u16 severity;
399
400         severity = estatus->error_severity;
401         if (severity == CPER_SEV_CORRECTED)
402                 printk("%s%s\n", pfx,
403                        "It has been corrected by h/w "
404                        "and requires no further action");
405         printk("%s""event severity: %s\n", pfx, cper_severity_str(severity));
406         data_len = estatus->data_length;
407         gdata = (struct acpi_generic_data *)(estatus + 1);
408         snprintf(newpfx, sizeof(newpfx), "%s%s", pfx, INDENT_SP);
409         while (data_len >= sizeof(*gdata)) {
410                 gedata_len = gdata->error_data_length;
411                 cper_estatus_print_section(newpfx, gdata, sec_no);
412                 data_len -= gedata_len + sizeof(*gdata);
413                 gdata = (void *)(gdata + 1) + gedata_len;
414                 sec_no++;
415         }
416 }
417 EXPORT_SYMBOL_GPL(cper_estatus_print);
418
419 int cper_estatus_check_header(const struct acpi_generic_status *estatus)
420 {
421         if (estatus->data_length &&
422             estatus->data_length < sizeof(struct acpi_generic_data))
423                 return -EINVAL;
424         if (estatus->raw_data_length &&
425             estatus->raw_data_offset < sizeof(*estatus) + estatus->data_length)
426                 return -EINVAL;
427
428         return 0;
429 }
430 EXPORT_SYMBOL_GPL(cper_estatus_check_header);
431
432 int cper_estatus_check(const struct acpi_generic_status *estatus)
433 {
434         struct acpi_generic_data *gdata;
435         unsigned int data_len, gedata_len;
436         int rc;
437
438         rc = cper_estatus_check_header(estatus);
439         if (rc)
440                 return rc;
441         data_len = estatus->data_length;
442         gdata = (struct acpi_generic_data *)(estatus + 1);
443         while (data_len >= sizeof(*gdata)) {
444                 gedata_len = gdata->error_data_length;
445                 if (gedata_len > data_len - sizeof(*gdata))
446                         return -EINVAL;
447                 data_len -= gedata_len + sizeof(*gdata);
448                 gdata = (void *)(gdata + 1) + gedata_len;
449         }
450         if (data_len)
451                 return -EINVAL;
452
453         return 0;
454 }
455 EXPORT_SYMBOL_GPL(cper_estatus_check);