sh: Fix up DSP context save/restore.
[safe/jmp/linux-2.6] / arch / sh / kernel / process_32.c
index 6d7f2b0..0747fab 100644 (file)
@@ -7,7 +7,11 @@
  *
  *  SuperH version:  Copyright (C) 1999, 2000  Niibe Yutaka & Kaz Kojima
  *                  Copyright (C) 2006 Lineo Solutions Inc. support SH4A UBC
- *                  Copyright (C) 2002 - 2007  Paul Mundt
+ *                  Copyright (C) 2002 - 2008  Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
  */
 #include <linux/module.h>
 #include <linux/mm.h>
 #include <asm/pgalloc.h>
 #include <asm/system.h>
 #include <asm/ubc.h>
+#include <asm/fpu.h>
+#include <asm/syscalls.h>
 
-static int hlt_counter;
 int ubc_usercnt = 0;
 
-void (*pm_idle)(void);
-void (*pm_power_off)(void);
-EXPORT_SYMBOL(pm_power_off);
-
-void disable_hlt(void)
-{
-       hlt_counter++;
-}
-EXPORT_SYMBOL(disable_hlt);
-
-void enable_hlt(void)
-{
-       hlt_counter--;
-}
-EXPORT_SYMBOL(enable_hlt);
-
-static int __init nohlt_setup(char *__unused)
-{
-       hlt_counter = 1;
-       return 1;
-}
-__setup("nohlt", nohlt_setup);
-
-static int __init hlt_setup(char *__unused)
-{
-       hlt_counter = 0;
-       return 1;
-}
-__setup("hlt", hlt_setup);
-
-void default_idle(void)
-{
-       if (!hlt_counter) {
-               clear_thread_flag(TIF_POLLING_NRFLAG);
-               smp_mb__after_clear_bit();
-               set_bl_bit();
-               while (!need_resched())
-                       cpu_sleep();
-               clear_bl_bit();
-               set_thread_flag(TIF_POLLING_NRFLAG);
-       } else
-               while (!need_resched())
-                       cpu_relax();
-}
-
-void cpu_idle(void)
-{
-       set_thread_flag(TIF_POLLING_NRFLAG);
-
-       /* endless idle loop with no priority at all */
-       while (1) {
-               void (*idle)(void) = pm_idle;
-
-               if (!idle)
-                       idle = default_idle;
-
-               tick_nohz_stop_sched_tick();
-               while (!need_resched())
-                       idle();
-               tick_nohz_restart_sched_tick();
-
-               preempt_enable_no_resched();
-               schedule();
-               preempt_disable();
-               check_pgt_cache();
-       }
-}
-
 void machine_restart(char * __unused)
 {
        /* SR.BL=1 and invoke address error to let CPU reset (manual reset) */
@@ -121,16 +58,22 @@ void machine_power_off(void)
 void show_regs(struct pt_regs * regs)
 {
        printk("\n");
-       printk("Pid : %d, Comm: %20s\n", task_pid_nr(current), current->comm);
+       printk("Pid : %d, Comm: \t\t%s\n", task_pid_nr(current), current->comm);
+       printk("CPU : %d        \t\t%s  (%s %.*s)\n\n",
+              smp_processor_id(), print_tainted(), init_utsname()->release,
+              (int)strcspn(init_utsname()->version, " "),
+              init_utsname()->version);
+
        print_symbol("PC is at %s\n", instruction_pointer(regs));
+       print_symbol("PR is at %s\n", regs->pr);
+
        printk("PC  : %08lx SP  : %08lx SR  : %08lx ",
               regs->pc, regs->regs[15], regs->sr);
 #ifdef CONFIG_MMU
-       printk("TEA : %08x    ", ctrl_inl(MMU_TEA));
+       printk("TEA : %08x\n", ctrl_inl(MMU_TEA));
 #else
-       printk("                  ");
+       printk("\n");
 #endif
-       printk("%s\n", print_tainted());
 
        printk("R0  : %08lx R1  : %08lx R2  : %08lx R3  : %08lx\n",
               regs->regs[0],regs->regs[1],
@@ -148,31 +91,22 @@ void show_regs(struct pt_regs * regs)
               regs->mach, regs->macl, regs->gbr, regs->pr);
 
        show_trace(NULL, (unsigned long *)regs->regs[15], regs);
+       show_code(regs);
 }
 
 /*
  * Create a kernel thread
  */
-
-/*
- * This is the mechanism for creating a new kernel thread.
- *
- */
-extern void kernel_thread_helper(void);
-__asm__(".align 5\n"
-       "kernel_thread_helper:\n\t"
-       "jsr    @r5\n\t"
-       " nop\n\t"
-       "mov.l  1f, r1\n\t"
-       "jsr    @r1\n\t"
-       " mov   r0, r4\n\t"
-       ".align 2\n\t"
-       "1:.long do_exit");
+ATTRIB_NORET void kernel_thread_helper(void *arg, int (*fn)(void *))
+{
+       do_exit(fn(arg));
+}
 
 /* Don't use this in BL=1(cli).  Or else, CPU resets! */
 int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 {
        struct pt_regs regs;
+       int pid;
 
        memset(&regs, 0, sizeof(regs));
        regs.regs[4] = (unsigned long)arg;
@@ -182,8 +116,12 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
        regs.sr = (1 << 30);
 
        /* Ok, create the new process.. */
-       return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
-                      &regs, 0, NULL, NULL);
+       pid = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
+                     &regs, 0, NULL, NULL);
+
+       trace_mark(kernel_arch_kthread_create, "pid %d fn %p", pid, fn);
+
+       return pid;
 }
 
 /*
@@ -221,38 +159,10 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
        struct task_struct *tsk = current;
 
        fpvalid = !!tsk_used_math(tsk);
-       if (fpvalid) {
-               unlazy_fpu(tsk, regs);
-               memcpy(fpu, &tsk->thread.fpu.hard, sizeof(*fpu));
-       }
-#endif
-
-       return fpvalid;
-}
-
-/*
- * Capture the user space registers if the task is not running (in user space)
- */
-int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs)
-{
-       struct pt_regs ptregs;
-
-       ptregs = *task_pt_regs(tsk);
-       elf_core_copy_regs(regs, &ptregs);
-
-       return 1;
-}
-
-int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpu)
-{
-       int fpvalid = 0;
-
-#if defined(CONFIG_SH_FPU)
-       fpvalid = !!tsk_used_math(tsk);
-       if (fpvalid) {
-               unlazy_fpu(tsk, task_pt_regs(tsk));
-               memcpy(fpu, &tsk->thread.fpu.hard, sizeof(*fpu));
-       }
+       if (fpvalid)
+               fpvalid = !fpregs_get(tsk, NULL, 0,
+                                     sizeof(struct user_fpu_struct),
+                                     fpu, NULL);
 #endif
 
        return fpvalid;
@@ -266,14 +176,26 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
 {
        struct thread_info *ti = task_thread_info(p);
        struct pt_regs *childregs;
-#if defined(CONFIG_SH_FPU)
+#if defined(CONFIG_SH_FPU) || defined(CONFIG_SH_DSP)
        struct task_struct *tsk = current;
+#endif
 
+#if defined(CONFIG_SH_FPU)
        unlazy_fpu(tsk, regs);
        p->thread.fpu = tsk->thread.fpu;
        copy_to_stopped_child_used_math(p);
 #endif
 
+#if defined(CONFIG_SH_DSP)
+       if (is_dsp_enabled(tsk)) {
+               /* We can use the __save_dsp or just copy the struct:
+                * __save_dsp(p);
+                * p->thread.dsp_status.status |= SR_DSP
+                */
+               p->thread.dsp_status = tsk->thread.dsp_status;
+       }
+#endif
+
        childregs = task_pt_regs(p);
        *childregs = *regs;
 
@@ -350,25 +272,6 @@ struct task_struct *__switch_to(struct task_struct *prev,
        unlazy_fpu(prev, task_pt_regs(prev));
 #endif
 
-#if defined(CONFIG_GUSA) && defined(CONFIG_PREEMPT)
-       {
-               struct pt_regs *regs;
-
-               preempt_disable();
-               regs = task_pt_regs(prev);
-               if (user_mode(regs) && regs->regs[15] >= 0xc0000000) {
-                       int offset = (int)regs->regs[15];
-
-                       /* Reset stack pointer: clear critical region mark */
-                       regs->regs[15] = regs->regs[1];
-                       if (regs->pc < regs->regs[0])
-                               /* Go to rewind point */
-                               regs->pc = regs->regs[0] + offset;
-               }
-               preempt_enable_no_resched();
-       }
-#endif
-
 #ifdef CONFIG_MMU
        /*
         * Restore the kernel mode register
@@ -510,49 +413,3 @@ asmlinkage void break_point_trap(void)
 
        force_sig(SIGTRAP, current);
 }
-
-/*
- * Generic trap handler.
- */
-asmlinkage void debug_trap_handler(unsigned long r4, unsigned long r5,
-                                  unsigned long r6, unsigned long r7,
-                                  struct pt_regs __regs)
-{
-       struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
-
-       /* Rewind */
-       regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
-
-       if (notify_die(DIE_TRAP, "debug trap", regs, 0, regs->tra & 0xff,
-                      SIGTRAP) == NOTIFY_STOP)
-               return;
-
-       force_sig(SIGTRAP, current);
-}
-
-/*
- * Special handler for BUG() traps.
- */
-asmlinkage void bug_trap_handler(unsigned long r4, unsigned long r5,
-                                unsigned long r6, unsigned long r7,
-                                struct pt_regs __regs)
-{
-       struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
-
-       /* Rewind */
-       regs->pc -= instruction_size(ctrl_inw(regs->pc - 4));
-
-       if (notify_die(DIE_TRAP, "bug trap", regs, 0, TRAPA_BUG_OPCODE & 0xff,
-                      SIGTRAP) == NOTIFY_STOP)
-               return;
-
-#ifdef CONFIG_BUG
-       if (__kernel_text_address(instruction_pointer(regs))) {
-               u16 insn = *(u16 *)instruction_pointer(regs);
-               if (insn == TRAPA_BUG_OPCODE)
-                       handle_BUG(regs);
-       }
-#endif
-
-       force_sig(SIGTRAP, current);
-}