MIPS: Set trap_no field in thread_struct on exception.
[linux-drm-fsl-dcu.git] / arch / mips / kernel / traps.c
index e207a43b5f8f0bcbf0544e5289cfc08126cbc7f5..cea964daf400644404e28d0f44477ecd86a94c8d 100644 (file)
@@ -192,6 +192,7 @@ static void show_stacktrace(struct task_struct *task,
 void show_stack(struct task_struct *task, unsigned long *sp)
 {
        struct pt_regs regs;
+       mm_segment_t old_fs = get_fs();
        if (sp) {
                regs.regs[29] = (unsigned long)sp;
                regs.regs[31] = 0;
@@ -210,7 +211,13 @@ void show_stack(struct task_struct *task, unsigned long *sp)
                        prepare_frametrace(&regs);
                }
        }
+       /*
+        * show_stack() deals exclusively with kernel mode, so be sure to access
+        * the stack in the kernel (not user) address space.
+        */
+       set_fs(KERNEL_DS);
        show_stacktrace(task, &regs);
+       set_fs(old_fs);
 }
 
 static void show_code(unsigned int __user *pc)
@@ -363,11 +370,6 @@ void show_registers(struct pt_regs *regs)
        set_fs(old_fs);
 }
 
-static int regs_to_trapnr(struct pt_regs *regs)
-{
-       return (regs->cp0_cause >> 2) & 0x1f;
-}
-
 static DEFINE_RAW_SPINLOCK(die_lock);
 
 void __noreturn die(const char *str, struct pt_regs *regs)
@@ -377,7 +379,7 @@ void __noreturn die(const char *str, struct pt_regs *regs)
 
        oops_enter();
 
