Merge branch 'rmobile-latest' of git://git.kernel.org/pub/scm/linux/kernel/git/lethal...
[pandora-kernel.git] / drivers / acpi / apei / 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 APEI 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.3.
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/acpi.h>
32 #include <linux/aer.h>
33
34 /*
35  * CPER record ID need to be unique even after reboot, because record
36  * ID is used as index for ERST storage, while CPER records from
37  * multiple boot may co-exist in ERST.
38  */
39 u64 cper_next_record_id(void)
40 {
41         static atomic64_t seq;
42
43         if (!atomic64_read(&seq))
44                 atomic64_set(&seq, ((u64)get_seconds()) << 32);
45
46         return atomic64_inc_return(&seq);
47 }
48 EXPORT_SYMBOL_GPL(cper_next_record_id);
49
50 static const char *cper_severity_strs[] = {
51         "recoverable",
52         "fatal",
53         "corrected",
54         "info",
55 };
56
57 static const char *cper_severity_str(unsigned int severity)
58 {
59         return severity < ARRAY_SIZE(cper_severity_strs) ?
60                 cper_severity_strs[severity] : "unknown";
61 }
62
63 /*
64  * cper_print_bits - print strings for set bits
65  * @pfx: prefix for each line, including log level and prefix string
66  * @bits: bit mask
67  * @strs: string array, indexed by bit position
68  * @strs_size: size of the string array: @strs
69  *
70  * For each set bit in @bits, print the corresponding string in @strs.
71  * If the output length is longer than 80, multiple line will be
72  * printed, with @pfx is printed at the beginning of each line.
73  */
74 void cper_print_bits(const char *pfx, unsigned int bits,
75                      const char *strs[], unsigned int strs_size)
76 {
77         int i, len = 0;
78         const char *str;
79         char buf[84];
80
81         for (i = 0; i < strs_size; i++) {
82                 if (!(bits & (1U << i)))
83                         continue;
84                 str = strs[i];
85                 if (!str)
86                         continue;
87                 if (len && len + strlen(str) + 2 > 80) {
88                         printk("%s\n", buf);
89                         len = 0;
90                 }
91                 if (!len)
92                         len = snprintf(buf, sizeof(buf), "%s%s", pfx, str);
93                 else
94                         len += snprintf(buf+len, sizeof(buf)-len, ", %s", str);
95         }
96         if (len)
97                 printk("%s\n", buf);
98 }
99
100 static const char *cper_proc_type_strs[] = {
101         "IA32/X64",
102         "IA64",
103 };
104
105 static const char *cper_proc_isa_strs[] = {
106         "IA32",
107         "IA64",
108         "X64",
109 };
110
111 static const char *cper_proc_error_type_strs[] = {
112         "cache error",
113         "TLB error",
114         "bus error",
115         "micro-architectural error",
116 };
117
118 static const char *cper_proc_op_strs[] = {
119         "unknown or generic",
120         "data read",
121         "data write",
122         "instruction execution",
123 };
124
125 static const char *cper_proc_flag_strs[] = {
126         "restartable",
127         "precise IP",
128         "overflow",
129         "corrected",
130 };
131
132 static void cper_print_proc_generic(const char *pfx,
133                                     const struct cper_sec_proc_generic *proc)
134 {
135         if (proc->validation_bits & CPER_PROC_VALID_TYPE)
136                 printk("%s""processor_type: %d, %s\n", pfx, proc->proc_type,
137                        proc->proc_type < ARRAY_SIZE(cper_proc_type_strs) ?
138                        cper_proc_type_strs[proc->proc_type] : "unknown");
139         if (proc->validation_bits & CPER_PROC_VALID_ISA)
140                 printk("%s""processor_isa: %d, %s\n", pfx, proc->proc_isa,
141                        proc->proc_isa < ARRAY_SIZE(cper_proc_isa_strs) ?
142                        cper_proc_isa_strs[proc->proc_isa] : "unknown");
143         if (proc->validation_bits & CPER_PROC_VALID_ERROR_TYPE) {
144                 printk("%s""error_type: 0x%02x\n", pfx, proc->proc_error_type);
145                 cper_print_bits(pfx, proc->proc_error_type,
146                                 cper_proc_error_type_strs,
147                                 ARRAY_SIZE(cper_proc_error_type_strs));
148         }
149         if (proc->validation_bits & CPER_PROC_VALID_OPERATION)
150                 printk("%s""operation: %d, %s\n", pfx, proc->operation,
151                        proc->operation < ARRAY_SIZE(cper_proc_op_strs) ?
152                        cper_proc_op_strs[proc->operation] : "unknown");
153         if (proc->validation_bits & CPER_PROC_VALID_FLAGS) {
154                 printk("%s""flags: 0x%02x\n", pfx, proc->flags);
155                 cper_print_bits(pfx, proc->flags, cper_proc_flag_strs,
156                                 ARRAY_SIZE(cper_proc_flag_strs));
157         }
158         if (proc->validation_bits & CPER_PROC_VALID_LEVEL)
159                 printk("%s""level: %d\n", pfx, proc->level);
160         if (proc->validation_bits & CPER_PROC_VALID_VERSION)
161                 printk("%s""version_info: 0x%016llx\n", pfx, proc->cpu_version);
162         if (proc->validation_bits & CPER_PROC_VALID_ID)
163                 printk("%s""processor_id: 0x%016llx\n", pfx, proc->proc_id);
164         if (proc->validation_bits & CPER_PROC_VALID_TARGET_ADDRESS)
165                 printk("%s""target_address: 0x%016llx\n",
166                        pfx, proc->target_addr);
167         if (proc->validation_bits & CPER_PROC_VALID_REQUESTOR_ID)
168                 printk("%s""requestor_id: 0x%016llx\n",
169                        pfx, proc->requestor_id);
170         if (proc->validation_bits & CPER_PROC_VALID_RESPONDER_ID)
171                 printk("%s""responder_id: 0x%016llx\n",
172                        pfx, proc->responder_id);
173         if (proc->validation_bits & CPER_PROC_VALID_IP)
174                 printk("%s""IP: 0x%016llx\n", pfx, proc->ip);
175 }
176
177 static const char *cper_mem_err_type_strs[] = {
178         "unknown",
179         "no error",
180         "single-bit ECC",
181         "multi-bit ECC",
182         "single-symbol chipkill ECC",
183         "multi-symbol chipkill ECC",
184         "master abort",
185         "target abort",
186         "parity error",
187         "watchdog timeout",
188         "invalid address",
189         "mirror Broken",
190         "memory sparing",
191         "scrub corrected error",
192         "scrub uncorrected error",
193 };
194
195 static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem)
196 {
197         if (mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS)
198                 printk("%s""error_status: 0x%016llx\n", pfx, mem->error_status);
199         if (mem->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS)
200                 printk("%s""physical_address: 0x%016llx\n",
201                        pfx, mem->physical_addr);
202         if (mem->validation_bits & CPER_MEM_VALID_PHYSICAL_ADDRESS_MASK)
203                 printk("%s""physical_address_mask: 0x%016llx\n",
204                        pfx, mem->physical_addr_mask);
205         if (mem->validation_bits & CPER_MEM_VALID_NODE)
206                 printk("%s""node: %d\n", pfx, mem->node);
207         if (mem->validation_bits & CPER_MEM_VALID_CARD)
208                 printk("%s""card: %d\n", pfx, mem->card);
209         if (mem->validation_bits & CPER_MEM_VALID_MODULE)
210                 printk("%s""module: %d\n", pfx, mem->module);
211         if (mem->validation_bits & CPER_MEM_VALID_BANK)
212                 printk("%s""bank: %d\n", pfx, mem->bank);
213         if (mem->validation_bits & CPER_MEM_VALID_DEVICE)
214                 printk("%s""device: %d\n", pfx, mem->device);
215         if (mem->validation_bits & CPER_MEM_VALID_ROW)
216                 printk("%s""row: %d\n", pfx, mem->row);
217         if (mem->validation_bits & CPER_MEM_VALID_COLUMN)
218                 printk("%s""column: %d\n", pfx, mem->column);
219         if (mem->validation_bits & CPER_MEM_VALID_BIT_POSITION)
220                 printk("%s""bit_position: %d\n", pfx, mem->bit_pos);
221         if (mem->validation_bits & CPER_MEM_VALID_REQUESTOR_ID)
222                 printk("%s""requestor_id: 0x%016llx\n", pfx, mem->requestor_id);
223         if (mem->validation_bits & CPER_MEM_VALID_RESPONDER_ID)
224                 printk("%s""responder_id: 0x%016llx\n", pfx, mem->responder_id);
225         if (mem->validation_bits & CPER_MEM_VALID_TARGET_ID)
226                 printk("%s""target_id: 0x%016llx\n", pfx, mem->target_id);
227         if (mem->validation_bits & CPER_MEM_VALID_ERROR_TYPE) {
228                 u8 etype = mem->error_type;
229                 printk("%s""error_type: %d, %s\n", pfx, etype,
230                        etype < ARRAY_SIZE(cper_mem_err_type_strs) ?
231                        cper_mem_err_type_strs[etype] : "unknown");
232         }
233 }
234
235 static const char *cper_pcie_port_type_strs[] = {
236         "PCIe end point",
237         "legacy PCI end point",
238         "unknown",
239         "unknown",
240         "root port",
241         "upstream switch port",
242         "downstream switch port",
243         "PCIe to PCI/PCI-X bridge",
244         "PCI/PCI-X to PCIe bridge",
245         "root complex integrated endpoint device",
246         "root complex event collector",
247 };
248
249 static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie,
250                             const struct acpi_hest_generic_data *gdata)
251 {
252         if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE)
253                 printk("%s""port_type: %d, %s\n", pfx, pcie->port_type,
254                        pcie->port_type < ARRAY_SIZE(cper_pcie_port_type_strs) ?
255                        cper_pcie_port_type_strs[pcie->port_type] : "unknown");
256         if (pcie->validation_bits & CPER_PCIE_VALID_VERSION)
257                 printk("%s""version: %d.%d\n", pfx,
258                        pcie->version.major, pcie->version.minor);
259         if (pcie->validation_bits & CPER_PCIE_VALID_COMMAND_STATUS)
260                 printk("%s""command: 0x%04x, status: 0x%04x\n", pfx,
261                        pcie->command, pcie->status);
262         if (pcie->validation_bits & CPER_PCIE_VALID_DEVICE_ID) {
263                 const __u8 *p;
264                 printk("%s""device_id: %04x:%02x:%02x.%x\n", pfx,
265                        pcie->device_id.segment, pcie->device_id.bus,
266                        pcie->device_id.device, pcie->device_id.function);
267                 printk("%s""slot: %d\n", pfx,
268                        pcie->device_id.slot >> CPER_PCIE_SLOT_SHIFT);
269                 printk("%s""secondary_bus: 0x%02x\n", pfx,
270                        pcie->device_id.secondary_bus);
271                 printk("%s""vendor_id: 0x%04x, device_id: 0x%04x\n", pfx,
272                        pcie->device_id.vendor_id, pcie->device_id.device_id);
273                 p = pcie->device_id.class_code;
274                 printk("%s""class_code: %02x%02x%02x\n", pfx, p[0], p[1], p[2]);
275         }
276         if (pcie->validation_bits & CPER_PCIE_VALID_SERIAL_NUMBER)
277                 printk("%s""serial number: 0x%04x, 0x%04x\n", pfx,
278                        pcie->serial_number.lower, pcie->serial_number.upper);
279         if (pcie->validation_bits & CPER_PCIE_VALID_BRIDGE_CONTROL_STATUS)
280                 printk(
281         "%s""bridge: secondary_status: 0x%04x, control: 0x%04x\n",
282         pfx, pcie->bridge.secondary_status, pcie->bridge.control);
283 #ifdef CONFIG_ACPI_APEI_PCIEAER
284         if (pcie->validation_bits & CPER_PCIE_VALID_AER_INFO) {
285                 struct aer_capability_regs *aer_regs = (void *)pcie->aer_info;
286                 cper_print_aer(pfx, gdata->error_severity, aer_regs);
287         }
288 #endif
289 }
290
291 static const char *apei_estatus_section_flag_strs[] = {
292         "primary",
293         "containment warning",
294         "reset",
295         "threshold exceeded",
296         "resource not accessible",
297         "latent error",
298 };
299
300 static void apei_estatus_print_section(
301         const char *pfx, const struct acpi_hest_generic_data *gdata, int sec_no)
302 {
303         uuid_le *sec_type = (uuid_le *)gdata->section_type;
304         __u16 severity;
305
306         severity = gdata->error_severity;
307         printk("%s""section: %d, severity: %d, %s\n", pfx, sec_no, severity,
308                cper_severity_str(severity));
309         printk("%s""flags: 0x%02x\n", pfx, gdata->flags);
310         cper_print_bits(pfx, gdata->flags, apei_estatus_section_flag_strs,
311                         ARRAY_SIZE(apei_estatus_section_flag_strs));
312         if (gdata->validation_bits & CPER_SEC_VALID_FRU_ID)
313                 printk("%s""fru_id: %pUl\n", pfx, (uuid_le *)gdata->fru_id);
314         if (gdata->validation_bits & CPER_SEC_VALID_FRU_TEXT)
315                 printk("%s""fru_text: %.20s\n", pfx, gdata->fru_text);
316
317         if (!uuid_le_cmp(*sec_type, CPER_SEC_PROC_GENERIC)) {
318                 struct cper_sec_proc_generic *proc_err = (void *)(gdata + 1);
319                 printk("%s""section_type: general processor error\n", pfx);
320                 if (gdata->error_data_length >= sizeof(*proc_err))
321                         cper_print_proc_generic(pfx, proc_err);
322                 else
323                         goto err_section_too_small;
324         } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PLATFORM_MEM)) {
325                 struct cper_sec_mem_err *mem_err = (void *)(gdata + 1);
326                 printk("%s""section_type: memory error\n", pfx);
327                 if (gdata->error_data_length >= sizeof(*mem_err))
328                         cper_print_mem(pfx, mem_err);
329                 else
330                         goto err_section_too_small;
331         } else if (!uuid_le_cmp(*sec_type, CPER_SEC_PCIE)) {
332                 struct cper_sec_pcie *pcie = (void *)(gdata + 1);
333                 printk("%s""section_type: PCIe error\n", pfx);
334                 if (gdata->error_data_length >= sizeof(*pcie))
335                         cper_print_pcie(pfx, pcie, gdata);
336                 else
337                         goto err_section_too_small;
338         } else
339                 printk("%s""section type: unknown, %pUl\n", pfx, sec_type);
340
341         return;
342
343 err_section_too_small:
344         pr_err(FW_WARN "error section length is too small\n");
345 }
346
347 void apei_estatus_print(const char *pfx,
348                         const struct acpi_hest_generic_status *estatus)
349 {
350         struct acpi_hest_generic_data *gdata;
351         unsigned int data_len, gedata_len;
352         int sec_no = 0;
353         __u16 severity;
354
355         printk("%s""APEI generic hardware error status\n", pfx);
356         severity = estatus->error_severity;
357         printk("%s""severity: %d, %s\n", pfx, severity,
358                cper_severity_str(severity));
359         data_len = estatus->data_length;
360         gdata = (struct acpi_hest_generic_data *)(estatus + 1);
361         while (data_len > sizeof(*gdata)) {
362                 gedata_len = gdata->error_data_length;
363                 apei_estatus_print_section(pfx, gdata, sec_no);
364                 data_len -= gedata_len + sizeof(*gdata);
365                 sec_no++;
366         }
367 }
368 EXPORT_SYMBOL_GPL(apei_estatus_print);
369
370 int apei_estatus_check_header(const struct acpi_hest_generic_status *estatus)
371 {
372         if (estatus->data_length &&
373             estatus->data_length < sizeof(struct acpi_hest_generic_data))
374                 return -EINVAL;
375         if (estatus->raw_data_length &&
376             estatus->raw_data_offset < sizeof(*estatus) + estatus->data_length)
377                 return -EINVAL;
378
379         return 0;
380 }
381 EXPORT_SYMBOL_GPL(apei_estatus_check_header);
382
383 int apei_estatus_check(const struct acpi_hest_generic_status *estatus)
384 {
385         struct acpi_hest_generic_data *gdata;
386         unsigned int data_len, gedata_len;
387         int rc;
388
389         rc = apei_estatus_check_header(estatus);
390         if (rc)
391                 return rc;
392         data_len = estatus->data_length;
393         gdata = (struct acpi_hest_generic_data *)(estatus + 1);
394         while (data_len > sizeof(*gdata)) {
395                 gedata_len = gdata->error_data_length;
396                 if (gedata_len > data_len - sizeof(*gdata))
397                         return -EINVAL;
398                 data_len -= gedata_len + sizeof(*gdata);
399         }
400         if (data_len)
401                 return -EINVAL;
402
403         return 0;
404 }
405 EXPORT_SYMBOL_GPL(apei_estatus_check);