Merge ../linux-2.6-watchdog-mm
[linux-drm-fsl-dcu.git] / arch / mips / kernel / traps.c
index 368fdb779175a396c71127c9e36e8008d5a7e41b..9fda1b8be3a7e53f52a0bbfb698869971117a4d3 100644 (file)
@@ -41,6 +41,7 @@
 #include <asm/mmu_context.h>
 #include <asm/watch.h>
 #include <asm/types.h>
+#include <asm/stacktrace.h>
 
 extern asmlinkage void handle_int(void);
 extern asmlinkage void handle_tlbm(void);
@@ -65,7 +66,7 @@ extern asmlinkage void handle_mcheck(void);
 extern asmlinkage void handle_reserved(void);
 
 extern int fpu_emulator_cop1Handler(struct pt_regs *xcp,
-       struct mips_fpu_struct *ctx);
+       struct mips_fpu_struct *ctx, int has_fpu);
 
 void (*board_be_init)(void);
 int (*board_be_handler)(struct pt_regs *regs, int is_fixup);
@@ -73,28 +74,62 @@ void (*board_nmi_handler_setup)(void);
 void (*board_ejtag_handler_setup)(void);
 void (*board_bind_eic_interrupt)(int irq, int regset);
 
-/*
- * These constant is for searching for possible module text segments.
- * MODULE_RANGE is a guess of how much space is likely to be vmalloced.
- */
-#define MODULE_RANGE (8*1024*1024)
+
+static void show_raw_backtrace(unsigned long reg29)
+{
+       unsigned long *sp = (unsigned long *)reg29;
+       unsigned long addr;
+
+       printk("Call Trace:");
+#ifdef CONFIG_KALLSYMS
+       printk("\n");
+#endif
+       while (!kstack_end(sp)) {
+               addr = *sp++;
+               if (__kernel_text_address(addr))
+                       print_ip_sym(addr);
+       }
+       printk("\n");
+}
+
+#ifdef CONFIG_KALLSYMS
+int raw_show_trace;
+static int __init set_raw_show_trace(char *str)
+{
+       raw_show_trace = 1;
+       return 1;
+}
+__setup("raw_show_trace", set_raw_show_trace);
+#endif
+
+static void show_backtrace(struct task_struct *task, struct pt_regs *regs)
+{
+       unsigned long sp = regs->regs[29];
+       unsigned long ra = regs->regs[31];
+       unsigned long pc = regs->cp0_epc;
+
+       if (raw_show_trace || !__kernel_text_address(pc)) {
+               show_raw_backtrace(sp);
+               return;
+       }
+       printk("Call Trace:\n");
+       do {
+               print_ip_sym(pc);
+               pc = unwind_stack(task, &sp, pc, &ra);
+       } while (pc);
+       printk("\n");
+}
 
 /*
  * This routine abuses get_user()/put_user() to reference pointers
  * with at least a bit of error checking ...
  */
-void show_stack(struct task_struct *task, unsigned long *sp)
+static void show_stacktrace(struct task_struct *task, struct pt_regs *regs)
 {
        const int field = 2 * sizeof(unsigned long);
        long stackdata;
        int i;
-
-       if (!sp) {
-               if (task && task != current)
-                       sp = (unsigned long *) task->thread.reg29;
-               else
-                       sp = (unsigned long *) &sp;
-       }
+       unsigned long *sp = (unsigned long *)regs->regs[29];
 
        printk("Stack :");
        i = 0;
@@ -115,32 +150,26 @@ void show_stack(struct task_struct *task, unsigned long *sp)
                i++;
        }
        printk("\n");
+       show_backtrace(task, regs);
 }
 
-void show_trace(struct task_struct *task, unsigned long *stack)
+void show_stack(struct task_struct *task, unsigned long *sp)
 {
-       const int field = 2 * sizeof(unsigned long);
-       unsigned long addr;
-
-       if (!stack) {
-               if (task && task != current)
-                       stack = (unsigned long *) task->thread.reg29;
-               else
-                       stack = (unsigned long *) &stack;
-       }
-
-       printk("Call Trace:");
-#ifdef CONFIG_KALLSYMS
-       printk("\n");
-#endif
-       while (!kstack_end(stack)) {
-               addr = *stack++;
-               if (__kernel_text_address(addr)) {
-                       printk(" [<%0*lx>] ", field, addr);
-                       print_symbol("%s\n", addr);
+       struct pt_regs regs;
+       if (sp) {
+               regs.regs[29] = (unsigned long)sp;
+               regs.regs[31] = 0;
+               regs.cp0_epc = 0;
+       } else {
+               if (task && task != current) {
+                       regs.regs[29] = task->thread.reg29;
+                       regs.regs[31] = 0;
+                       regs.cp0_epc = task->thread.reg31;
+               } else {
+                       prepare_frametrace(&regs);
                }
        }
-       printk("\n");
+       show_stacktrace(task, &regs);
 }
 
 /*
@@ -148,9 +177,10 @@ void show_trace(struct task_struct *task, unsigned long *stack)
  */
 void dump_stack(void)
 {
-       unsigned long stack;
+       struct pt_regs regs;
 
-       show_trace(current, &stack);
+       prepare_frametrace(&regs);
+       show_backtrace(current, &regs);
 }
 
 EXPORT_SYMBOL(dump_stack);
@@ -269,8 +299,7 @@ void show_registers(struct pt_regs *regs)
        print_modules();
        printk("Process %s (pid: %d, threadinfo=%p, task=%p)\n",
                current->comm, current->pid, current_thread_info(), current);
-       show_stack(current, (long *) regs->regs[29]);
-       show_trace(current, (long *) regs->regs[29]);
+       show_stacktrace(current, regs);
        show_code((unsigned int *) regs->cp0_epc);
        printk("\n");
 }
@@ -612,7 +641,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
                preempt_enable();
 
                /* Run the emulator */
-               sig = fpu_emulator_cop1Handler (regs, &current->thread.fpu);
+               sig = fpu_emulator_cop1Handler (regs, &current->thread.fpu, 1);
 
                preempt_disable();
 
@@ -762,11 +791,13 @@ asmlinkage void do_cpu(struct pt_regs *regs)
                        set_used_math();
                }
 
-               preempt_enable();
-
-               if (!cpu_has_fpu) {
-                       int sig = fpu_emulator_cop1Handler(regs,
-                                               &current->thread.fpu);
+               if (cpu_has_fpu) {
+                       preempt_enable();
+               } else {
+                       int sig;
+                       preempt_enable();
+                       sig = fpu_emulator_cop1Handler(regs,
+                                               &current->thread.fpu, 0);
                        if (sig)
                                force_sig(sig, current);
 #ifdef CONFIG_MIPS_MT_FPAFF
@@ -1080,7 +1111,7 @@ static struct shadow_registers {
 static void mips_srs_init(void)
 {
        shadow_registers.sr_supported = ((read_c0_srsctl() >> 26) & 0x0f) + 1;
-       printk(KERN_INFO "%d MIPSR2 register sets available\n",
+       printk(KERN_INFO "%ld MIPSR2 register sets available\n",
               shadow_registers.sr_supported);
        shadow_registers.sr_allocated = 1;      /* Set 0 used by kernel */
 }