aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/traps.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel/traps.c')
-rw-r--r--arch/powerpc/kernel/traps.c87
1 files changed, 74 insertions, 13 deletions
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 59c464e26f38..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
@@ -622,6 +658,9 @@ static void parse_fpe(struct pt_regs *regs)
622#define INST_POPCNTB 0x7c0000f4 658#define INST_POPCNTB 0x7c0000f4
623#define INST_POPCNTB_MASK 0xfc0007fe 659#define INST_POPCNTB_MASK 0xfc0007fe
624 660
661#define INST_ISEL 0x7c00001e
662#define INST_ISEL_MASK 0xfc00003e
663
625static int emulate_string_inst(struct pt_regs *regs, u32 instword) 664static int emulate_string_inst(struct pt_regs *regs, u32 instword)
626{ 665{
627 u8 rT = (instword >> 21) & 0x1f; 666 u8 rT = (instword >> 21) & 0x1f;
@@ -707,6 +746,23 @@ static int emulate_popcntb_inst(struct pt_regs *regs, u32 instword)
707 return 0; 746 return 0;
708} 747}
709 748
749static int emulate_isel(struct pt_regs *regs, u32 instword)
750{
751 u8 rT = (instword >> 21) & 0x1f;
752 u8 rA = (instword >> 16) & 0x1f;
753 u8 rB = (instword >> 11) & 0x1f;
754 u8 BC = (instword >> 6) & 0x1f;
755 u8 bit;
756 unsigned long tmp;
757
758 tmp = (rA == 0) ? 0 : regs->gpr[rA];
759 bit = (regs->ccr >> (31 - BC)) & 0x1;
760
761 regs->gpr[rT] = bit ? tmp : regs->gpr[rB];
762
763 return 0;
764}
765
710static int emulate_instruction(struct pt_regs *regs) 766static int emulate_instruction(struct pt_regs *regs)
711{ 767{
712 u32 instword; 768 u32 instword;
@@ -749,6 +805,11 @@ static int emulate_instruction(struct pt_regs *regs)
749 return emulate_popcntb_inst(regs, instword); 805 return emulate_popcntb_inst(regs, instword);
750 } 806 }
751 807
808 /* Emulate isel (Integer Select) instruction */
809 if ((instword & INST_ISEL_MASK) == INST_ISEL) {
810 return emulate_isel(regs, instword);
811 }
812
752 return -EINVAL; 813 return -EINVAL;
753} 814}
754 815