-       if (notify_die(DIE_OOPS, str, regs, 0, regs_to_trapnr(regs),
+       if (notify_die(DIE_OOPS, str, regs, 0, current->thread.trap_nr,
                       SIGSEGV) == NOTIFY_STOP)
                sig = 0;
 
@@ -463,7 +465,7 @@ asmlinkage void do_be(struct pt_regs *regs)
        printk(KERN_ALERT "%s bus error, epc == %0*lx, ra == %0*lx\n",
               data ? "Data" : "Instruction",
               field, regs->cp0_epc, field, regs->regs[31]);
-       if (notify_die(DIE_OOPS, "bus error", regs, 0, regs_to_trapnr(regs),
+       if (notify_die(DIE_OOPS, "bus error", regs, 0, current->thread.trap_nr,
                       SIGBUS) == NOTIFY_STOP)
                goto out;
 
@@ -819,7 +821,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
        int sig;
 
        prev_state = exception_enter();
-       if (notify_die(DIE_FP, "FP exception", regs, 0, regs_to_trapnr(regs),
+       if (notify_die(DIE_FP, "FP exception", regs, 0, current->thread.trap_nr,
                       SIGFPE) == NOTIFY_STOP)
                goto out;
 
@@ -875,11 +877,12 @@ void do_trap_or_bp(struct pt_regs *regs, unsigned int code,
        char b[40];
 
 #ifdef CONFIG_KGDB_LOW_LEVEL_TRAP
-       if (kgdb_ll_trap(DIE_TRAP, str, regs, code, regs_to_trapnr(regs), SIGTRAP) == NOTIFY_STOP)
+       if (kgdb_ll_trap(DIE_TRAP, str, regs, code, current->thread.trap_nr,
+                        SIGTRAP) == NOTIFY_STOP)
                return;
 #endif /* CONFIG_KGDB_LOW_LEVEL_TRAP */
 
-       if (notify_die(DIE_TRAP, str, regs, code, regs_to_trapnr(regs),
+       if (notify_die(DIE_TRAP, str, regs, code, current->thread.trap_nr,
                       SIGTRAP) == NOTIFY_STOP)
                return;
 
@@ -941,6 +944,7 @@ asmlinkage void do_bp(struct pt_regs *regs)
                set_fs(KERNEL_DS);
 
        prev_state = exception_enter();
+       current->thread.trap_nr = (regs->cp0_cause >> 2) & 0x1f;
        if (get_isa16_mode(regs->cp0_epc)) {
                u16 instr[2];
 
@@ -982,13 +986,13 @@ asmlinkage void do_bp(struct pt_regs *regs)
        switch (bcode) {
        case BRK_KPROBE_BP:
                if (notify_die(DIE_BREAK, "debug", regs, bcode,
-                              regs_to_trapnr(regs), SIGTRAP) == NOTIFY_STOP)
+                              current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP)
                        goto out;
                else
                        break;
        case BRK_KPROBE_SSTEPBP:
                if (notify_die(DIE_SSTEPBP, "single_step", regs, bcode,
-                              regs_to_trapnr(regs), SIGTRAP) == NOTIFY_STOP)
+                              current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP)
                        goto out;
                else
                        break;
@@ -1021,6 +1025,7 @@ asmlinkage void do_tr(struct pt_regs *regs)
                set_fs(get_ds());
 
        prev_state = exception_enter();
+       current->thread.trap_nr = (regs->cp0_cause >> 2) & 0x1f;
        if (get_isa16_mode(regs->cp0_epc)) {
                if (__get_user(instr[0], (u16 __user *)(epc + 0)) ||
                    __get_user(instr[1], (u16 __user *)(epc + 2)))
@@ -1087,8 +1092,9 @@ asmlinkage void do_ri(struct pt_regs *regs)
 no_r2_instr:
 
        prev_state = exception_enter();
+       current->thread.trap_nr = (regs->cp0_cause >> 2) & 0x1f;
 
-       if (notify_die(DIE_RI, "RI Fault", regs, 0, regs_to_trapnr(regs),
+       if (notify_die(DIE_RI, "RI Fault", regs, 0, current->thread.trap_nr,
                       SIGILL) == NOTIFY_STOP)
                goto out;
 
@@ -1437,8 +1443,9 @@ asmlinkage void do_msa_fpe(struct pt_regs *regs, unsigned int msacsr)
        enum ctx_state prev_state;
 
        prev_state = exception_enter();
+       current->thread.trap_nr = (regs->cp0_cause >> 2) & 0x1f;
        if (notify_die(DIE_MSAFP, "MSA FP exception", regs, 0,
-                      regs_to_trapnr(regs), SIGFPE) == NOTIFY_STOP)
+                      current->thread.trap_nr, SIGFPE) == NOTIFY_STOP)
                goto out;
 
        /* Clear MSACSR.Cause before enabling interrupts */
@@ -1516,32 +1523,26 @@ asmlinkage void do_watch(struct pt_regs *regs)
 
 asmlinkage void do_mcheck(struct pt_regs *regs)
 {
-       const int field = 2 * sizeof(unsigned long);
        int multi_match = regs->cp0_status & ST0_TS;
        enum ctx_state prev_state;
+       mm_segment_t old_fs = get_fs();
 
        prev_state = exception_enter();
        show_regs(regs);
 
        if (multi_match) {
-               pr_err("Index   : %0x\n", read_c0_index());
-               pr_err("Pagemask: %0x\n", read_c0_pagemask());
-               pr_err("EntryHi : %0*lx\n", field, read_c0_entryhi());
-               pr_err("EntryLo0: %0*lx\n", field, read_c0_entrylo0());
-               pr_err("EntryLo1: %0*lx\n", field, read_c0_entrylo1());
-               pr_err("Wired   : %0x\n", read_c0_wired());
-               pr_err("Pagegrain: %0x\n", read_c0_pagegrain());
-               if (cpu_has_htw) {
-                       pr_err("PWField : %0*lx\n", field, read_c0_pwfield());
-                       pr_err("PWSize  : %0*lx\n", field, read_c0_pwsize());
-                       pr_err("PWCtl   : %0x\n", read_c0_pwctl());
-               }
-               pr_err("\n");
+               dump_tlb_regs();
+               pr_info("\n");
                dump_tlb_all();
        }
 
+       if (!user_mode(regs))
+               set_fs(KERNEL_DS);
+
        show_code((unsigned int __user *) regs->cp0_epc);
 
+       set_fs(old_fs);
+
        /*
         * Some chips may have other causes of machine check (e.g. SB1
         * graduation timer)
@@ -1638,6 +1639,7 @@ static inline void parity_protection_init(void)
        case CPU_PROAPTIV:
        case CPU_P5600:
        case CPU_QEMU_GENERIC:
+       case CPU_I6400:
                {
 #define ERRCTL_PE      0x80000000
 #define ERRCTL_L2P     0x00800000