diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2007-12-20 23:39:21 -0500 |
---|---|---|
committer | Josh Boyer <jwboyer@linux.vnet.ibm.com> | 2007-12-23 14:11:59 -0500 |
commit | 47c0bd1ae24c34e851cf0f2b02ef2a6847d7ae15 (patch) | |
tree | 86fab68618a4afa03660cc576c9e7da3e5a0b520 /arch/ppc/kernel | |
parent | c2a7dcad9f0d92d7a96e735abb8bec7b9c621536 (diff) |
[POWERPC] Reworking machine check handling and Fix 440/440A
This adds a cputable function pointer for the CPU-side machine
check handling. The semantic is still the same as the old one,
the one in ppc_md. overrides the one in cputable, though
ultimately we'll want to change that so the CPU gets first.
This removes CONFIG_440A which was a problem for multiplatform
kernels and instead fixes up the IVOR at runtime from a setup_cpu
function. The "A" version of the machine check also tweaks the
regs->trap value to differenciate the 2 versions at the C level.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Josh Boyer <jwboyer@linux.vnet.ibm.com>
Diffstat (limited to 'arch/ppc/kernel')
-rw-r--r-- | arch/ppc/kernel/traps.c | 98 |
1 files changed, 67 insertions, 31 deletions
diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c index c78568905c3b..25a1085fbd01 100644 --- a/arch/ppc/kernel/traps.c +++ b/arch/ppc/kernel/traps.c | |||
@@ -231,39 +231,25 @@ platform_machine_check(struct pt_regs *regs) | |||
231 | { | 231 | { |
232 | } | 232 | } |
233 | 233 | ||
234 | void machine_check_exception(struct pt_regs *regs) | 234 | #if defined(CONFIG_4xx) |
235 | int machine_check_4xx(struct pt_regs *regs) | ||
235 | { | 236 | { |
236 | unsigned long reason = get_mc_reason(regs); | 237 | unsigned long reason = get_mc_reason(regs); |
237 | 238 | ||
238 | if (user_mode(regs)) { | ||
239 | regs->msr |= MSR_RI; | ||
240 | _exception(SIGBUS, regs, BUS_ADRERR, regs->nip); | ||
241 | return; | ||
242 | } | ||
243 | |||
244 | #if defined(CONFIG_8xx) && defined(CONFIG_PCI) | ||
245 | /* the qspan pci read routines can cause machine checks -- Cort */ | ||
246 | bad_page_fault(regs, regs->dar, SIGBUS); | ||
247 | return; | ||
248 | #endif | ||
249 | |||
250 | if (debugger_fault_handler) { | ||
251 | debugger_fault_handler(regs); | ||
252 | regs->msr |= MSR_RI; | ||
253 | return; | ||
254 | } | ||
255 | |||
256 | if (check_io_access(regs)) | ||
257 | return; | ||
258 | |||
259 | #if defined(CONFIG_4xx) && !defined(CONFIG_440A) | ||
260 | if (reason & ESR_IMCP) { | 239 | if (reason & ESR_IMCP) { |
261 | printk("Instruction"); | 240 | printk("Instruction"); |
262 | mtspr(SPRN_ESR, reason & ~ESR_IMCP); | 241 | mtspr(SPRN_ESR, reason & ~ESR_IMCP); |
263 | } else | 242 | } else |
264 | printk("Data"); | 243 | printk("Data"); |
265 | printk(" machine check in kernel mode.\n"); | 244 | printk(" machine check in kernel mode.\n"); |
266 | #elif defined(CONFIG_440A) | 245 | |
246 | return 0; | ||
247 | } | ||
248 | |||
249 | int machine_check_440A(struct pt_regs *regs) | ||
250 | { | ||
251 | unsigned long reason = get_mc_reason(regs); | ||
252 | |||
267 | printk("Machine check in kernel mode.\n"); | 253 | printk("Machine check in kernel mode.\n"); |
268 | if (reason & ESR_IMCP){ | 254 | if (reason & ESR_IMCP){ |
269 | printk("Instruction Synchronous Machine Check exception\n"); | 255 | printk("Instruction Synchronous Machine Check exception\n"); |
@@ -293,7 +279,13 @@ void machine_check_exception(struct pt_regs *regs) | |||
293 | /* Clear MCSR */ | 279 | /* Clear MCSR */ |
294 | mtspr(SPRN_MCSR, mcsr); | 280 | mtspr(SPRN_MCSR, mcsr); |
295 | } | 281 | } |
296 | #elif defined (CONFIG_E500) | 282 | return 0; |
283 | } | ||
284 | #elif defined(CONFIG_E500) | ||
285 | int machine_check_e500(struct pt_regs *regs) | ||
286 | { | ||
287 | unsigned long reason = get_mc_reason(regs); | ||
288 | |||
297 | printk("Machine check in kernel mode.\n"); | 289 | printk("Machine check in kernel mode.\n"); |
298 | printk("Caused by (from MCSR=%lx): ", reason); | 290 | printk("Caused by (from MCSR=%lx): ", reason); |
299 | 291 | ||
@@ -305,8 +297,6 @@ void machine_check_exception(struct pt_regs *regs) | |||
305 | printk("Data Cache Push Parity Error\n"); | 297 | printk("Data Cache Push Parity Error\n"); |
306 | if (reason & MCSR_DCPERR) | 298 | if (reason & MCSR_DCPERR) |
307 | printk("Data Cache Parity Error\n"); | 299 | printk("Data Cache Parity Error\n"); |
308 | if (reason & MCSR_GL_CI) | ||
309 | printk("Guarded Load or Cache-Inhibited stwcx.\n"); | ||
310 | if (reason & MCSR_BUS_IAERR) | 300 | if (reason & MCSR_BUS_IAERR) |
311 | printk("Bus - Instruction Address Error\n"); | 301 | printk("Bus - Instruction Address Error\n"); |
312 | if (reason & MCSR_BUS_RAERR) | 302 | if (reason & MCSR_BUS_RAERR) |
@@ -318,12 +308,19 @@ void machine_check_exception(struct pt_regs *regs) | |||
318 | if (reason & MCSR_BUS_RBERR) | 308 | if (reason & MCSR_BUS_RBERR) |
319 | printk("Bus - Read Data Bus Error\n"); | 309 | printk("Bus - Read Data Bus Error\n"); |
320 | if (reason & MCSR_BUS_WBERR) | 310 | if (reason & MCSR_BUS_WBERR) |
321 | printk("Bus - Write Data Bus Error\n"); | 311 | printk("Bus - Read Data Bus Error\n"); |
322 | if (reason & MCSR_BUS_IPERR) | 312 | if (reason & MCSR_BUS_IPERR) |
323 | printk("Bus - Instruction Parity Error\n"); | 313 | printk("Bus - Instruction Parity Error\n"); |
324 | if (reason & MCSR_BUS_RPERR) | 314 | if (reason & MCSR_BUS_RPERR) |
325 | printk("Bus - Read Parity Error\n"); | 315 | printk("Bus - Read Parity Error\n"); |
326 | #elif defined (CONFIG_E200) | 316 | |
317 | return 0; | ||
318 | } | ||
319 | #elif defined(CONFIG_E200) | ||
320 | int machine_check_e200(struct pt_regs *regs) | ||
321 | { | ||
322 | unsigned long reason = get_mc_reason(regs); | ||
323 | |||
327 | printk("Machine check in kernel mode.\n"); | 324 | printk("Machine check in kernel mode.\n"); |
328 | printk("Caused by (from MCSR=%lx): ", reason); | 325 | printk("Caused by (from MCSR=%lx): ", reason); |
329 | 326 | ||
@@ -341,7 +338,14 @@ void machine_check_exception(struct pt_regs *regs) | |||
341 | printk("Bus - Read Bus Error on data load\n"); | 338 | printk("Bus - Read Bus Error on data load\n"); |
342 | if (reason & MCSR_BUS_WRERR) | 339 | if (reason & MCSR_BUS_WRERR) |
343 | printk("Bus - Write Bus Error on buffered store or cache line push\n"); | 340 | printk("Bus - Write Bus Error on buffered store or cache line push\n"); |
344 | #else /* !CONFIG_4xx && !CONFIG_E500 && !CONFIG_E200 */ | 341 | |
342 | return 0; | ||
343 | } | ||
344 | #else | ||
345 | int machine_check_generic(struct pt_regs *regs) | ||
346 | { | ||
347 | unsigned long reason = get_mc_reason(regs); | ||
348 | |||
345 | printk("Machine check in kernel mode.\n"); | 349 | printk("Machine check in kernel mode.\n"); |
346 | printk("Caused by (from SRR1=%lx): ", reason); | 350 | printk("Caused by (from SRR1=%lx): ", reason); |
347 | switch (reason & 0x601F0000) { | 351 | switch (reason & 0x601F0000) { |
@@ -371,7 +375,39 @@ void machine_check_exception(struct pt_regs *regs) | |||
371 | default: | 375 | default: |
372 | printk("Unknown values in msr\n"); | 376 | printk("Unknown values in msr\n"); |
373 | } | 377 | } |
374 | #endif /* CONFIG_4xx */ | 378 | return 0; |
379 | } | ||
380 | #endif /* everything else */ | ||
381 | |||
382 | void machine_check_exception(struct pt_regs *regs) | ||
383 | { | ||
384 | int recover = 0; | ||
385 | |||
386 | if (cur_cpu_spec->machine_check) | ||
387 | recover = cur_cpu_spec->machine_check(regs); | ||
388 | if (recover > 0) | ||
389 | return; | ||
390 | |||
391 | if (user_mode(regs)) { | ||
392 | regs->msr |= MSR_RI; | ||
393 | _exception(SIGBUS, regs, BUS_ADRERR, regs->nip); | ||
394 | return; | ||
395 | } | ||
396 | |||
397 | #if defined(CONFIG_8xx) && defined(CONFIG_PCI) | ||
398 | /* the qspan pci read routines can cause machine checks -- Cort */ | ||
399 | bad_page_fault(regs, regs->dar, SIGBUS); | ||
400 | return; | ||
401 | #endif | ||
402 | |||
403 | if (debugger_fault_handler) { | ||
404 | debugger_fault_handler(regs); | ||
405 | regs->msr |= MSR_RI; | ||
406 | return; | ||
407 | } | ||
408 | |||
409 | if (check_io_access(regs)) | ||
410 | return; | ||
375 | 411 | ||
376 | /* | 412 | /* |
377 | * Optional platform-provided routine to print out | 413 | * Optional platform-provided routine to print out |