diff options
Diffstat (limited to 'arch/powerpc/kernel/traps.c')
-rw-r--r-- | arch/powerpc/kernel/traps.c | 87 |
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 | ||
337 | static int generic_machine_check_exception(struct pt_regs *regs) | 337 | #if defined(CONFIG_4xx) |
338 | int 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 | |||
352 | int 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) | ||
388 | int 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) | ||
423 | int 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 | ||
448 | int 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 | ||
459 | void machine_check_exception(struct pt_regs *regs) | 485 | void 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 | |||
625 | static int emulate_string_inst(struct pt_regs *regs, u32 instword) | 664 | static 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 | ||
749 | static 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 | |||
710 | static int emulate_instruction(struct pt_regs *regs) | 766 | static 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 | ||