diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-04 20:21:59 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-04 20:21:59 -0400 |
commit | d782cebd6b39b4caab8a913180c0acfd6c33e9c2 (patch) | |
tree | e8ed959e9475f57bf7f2a0753e5a0f7cf04c8f75 /drivers/firmware | |
parent | 8556d44fee6ded9f4287d7ff7b5cc9d8635b0be0 (diff) | |
parent | c3107e3c504d3187ed8eac8179494946faff1481 (diff) |
Merge branch 'x86-ras-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull RAS updates from Ingo Molnar:
"The main changes in this cycle are:
- RAS tracing/events infrastructure, by Gong Chen.
- Various generalizations of the APEI code to make it available to
non-x86 architectures, by Tomasz Nowicki"
* 'x86-ras-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
x86/ras: Fix build warnings in <linux/aer.h>
acpi, apei, ghes: Factor out ioremap virtual memory for IRQ and NMI context.
acpi, apei, ghes: Make NMI error notification to be GHES architecture extension.
apei, mce: Factor out APEI architecture specific MCE calls.
RAS, extlog: Adjust init flow
trace, eMCA: Add a knob to adjust where to save event log
trace, RAS: Add eMCA trace event interface
RAS, debugfs: Add debugfs interface for RAS subsystem
CPER: Adjust code flow of some functions
x86, MCE: Robustify mcheck_init_device
trace, AER: Move trace into unified interface
trace, RAS: Add basic RAS trace event
x86, MCE: Kill CPU_POST_DEAD
Diffstat (limited to 'drivers/firmware')
-rw-r--r-- | drivers/firmware/efi/cper.c | 192 |
1 files changed, 137 insertions, 55 deletions
diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c index 1491dd4f08f9..437e6fd47311 100644 --- a/drivers/firmware/efi/cper.c +++ b/drivers/firmware/efi/cper.c | |||
@@ -34,6 +34,9 @@ | |||
34 | #include <linux/aer.h> | 34 | #include <linux/aer.h> |
35 | 35 | ||
36 | #define INDENT_SP " " | 36 | #define INDENT_SP " " |
37 | |||
38 | static char rcd_decode_str[CPER_REC_LEN]; | ||
39 | |||
37 | /* | 40 | /* |
38 | * CPER record ID need to be unique even after reboot, because record | 41 | * CPER record ID need to be unique even after reboot, because record |
39 | * ID is used as index for ERST storage, while CPER records from | 42 | * ID is used as index for ERST storage, while CPER records from |
@@ -50,18 +53,19 @@ u64 cper_next_record_id(void) | |||
50 | } | 53 | } |
51 | EXPORT_SYMBOL_GPL(cper_next_record_id); | 54 | EXPORT_SYMBOL_GPL(cper_next_record_id); |
52 | 55 | ||
53 | static const char *cper_severity_strs[] = { | 56 | static const char * const severity_strs[] = { |
54 | "recoverable", | 57 | "recoverable", |
55 | "fatal", | 58 | "fatal", |
56 | "corrected", | 59 | "corrected", |
57 | "info", | 60 | "info", |
58 | }; | 61 | }; |
59 | 62 | ||
60 | static const char *cper_severity_str(unsigned int severity) | 63 | const char *cper_severity_str(unsigned int severity) |
61 | { | 64 | { |
62 | return severity < ARRAY_SIZE(cper_severity_strs) ? | 65 | return severity < ARRAY_SIZE(severity_strs) ? |
63 | cper_severity_strs[severity] : "unknown"; | 66 | severity_strs[severity] : "unknown"; |
64 | } | 67 | } |
68 | EXPORT_SYMBOL_GPL(cper_severity_str); | ||
65 | 69 | ||
66 | /* | 70 | /* |
67 | * cper_print_bits - print strings for set bits | 71 | * cper_print_bits - print strings for set bits |
@@ -100,32 +104,32 @@ void cper_print_bits(const char *pfx, unsigned int bits, | |||
100 | printk("%s\n", buf); | 104 | printk("%s\n", buf); |
101 | } | 105 | } |
102 | 106 | ||
103 | static const char * const cper_proc_type_strs[] = { | 107 | static const char * const proc_type_strs[] = { |
104 | "IA32/X64", | 108 | "IA32/X64", |
105 | "IA64", | 109 | "IA64", |
106 | }; | 110 | }; |
107 | 111 | ||
108 | static const char * const cper_proc_isa_strs[] = { | 112 | static const char * const proc_isa_strs[] = { |
109 | "IA32", | 113 | "IA32", |
110 | "IA64", | 114 | "IA64", |
111 | "X64", | 115 | "X64", |
112 | }; | 116 | }; |
113 | 117 | ||
114 | static const char * const cper_proc_error_type_strs[] = { | 118 | static const char * const proc_error_type_strs[] = { |
115 | "cache error", | 119 | "cache error", |
116 | "TLB error", | 120 | "TLB error", |
117 | "bus error", | 121 | "bus error", |
118 | "micro-architectural error", | 122 | "micro-architectural error", |
119 | }; | 123 | }; |
120 | 124 | ||
121 | static const char * const cper_proc_op_strs[] = { | 125 | static const char * const proc_op_strs[] = { |
122 | "unknown or generic", | 126 | "unknown or generic", |
123 | "data read", | 127 | "data read", |
124 | "data write", | 128 | "data write", |
125 | "instruction execution", | 129 | "instruction execution", |
126 | }; | 130 | }; |
127 | 131 | ||
128 | static const char * const cper_proc_flag_strs[] = { | 132 | static const char * const proc_flag_strs[] = { |
129 | "restartable", | 133 | "restartable", |
130 | "precise IP", | 134 | "precise IP", |
131 | "overflow", | 135 | "overflow", |
@@ -137,26 +141,26 @@ static void cper_print_proc_generic(const char *pfx, | |||
137 | { | 141 | { |
138 | if (proc->validation_bits & CPER_PROC_VALID_TYPE) | 142 | if (proc->validation_bits & CPER_PROC_VALID_TYPE) |
139 | printk("%s""processor_type: %d, %s\n", pfx, proc->proc_type, | 143 | printk("%s""processor_type: %d, %s\n", pfx, proc->proc_type, |
140 | proc->proc_type < ARRAY_SIZE(cper_proc_type_strs) ? | 144 | proc->proc_type < ARRAY_SIZE(proc_type_strs) ? |
141 | cper_proc_type_strs[proc->proc_type] : "unknown"); | 145 | proc_type_strs[proc->proc_type] : "unknown"); |
142 | if (proc->validation_bits & CPER_PROC_VALID_ISA) | 146 | if (proc->validation_bits & CPER_PROC_VALID_ISA) |
143 | printk("%s""processor_isa: %d, %s\n", pfx, proc->proc_isa, | 147 | printk("%s""processor_isa: %d, %s\n", pfx, proc->proc_isa, |
144 | proc->proc_isa < ARRAY_SIZE(cper_proc_isa_strs) ? | 148 | proc->proc_isa < ARRAY_SIZE(proc_isa_strs) ? |
145 | cper_proc_isa_strs[proc->proc_isa] : "unknown"); | 149 | proc_isa_strs[proc->proc_isa] : "unknown"); |
146 | if (proc->validation_bits & CPER_PROC_VALID_ERROR_TYPE) { | 150 | if (proc->validation_bits & CPER_PROC_VALID_ERROR_TYPE) { |
147 | printk("%s""error_type: 0x%02x\n", pfx, proc->proc_error_type); | 151 | printk("%s""error_type: 0x%02x\n", pfx, proc->proc_error_type); |
148 | cper_print_bits(pfx, proc->proc_error_type, | 152 | cper_print_bits(pfx, proc->proc_error_type, |
149 | cper_proc_error_type_strs, | 153 | proc_error_type_strs, |
150 | ARRAY_SIZE(cper_proc_error_type_strs)); | 154 | ARRAY_SIZE(proc_error_type_strs)); |
151 | } | 155 | } |
152 | if (proc->validation_bits & CPER_PROC_VALID_OPERATION) | 156 | if (proc->validation_bits & CPER_PROC_VALID_OPERATION) |
153 | printk("%s""operation: %d, %s\n", pfx, proc->operation, | 157 | printk("%s""operation: %d, %s\n", pfx, proc->operation, |
154 | proc->operation < ARRAY_SIZE(cper_proc_op_strs) ? | 158 | proc->operation < ARRAY_SIZE(proc_op_strs) ? |
155 | cper_proc_op_strs[proc->operation] : "unknown"); | 159 | proc_op_strs[proc->operation] : "unknown"); |
156 | if (proc->validation_bits & CPER_PROC_VALID_FLAGS) { | 160 | if (proc->validation_bits & CPER_PROC_VALID_FLAGS) { |
157 | printk("%s""flags: 0x%02x\n", pfx, proc->flags); | 161 | printk("%s""flags: 0x%02x\n", pfx, proc->flags); |
158 | cper_print_bits(pfx, proc->flags, cper_proc_flag_strs, | 162 | cper_print_bits(pfx, proc->flags, proc_flag_strs, |
159 | ARRAY_SIZE(cper_proc_flag_strs)); | 163 | ARRAY_SIZE(proc_flag_strs)); |
160 | } | 164 | } |
161 | if (proc->validation_bits & CPER_PROC_VALID_LEVEL) | 165 | if (proc->validation_bits & CPER_PROC_VALID_LEVEL) |
162 | printk("%s""level: %d\n", pfx, proc->level); | 166 | printk("%s""level: %d\n", pfx, proc->level); |
@@ -177,7 +181,7 @@ static void cper_print_proc_generic(const char *pfx, | |||
177 | printk("%s""IP: 0x%016llx\n", pfx, proc->ip); | 181 | printk("%s""IP: 0x%016llx\n", pfx, proc->ip); |
178 | } | 182 | } |
179 | 183 | ||
180 | static const char *cper_mem_err_type_strs[] = { | 184 | static const char * const mem_err_type_strs[] = { |
181 | "unknown", | 185 | "unknown", |
182 | "no error", | 186 | "no error", |
183 | "single-bit ECC", | 187 | "single-bit ECC", |
@@ -196,58 +200,136 @@ static const char *cper_mem_err_type_strs[] = { | |||
196 | "physical memory map-out event", | 200 | "physical memory map-out event", |
197 | }; | 201 | }; |
198 | 202 | ||
199 | static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem) | 203 | const char *cper_mem_err_type_str(unsigned int etype) |
200 | { | 204 | { |
201 | if (mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS) | 205 | return etype < ARRAY_SIZE(mem_err_type_strs) ? |
202 | printk("%s""error_status: 0x%016llx\n", pfx, mem->error_status); | 206 | mem_err_type_strs[etype] : "unknown"; |
203 | if (mem->validation_bits & CPER_MEM_VALID_PA) | 207 | } |
204 | printk("%s""physical_address: 0x%016llx\n", | 208 | EXPORT_SYMBOL_GPL(cper_mem_err_type_str); |
205 | pfx, mem->physical_addr); | 209 | |
206 | if (mem->validation_bits & CPER_MEM_VALID_PA_MASK) | 210 | static int cper_mem_err_location(struct cper_mem_err_compact *mem, char *msg) |
207 | printk("%s""physical_address_mask: 0x%016llx\n", | 211 | { |
208 | pfx, mem->physical_addr_mask); | 212 | u32 len, n; |
213 | |||
214 | if (!msg) | ||
215 | return 0; | ||
216 | |||
217 | n = 0; | ||
218 | len = CPER_REC_LEN - 1; | ||
209 | if (mem->validation_bits & CPER_MEM_VALID_NODE) | 219 | if (mem->validation_bits & CPER_MEM_VALID_NODE) |
210 | pr_debug("node: %d\n", mem->node); | 220 | n += scnprintf(msg + n, len - n, "node: %d ", mem->node); |
211 | if (mem->validation_bits & CPER_MEM_VALID_CARD) | 221 | if (mem->validation_bits & CPER_MEM_VALID_CARD) |
212 | pr_debug("card: %d\n", mem->card); | 222 | n += scnprintf(msg + n, len - n, "card: %d ", mem->card); |
213 | if (mem->validation_bits & CPER_MEM_VALID_MODULE) | 223 | if (mem->validation_bits & CPER_MEM_VALID_MODULE) |
214 | pr_debug("module: %d\n", mem->module); | 224 | n += scnprintf(msg + n, len - n, "module: %d ", mem->module); |
215 | if (mem->validation_bits & CPER_MEM_VALID_RANK_NUMBER) | 225 | if (mem->validation_bits & CPER_MEM_VALID_RANK_NUMBER) |
216 | pr_debug("rank: %d\n", mem->rank); | 226 | n += scnprintf(msg + n, len - n, "rank: %d ", mem->rank); |
217 | if (mem->validation_bits & CPER_MEM_VALID_BANK) | 227 | if (mem->validation_bits & CPER_MEM_VALID_BANK) |
218 | pr_debug("bank: %d\n", mem->bank); | 228 | n += scnprintf(msg + n, len - n, "bank: %d ", mem->bank); |
219 | if (mem->validation_bits & CPER_MEM_VALID_DEVICE) | 229 | if (mem->validation_bits & CPER_MEM_VALID_DEVICE) |
220 | pr_debug("device: %d\n", mem->device); | 230 | n += scnprintf(msg + n, len - n, "device: %d ", mem->device); |
221 | if (mem->validation_bits & CPER_MEM_VALID_ROW) | 231 | if (mem->validation_bits & CPER_MEM_VALID_ROW) |
222 | pr_debug("row: %d\n", mem->row); | 232 | n += scnprintf(msg + n, len - n, "row: %d ", mem->row); |
223 | if (mem->validation_bits & CPER_MEM_VALID_COLUMN) | 233 | if (mem->validation_bits & CPER_MEM_VALID_COLUMN) |
224 | pr_debug("column: %d\n", mem->column); | 234 | n += scnprintf(msg + n, len - n, "column: %d ", mem->column); |
225 | if (mem->validation_bits & CPER_MEM_VALID_BIT_POSITION) | 235 | if (mem->validation_bits & CPER_MEM_VALID_BIT_POSITION) |
226 | pr_debug("bit_position: %d\n", mem->bit_pos); | 236 | n += scnprintf(msg + n, len - n, "bit_position: %d ", |
237 | mem->bit_pos); | ||
227 | if (mem->validation_bits & CPER_MEM_VALID_REQUESTOR_ID) | 238 | if (mem->validation_bits & CPER_MEM_VALID_REQUESTOR_ID) |
228 | pr_debug("requestor_id: 0x%016llx\n", mem->requestor_id); | 239 | n += scnprintf(msg + n, len - n, "requestor_id: 0x%016llx ", |
240 | mem->requestor_id); | ||
229 | if (mem->validation_bits & CPER_MEM_VALID_RESPONDER_ID) | 241 | if (mem->validation_bits & CPER_MEM_VALID_RESPONDER_ID) |
230 | pr_debug("responder_id: 0x%016llx\n", mem->responder_id); | 242 | n += scnprintf(msg + n, len - n, "responder_id: 0x%016llx ", |
243 | mem->responder_id); | ||
231 | if (mem->validation_bits & CPER_MEM_VALID_TARGET_ID) | 244 | if (mem->validation_bits & CPER_MEM_VALID_TARGET_ID) |
232 | pr_debug("target_id: 0x%016llx\n", mem->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(struct cper_mem_err_compact *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 | void cper_mem_err_pack(const struct cper_sec_mem_err *mem, | ||
275 | struct cper_mem_err_compact *cmem) | ||
276 | { | ||
277 | cmem->validation_bits = mem->validation_bits; | ||
278 | cmem->node = mem->node; | ||
279 | cmem->card = mem->card; | ||
280 | cmem->module = mem->module; | ||
281 | cmem->bank = mem->bank; | ||
282 | cmem->device = mem->device; | ||
283 | cmem->row = mem->row; | ||
284 | cmem->column = mem->column; | ||
285 | cmem->bit_pos = mem->bit_pos; | ||
286 | cmem->requestor_id = mem->requestor_id; | ||
287 | cmem->responder_id = mem->responder_id; | ||
288 | cmem->target_id = mem->target_id; | ||
289 | cmem->rank = mem->rank; | ||
290 | cmem->mem_array_handle = mem->mem_array_handle; | ||
291 | cmem->mem_dev_handle = mem->mem_dev_handle; | ||
292 | } | ||
293 | |||
294 | const char *cper_mem_err_unpack(struct trace_seq *p, | ||
295 | struct cper_mem_err_compact *cmem) | ||
296 | { | ||
297 | const char *ret = p->buffer + p->len; | ||
298 | |||
299 | if (cper_mem_err_location(cmem, rcd_decode_str)) | ||
300 | trace_seq_printf(p, "%s", rcd_decode_str); | ||
301 | if (cper_dimm_err_location(cmem, rcd_decode_str)) | ||
302 | trace_seq_printf(p, "%s", rcd_decode_str); | ||
303 | trace_seq_putc(p, '\0'); | ||
304 | |||
305 | return ret; | ||
306 | } | ||
307 | |||
308 | static void cper_print_mem(const char *pfx, const struct cper_sec_mem_err *mem) | ||
309 | { | ||
310 | struct cper_mem_err_compact cmem; | ||
311 | |||
312 | if (mem->validation_bits & CPER_MEM_VALID_ERROR_STATUS) | ||
313 | printk("%s""error_status: 0x%016llx\n", pfx, mem->error_status); | ||
314 | if (mem->validation_bits & CPER_MEM_VALID_PA) | ||
315 | printk("%s""physical_address: 0x%016llx\n", | ||
316 | pfx, mem->physical_addr); | ||
317 | if (mem->validation_bits & CPER_MEM_VALID_PA_MASK) | ||
318 | printk("%s""physical_address_mask: 0x%016llx\n", | ||
319 | pfx, mem->physical_addr_mask); | ||
320 | cper_mem_err_pack(mem, &cmem); | ||
321 | if (cper_mem_err_location(&cmem, rcd_decode_str)) | ||
322 | printk("%s%s\n", pfx, rcd_decode_str); | ||
233 | if (mem->validation_bits & CPER_MEM_VALID_ERROR_TYPE) { | 323 | if (mem->validation_bits & CPER_MEM_VALID_ERROR_TYPE) { |
234 | u8 etype = mem->error_type; | 324 | u8 etype = mem->error_type; |
235 | printk("%s""error_type: %d, %s\n", pfx, etype, | 325 | printk("%s""error_type: %d, %s\n", pfx, etype, |
236 | etype < ARRAY_SIZE(cper_mem_err_type_strs) ? | 326 | cper_mem_err_type_str(etype)); |
237 | cper_mem_err_type_strs[etype] : "unknown"); | ||
238 | } | ||
239 | if (mem->validation_bits & CPER_MEM_VALID_MODULE_HANDLE) { | ||
240 | const char *bank = NULL, *device = NULL; | ||
241 | dmi_memdev_name(mem->mem_dev_handle, &bank, &device); | ||
242 | if (bank != NULL && device != NULL) | ||
243 | printk("%s""DIMM location: %s %s", pfx, bank, device); | ||
244 | else | ||
245 | printk("%s""DIMM DMI handle: 0x%.4x", | ||
246 | pfx, mem->mem_dev_handle); | ||
247 | } | 327 | } |
328 | if (cper_dimm_err_location(&cmem, rcd_decode_str)) | ||
329 | printk("%s%s\n", pfx, rcd_decode_str); | ||
248 | } | 330 | } |
249 | 331 | ||
250 | static const char *cper_pcie_port_type_strs[] = { | 332 | static const char * const pcie_port_type_strs[] = { |
251 | "PCIe end point", | 333 | "PCIe end point", |
252 | "legacy PCI end point", | 334 | "legacy PCI end point", |
253 | "unknown", | 335 | "unknown", |
@@ -266,8 +348,8 @@ static void cper_print_pcie(const char *pfx, const struct cper_sec_pcie *pcie, | |||
266 | { | 348 | { |
267 | if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE) | 349 | if (pcie->validation_bits & CPER_PCIE_VALID_PORT_TYPE) |
268 | printk("%s""port_type: %d, %s\n", pfx, pcie->port_type, | 350 | printk("%s""port_type: %d, %s\n", pfx, pcie->port_type, |
269 | pcie->port_type < ARRAY_SIZE(cper_pcie_port_type_strs) ? | 351 | pcie->port_type < ARRAY_SIZE(pcie_port_type_strs) ? |
270 | cper_pcie_port_type_strs[pcie->port_type] : "unknown"); | 352 | pcie_port_type_strs[pcie->port_type] : "unknown"); |
271 | if (pcie->validation_bits & CPER_PCIE_VALID_VERSION) | 353 | if (pcie->validation_bits & CPER_PCIE_VALID_VERSION) |
272 | printk("%s""version: %d.%d\n", pfx, | 354 | printk("%s""version: %d.%d\n", pfx, |
273 | pcie->version.major, pcie->version.minor); | 355 | pcie->version.major, pcie->version.minor); |