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