Merge branch 'for-linus' of ssh://master.kernel.org/pub/scm/linux/kernel/git/ieee1394...
[pandora-kernel.git] / arch / mips / kernel / process.c
index 2613a0d..04e5b38 100644 (file)
 #include <asm/elf.h>
 #include <asm/isadep.h>
 #include <asm/inst.h>
-#ifdef CONFIG_MIPS_MT_SMTC
-#include <asm/mipsmtregs.h>
-extern void smtc_idle_loop_hook(void);
-#endif /* CONFIG_MIPS_MT_SMTC */
+#include <asm/stacktrace.h>
 
 /*
  * The idle thread. There's no useful work to be done, so just try to conserve
@@ -56,6 +53,8 @@ ATTRIB_NORET void cpu_idle(void)
        while (1) {
                while (!need_resched()) {
 #ifdef CONFIG_MIPS_MT_SMTC
+                       extern void smtc_idle_loop_hook(void);
+
                        smtc_idle_loop_hook();
 #endif /* CONFIG_MIPS_MT_SMTC */
                        if (cpu_wait)
@@ -114,7 +113,7 @@ void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp)
        status |= KU_USER;
        regs->cp0_status = status;
        clear_used_math();
-       lose_fpu();
+       clear_fpu_owner();
        if (cpu_has_dsp)
                __init_dsp();
        regs->cp0_epc = pc;
@@ -357,10 +356,8 @@ static int __init frame_info_init(void)
        unsigned long size = 0;
 #ifdef CONFIG_KALLSYMS
        unsigned long ofs;
-       char *modname;
-       char namebuf[KSYM_NAME_LEN + 1];
 
-       kallsyms_lookup((unsigned long)schedule, &size, &ofs, &modname, namebuf);
+       kallsyms_lookup_size_offset((unsigned long)schedule, &size, &ofs);
 #endif
        schedule_mfi.func = schedule;
        schedule_mfi.func_size = size;
@@ -398,26 +395,48 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
 #ifdef CONFIG_KALLSYMS
 /* used by show_backtrace() */
 unsigned long unwind_stack(struct task_struct *task, unsigned long *sp,
-                          unsigned long pc, unsigned long ra)
+                          unsigned long pc, unsigned long *ra)
 {
        unsigned long stack_page;
        struct mips_frame_info info;
-       char *modname;
-       char namebuf[KSYM_NAME_LEN + 1];
        unsigned long size, ofs;
        int leaf;
+       extern void ret_from_irq(void);
+       extern void ret_from_exception(void);
 
        stack_page = (unsigned long)task_stack_page(task);
        if (!stack_page)
                return 0;
 
-       if (!kallsyms_lookup(pc, &size, &ofs, &modname, namebuf))
+       /*
+        * If we reached the bottom of interrupt context,
+        * return saved pc in pt_regs.
+        */
+       if (pc == (unsigned long)ret_from_irq ||
+           pc == (unsigned long)ret_from_exception) {
+               struct pt_regs *regs;
+               if (*sp >= stack_page &&
+                   *sp + sizeof(*regs) <= stack_page + THREAD_SIZE - 32) {
+                       regs = (struct pt_regs *)*sp;
+                       pc = regs->cp0_epc;
+                       if (__kernel_text_address(pc)) {
+                               *sp = regs->regs[29];
+                               *ra = regs->regs[31];
+                               return pc;
+                       }
+               }
+               return 0;
+       }
+       if (!kallsyms_lookup_size_offset(pc, &size, &ofs))
                return 0;
        /*
         * Return ra if an exception occured at the first instruction
         */
-       if (unlikely(ofs == 0))
-               return ra;
+       if (unlikely(ofs == 0)) {
+               pc = *ra;
+               *ra = 0;
+               return pc;
+       }
 
        info.func = (void *)(pc - ofs);
        info.func_size = ofs;   /* analyze from start to ofs */
@@ -436,11 +455,12 @@ unsigned long unwind_stack(struct task_struct *task, unsigned long *sp,
                 * one. In that cases avoid to return always the
                 * same value.
                 */
-               pc = pc != ra ? ra : 0;
+               pc = pc != *ra ? *ra : 0;
        else
                pc = ((unsigned long *)(*sp))[info.pc_offset];
 
        *sp += info.frame_size;
+       *ra = 0;
        return __kernel_text_address(pc) ? pc : 0;
 }
 #endif
@@ -453,6 +473,7 @@ unsigned long get_wchan(struct task_struct *task)
        unsigned long pc = 0;
 #ifdef CONFIG_KALLSYMS
        unsigned long sp;
+       unsigned long ra = 0;
 #endif
 
        if (!task || task == current || task->state == TASK_RUNNING)
@@ -466,7 +487,7 @@ unsigned long get_wchan(struct task_struct *task)
        sp = task->thread.reg29 + schedule_mfi.frame_size;
 
        while (in_sched_functions(pc))
-               pc = unwind_stack(task, &sp, pc, 0);
+               pc = unwind_stack(task, &sp, pc, &ra);
 #endif
 
 out: