aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/traps.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2007-12-20 23:39:21 -0500
committerJosh Boyer <jwboyer@linux.vnet.ibm.com>2007-12-23 14:11:59 -0500
commit47c0bd1ae24c34e851cf0f2b02ef2a6847d7ae15 (patch)
tree86fab68618a4afa03660cc576c9e7da3e5a0b520 /arch/powerpc/kernel/traps.c
parentc2a7dcad9f0d92d7a96e735abb8bec7b9c621536 (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/powerpc/kernel/traps.c')
-rw-r--r--arch/powerpc/kernel/traps.c62
1 files changed, 49 insertions, 13 deletions
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index cad64840fce4..848a20475db8 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -334,18 +334,25 @@ static inline int check_io_access(struct pt_regs *regs)
334#define clear_single_step(regs) ((regs)->msr &= ~MSR_SE) 334#define clear_single_step(regs) ((regs)->msr &= ~MSR_SE)
335#endif 335#endif
336 336
337static int generic_machine_check_exception(struct pt_regs *regs) 337#if defined(CONFIG_4xx)
338int machine_check_4xx(struct pt_regs *regs)
338{ 339{
339 unsigned long reason = get_mc_reason(regs); 340 unsigned long reason = get_mc_reason(regs);
340 341
341#if defined(CONFIG_4xx) && !defined(CONFIG_440A)
342 if (reason & ESR_IMCP) { 342 if (reason & ESR_IMCP) {
343 printk("Instruction"); 343 printk("Instruction");
344 mtspr(SPRN_ESR, reason & ~ESR_IMCP); 344 mtspr(SPRN_ESR, reason & ~ESR_IMCP);
345 } else 345 } else
346 printk("Data"); 346 printk("Data");
347 printk(" machine check in kernel mode.\n"); 347 printk(" machine check in kernel mode.\n");
348#elif defined(CONFIG_440A) 348
349 return 0;
350}
351
352int machine_check_440A(struct pt_regs *regs)
353{
354 unsigned long reason = get_mc_reason(regs);
355
349 printk("Machine check in kernel mode.\n"); 356 printk("Machine check in kernel mode.\n");
350 if (reason & ESR_IMCP){ 357 if (reason & ESR_IMCP){
351 printk("Instruction Synchronous Machine Check exception\n"); 358 printk("Instruction Synchronous Machine Check exception\n");
@@ -375,7 +382,13 @@ static int generic_machine_check_exception(struct pt_regs *regs)
375 /* Clear MCSR */ 382 /* Clear MCSR */
376 mtspr(SPRN_MCSR, mcsr); 383 mtspr(SPRN_MCSR, mcsr);
377 } 384 }
378#elif defined (CONFIG_E500) 385 return 0;
386}
387#elif defined(CONFIG_E500)
388int machine_check_e500(struct pt_regs *regs)
389{
390 unsigned long reason = get_mc_reason(regs);
391
379 printk("Machine check in kernel mode.\n"); 392 printk("Machine check in kernel mode.\n");
380 printk("Caused by (from MCSR=%lx): ", reason); 393 printk("Caused by (from MCSR=%lx): ", reason);
381 394
@@ -403,7 +416,14 @@ static int generic_machine_check_exception(struct pt_regs *regs)
403 printk("Bus - Instruction Parity Error\n"); 416 printk("Bus - Instruction Parity Error\n");
404 if (reason & MCSR_BUS_RPERR) 417 if (reason & MCSR_BUS_RPERR)
405 printk("Bus - Read Parity Error\n"); 418 printk("Bus - Read Parity Error\n");
406#elif defined (CONFIG_E200) 419
420 return 0;
421}
422#elif defined(CONFIG_E200)
423int machine_check_e200(struct pt_regs *regs)
424{
425 unsigned long reason = get_mc_reason(regs);
426
407 printk("Machine check in kernel mode.\n"); 427 printk("Machine check in kernel mode.\n");
408 printk("Caused by (from MCSR=%lx): ", reason); 428 printk("Caused by (from MCSR=%lx): ", reason);
409 429
@@ -421,7 +441,14 @@ static int generic_machine_check_exception(struct pt_regs *regs)
421 printk("Bus - Read Bus Error on data load\n"); 441 printk("Bus - Read Bus Error on data load\n");
422 if (reason & MCSR_BUS_WRERR) 442 if (reason & MCSR_BUS_WRERR)
423 printk("Bus - Write Bus Error on buffered store or cache line push\n"); 443 printk("Bus - Write Bus Error on buffered store or cache line push\n");
424#else /* !CONFIG_4xx && !CONFIG_E500 && !CONFIG_E200 */ 444
445 return 0;
446}
447#else
448int machine_check_generic(struct pt_regs *regs)
449{
450 unsigned long reason = get_mc_reason(regs);
451
425 printk("Machine check in kernel mode.\n"); 452 printk("Machine check in kernel mode.\n");
426 printk("Caused by (from SRR1=%lx): ", reason); 453 printk("Caused by (from SRR1=%lx): ", reason);
427 switch (reason & 0x601F0000) { 454 switch (reason & 0x601F0000) {
@@ -451,22 +478,26 @@ static int generic_machine_check_exception(struct pt_regs *regs)
451 default: 478 default:
452 printk("Unknown values in msr\n"); 479 printk("Unknown values in msr\n");
453 } 480 }
454#endif /* CONFIG_4xx */
455
456 return 0; 481 return 0;
457} 482}
483#endif /* everything else */
458 484
459void machine_check_exception(struct pt_regs *regs) 485void machine_check_exception(struct pt_regs *regs)
460{ 486{
461 int recover = 0; 487 int recover = 0;
462 488
463 /* See if any machine dependent calls */ 489 /* See if any machine dependent calls. In theory, we would want
490 * to call the CPU first, and call the ppc_md. one if the CPU
491 * one returns a positive number. However there is existing code
492 * that assumes the board gets a first chance, so let's keep it
493 * that way for now and fix things later. --BenH.
494 */
464 if (ppc_md.machine_check_exception) 495 if (ppc_md.machine_check_exception)
465 recover = ppc_md.machine_check_exception(regs); 496 recover = ppc_md.machine_check_exception(regs);
466 else 497 else if (cur_cpu_spec->machine_check)
467 recover = generic_machine_check_exception(regs); 498 recover = cur_cpu_spec->machine_check(regs);
468 499
469 if (recover) 500 if (recover > 0)
470 return; 501 return;
471 502
472 if (user_mode(regs)) { 503 if (user_mode(regs)) {
@@ -476,7 +507,12 @@ void machine_check_exception(struct pt_regs *regs)
476 } 507 }
477 508
478#if defined(CONFIG_8xx) && defined(CONFIG_PCI) 509#if defined(CONFIG_8xx) && defined(CONFIG_PCI)
479 /* the qspan pci read routines can cause machine checks -- Cort */ 510 /* the qspan pci read routines can cause machine checks -- Cort
511 *
512 * yuck !!! that totally needs to go away ! There are better ways
513 * to deal with that than having a wart in the mcheck handler.
514 * -- BenH
515 */
480 bad_page_fault(regs, regs->dar, SIGBUS); 516 bad_page_fault(regs, regs->dar, SIGBUS);
481 return; 517 return;
482#endif 518#endif