diff options
Diffstat (limited to 'arch/powerpc/kernel/traps.c')
-rw-r--r-- | arch/powerpc/kernel/traps.c | 81 |
1 files changed, 55 insertions, 26 deletions
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index a45a63c3a0c7..1a0141426cda 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/bug.h> | 34 | #include <linux/bug.h> |
35 | #include <linux/kdebug.h> | 35 | #include <linux/kdebug.h> |
36 | #include <linux/debugfs.h> | 36 | #include <linux/debugfs.h> |
37 | #include <linux/ratelimit.h> | ||
37 | 38 | ||
38 | #include <asm/emulated_ops.h> | 39 | #include <asm/emulated_ops.h> |
39 | #include <asm/pgtable.h> | 40 | #include <asm/pgtable.h> |
@@ -55,6 +56,7 @@ | |||
55 | #endif | 56 | #endif |
56 | #include <asm/kexec.h> | 57 | #include <asm/kexec.h> |
57 | #include <asm/ppc-opcode.h> | 58 | #include <asm/ppc-opcode.h> |
59 | #include <asm/rio.h> | ||
58 | 60 | ||
59 | #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) | 61 | #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) |
60 | int (*__debugger)(struct pt_regs *regs) __read_mostly; | 62 | int (*__debugger)(struct pt_regs *regs) __read_mostly; |
@@ -143,7 +145,6 @@ int die(const char *str, struct pt_regs *regs, long err) | |||
143 | #endif | 145 | #endif |
144 | printk("%s\n", ppc_md.name ? ppc_md.name : ""); | 146 | printk("%s\n", ppc_md.name ? ppc_md.name : ""); |
145 | 147 | ||
146 | sysfs_printk_last_file(); | ||
147 | if (notify_die(DIE_OOPS, str, regs, err, 255, | 148 | if (notify_die(DIE_OOPS, str, regs, err, 255, |
148 | SIGSEGV) == NOTIFY_STOP) | 149 | SIGSEGV) == NOTIFY_STOP) |
149 | return 1; | 150 | return 1; |
@@ -197,12 +198,11 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) | |||
197 | if (die("Exception in kernel mode", regs, signr)) | 198 | if (die("Exception in kernel mode", regs, signr)) |
198 | return; | 199 | return; |
199 | } else if (show_unhandled_signals && | 200 | } else if (show_unhandled_signals && |
200 | unhandled_signal(current, signr) && | 201 | unhandled_signal(current, signr)) { |
201 | printk_ratelimit()) { | 202 | printk_ratelimited(regs->msr & MSR_64BIT ? fmt64 : fmt32, |
202 | printk(regs->msr & MSR_SF ? fmt64 : fmt32, | 203 | current->comm, current->pid, signr, |
203 | current->comm, current->pid, signr, | 204 | addr, regs->nip, regs->link, code); |
204 | addr, regs->nip, regs->link, code); | 205 | } |
205 | } | ||
206 | 206 | ||
207 | memset(&info, 0, sizeof(info)); | 207 | memset(&info, 0, sizeof(info)); |
208 | info.si_signo = signr; | 208 | info.si_signo = signr; |
@@ -221,7 +221,7 @@ void system_reset_exception(struct pt_regs *regs) | |||
221 | } | 221 | } |
222 | 222 | ||
223 | #ifdef CONFIG_KEXEC | 223 | #ifdef CONFIG_KEXEC |
224 | cpu_set(smp_processor_id(), cpus_in_sr); | 224 | cpumask_set_cpu(smp_processor_id(), &cpus_in_sr); |
225 | #endif | 225 | #endif |
226 | 226 | ||
227 | die("System Reset", regs, SIGABRT); | 227 | die("System Reset", regs, SIGABRT); |
@@ -425,6 +425,12 @@ int machine_check_e500mc(struct pt_regs *regs) | |||
425 | unsigned long reason = mcsr; | 425 | unsigned long reason = mcsr; |
426 | int recoverable = 1; | 426 | int recoverable = 1; |
427 | 427 | ||
428 | if (reason & MCSR_LD) { | ||
429 | recoverable = fsl_rio_mcheck_exception(regs); | ||
430 | if (recoverable == 1) | ||
431 | goto silent_out; | ||
432 | } | ||
433 | |||
428 | printk("Machine check in kernel mode.\n"); | 434 | printk("Machine check in kernel mode.\n"); |
429 | printk("Caused by (from MCSR=%lx): ", reason); | 435 | printk("Caused by (from MCSR=%lx): ", reason); |
430 | 436 | ||
@@ -500,6 +506,7 @@ int machine_check_e500mc(struct pt_regs *regs) | |||
500 | reason & MCSR_MEA ? "Effective" : "Physical", addr); | 506 | reason & MCSR_MEA ? "Effective" : "Physical", addr); |
501 | } | 507 | } |
502 | 508 | ||
509 | silent_out: | ||
503 | mtspr(SPRN_MCSR, mcsr); | 510 | mtspr(SPRN_MCSR, mcsr); |
504 | return mfspr(SPRN_MCSR) == 0 && recoverable; | 511 | return mfspr(SPRN_MCSR) == 0 && recoverable; |
505 | } | 512 | } |
@@ -508,6 +515,11 @@ int machine_check_e500(struct pt_regs *regs) | |||
508 | { | 515 | { |
509 | unsigned long reason = get_mc_reason(regs); | 516 | unsigned long reason = get_mc_reason(regs); |
510 | 517 | ||
518 | if (reason & MCSR_BUS_RBERR) { | ||
519 | if (fsl_rio_mcheck_exception(regs)) | ||
520 | return 1; | ||
521 | } | ||
522 | |||
511 | printk("Machine check in kernel mode.\n"); | 523 | printk("Machine check in kernel mode.\n"); |
512 | printk("Caused by (from MCSR=%lx): ", reason); | 524 | printk("Caused by (from MCSR=%lx): ", reason); |
513 | 525 | ||
@@ -538,6 +550,11 @@ int machine_check_e500(struct pt_regs *regs) | |||
538 | 550 | ||
539 | return 0; | 551 | return 0; |
540 | } | 552 | } |
553 | |||
554 | int machine_check_generic(struct pt_regs *regs) | ||
555 | { | ||
556 | return 0; | ||
557 | } | ||
541 | #elif defined(CONFIG_E200) | 558 | #elif defined(CONFIG_E200) |
542 | int machine_check_e200(struct pt_regs *regs) | 559 | int machine_check_e200(struct pt_regs *regs) |
543 | { | 560 | { |
@@ -621,12 +638,6 @@ void machine_check_exception(struct pt_regs *regs) | |||
621 | if (recover > 0) | 638 | if (recover > 0) |
622 | return; | 639 | return; |
623 | 640 | ||
624 | if (user_mode(regs)) { | ||
625 | regs->msr |= MSR_RI; | ||
626 | _exception(SIGBUS, regs, BUS_ADRERR, regs->nip); | ||
627 | return; | ||
628 | } | ||
629 | |||
630 | #if defined(CONFIG_8xx) && defined(CONFIG_PCI) | 641 | #if defined(CONFIG_8xx) && defined(CONFIG_PCI) |
631 | /* the qspan pci read routines can cause machine checks -- Cort | 642 | /* the qspan pci read routines can cause machine checks -- Cort |
632 | * | 643 | * |
@@ -638,16 +649,12 @@ void machine_check_exception(struct pt_regs *regs) | |||
638 | return; | 649 | return; |
639 | #endif | 650 | #endif |
640 | 651 | ||
641 | if (debugger_fault_handler(regs)) { | 652 | if (debugger_fault_handler(regs)) |
642 | regs->msr |= MSR_RI; | ||
643 | return; | 653 | return; |
644 | } | ||
645 | 654 | ||
646 | if (check_io_access(regs)) | 655 | if (check_io_access(regs)) |
647 | return; | 656 | return; |
648 | 657 | ||
649 | if (debugger_fault_handler(regs)) | ||
650 | return; | ||
651 | die("Machine check", regs, SIGBUS); | 658 | die("Machine check", regs, SIGBUS); |
652 | 659 | ||
653 | /* Must die if the interrupt is not recoverable */ | 660 | /* Must die if the interrupt is not recoverable */ |
@@ -914,6 +921,26 @@ static int emulate_instruction(struct pt_regs *regs) | |||
914 | return emulate_isel(regs, instword); | 921 | return emulate_isel(regs, instword); |
915 | } | 922 | } |
916 | 923 | ||
924 | #ifdef CONFIG_PPC64 | ||
925 | /* Emulate the mfspr rD, DSCR. */ | ||
926 | if (((instword & PPC_INST_MFSPR_DSCR_MASK) == PPC_INST_MFSPR_DSCR) && | ||
927 | cpu_has_feature(CPU_FTR_DSCR)) { | ||
928 | PPC_WARN_EMULATED(mfdscr, regs); | ||
929 | rd = (instword >> 21) & 0x1f; | ||
930 | regs->gpr[rd] = mfspr(SPRN_DSCR); | ||
931 | return 0; | ||
932 | } | ||
933 | /* Emulate the mtspr DSCR, rD. */ | ||
934 | if (((instword & PPC_INST_MTSPR_DSCR_MASK) == PPC_INST_MTSPR_DSCR) && | ||
935 | cpu_has_feature(CPU_FTR_DSCR)) { | ||
936 | PPC_WARN_EMULATED(mtdscr, regs); | ||
937 | rd = (instword >> 21) & 0x1f; | ||
938 | mtspr(SPRN_DSCR, regs->gpr[rd]); | ||
939 | current->thread.dscr_inherit = 1; | ||
940 | return 0; | ||
941 | } | ||
942 | #endif | ||
943 | |||
917 | return -EINVAL; | 944 | return -EINVAL; |
918 | } | 945 | } |
919 | 946 | ||
@@ -964,7 +991,7 @@ void __kprobes program_check_exception(struct pt_regs *regs) | |||
964 | * ESR_DST (!?) or 0. In the process of chasing this with the | 991 | * ESR_DST (!?) or 0. In the process of chasing this with the |
965 | * hardware people - not sure if it can happen on any illegal | 992 | * hardware people - not sure if it can happen on any illegal |
966 | * instruction or only on FP instructions, whether there is a | 993 | * instruction or only on FP instructions, whether there is a |
967 | * pattern to occurences etc. -dgibson 31/Mar/2003 */ | 994 | * pattern to occurrences etc. -dgibson 31/Mar/2003 */ |
968 | switch (do_mathemu(regs)) { | 995 | switch (do_mathemu(regs)) { |
969 | case 0: | 996 | case 0: |
970 | emulate_single_step(regs); | 997 | emulate_single_step(regs); |
@@ -1315,9 +1342,8 @@ void altivec_assist_exception(struct pt_regs *regs) | |||
1315 | } else { | 1342 | } else { |
1316 | /* didn't recognize the instruction */ | 1343 | /* didn't recognize the instruction */ |
1317 | /* XXX quick hack for now: set the non-Java bit in the VSCR */ | 1344 | /* XXX quick hack for now: set the non-Java bit in the VSCR */ |
1318 | if (printk_ratelimit()) | 1345 | printk_ratelimited(KERN_ERR "Unrecognized altivec instruction " |
1319 | printk(KERN_ERR "Unrecognized altivec instruction " | 1346 | "in %s at %lx\n", current->comm, regs->nip); |
1320 | "in %s at %lx\n", current->comm, regs->nip); | ||
1321 | current->thread.vscr.u[3] |= 0x10000; | 1347 | current->thread.vscr.u[3] |= 0x10000; |
1322 | } | 1348 | } |
1323 | } | 1349 | } |
@@ -1511,15 +1537,18 @@ struct ppc_emulated ppc_emulated = { | |||
1511 | #ifdef CONFIG_VSX | 1537 | #ifdef CONFIG_VSX |
1512 | WARN_EMULATED_SETUP(vsx), | 1538 | WARN_EMULATED_SETUP(vsx), |
1513 | #endif | 1539 | #endif |
1540 | #ifdef CONFIG_PPC64 | ||
1541 | WARN_EMULATED_SETUP(mfdscr), | ||
1542 | WARN_EMULATED_SETUP(mtdscr), | ||
1543 | #endif | ||
1514 | }; | 1544 | }; |
1515 | 1545 | ||
1516 | u32 ppc_warn_emulated; | 1546 | u32 ppc_warn_emulated; |
1517 | 1547 | ||
1518 | void ppc_warn_emulated_print(const char *type) | 1548 | void ppc_warn_emulated_print(const char *type) |
1519 | { | 1549 | { |
1520 | if (printk_ratelimit()) | 1550 | pr_warn_ratelimited("%s used emulated %s instruction\n", current->comm, |
1521 | pr_warning("%s used emulated %s instruction\n", current->comm, | 1551 | type); |
1522 | type); | ||
1523 | } | 1552 | } |
1524 | 1553 | ||
1525 | static int __init ppc_warn_emulated_init(void) | 1554 | static int __init ppc_warn_emulated_init(void) |