diff options
author | Michael Trimarchi <trimarchi@gandalf.sssup.it> | 2009-04-03 19:32:33 +0200 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2009-04-04 17:48:11 +0200 |
commit | 01ab10393c510342ec4ce85df11ccfa3df06bbb2 (patch) | |
tree | ebf0493fa7b53941f830f8b300037f834eb85e59 /arch/sh/kernel | |
parent | sh: Fix up number of on-chip DMA channels on SH7091. (diff) | |
download | linux-01ab10393c510342ec4ce85df11ccfa3df06bbb2.tar.xz linux-01ab10393c510342ec4ce85df11ccfa3df06bbb2.zip |
sh: Fix up DSP context save/restore.
There were a number of issues with the DSP context save/restore code,
mostly left-over relics from when it was introduced on SH3-DSP with
little follow-up testing, resulting in things like task_pt_dspregs()
referencing incorrect state on the stack.
This follows the MIPS convention of tracking the DSP state in the
thread_struct and handling the state save/restore in switch_to() and
finish_arch_switch() respectively. The regset interface is also updated,
which allows us to finally be rid of task_pt_dspregs() and the special
cased task_pt_regs().
Signed-off-by: Michael Trimarchi <michael@evidence.eu.com>
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh/kernel')
-rw-r--r-- | arch/sh/kernel/cpu/sh3/entry.S | 85 | ||||
-rw-r--r-- | arch/sh/kernel/process_32.c | 14 | ||||
-rw-r--r-- | arch/sh/kernel/ptrace_32.c | 6 | ||||
-rw-r--r-- | arch/sh/kernel/traps_32.c | 2 |
4 files changed, 25 insertions, 82 deletions
diff --git a/arch/sh/kernel/cpu/sh3/entry.S b/arch/sh/kernel/cpu/sh3/entry.S index 55da0ff9848d..3cb531f233f2 100644 --- a/arch/sh/kernel/cpu/sh3/entry.S +++ b/arch/sh/kernel/cpu/sh3/entry.S @@ -254,40 +254,6 @@ restore_all: lds k2, pr ! restore pr ! -#ifdef CONFIG_SH_DSP - mov.l @r15+, k0 ! DSP mode marker - mov.l 5f, k1 - cmp/eq k0, k1 ! Do we have a DSP stack frame? - bf skip_restore - - stc sr, k0 ! Enable CPU DSP mode - or k1, k0 ! (within kernel it may be disabled) - ldc k0, sr - mov r2, k0 ! Backup r2 - - ! Restore DSP registers from stack - mov r15, r2 - movs.l @r2+, a1 - movs.l @r2+, a0g - movs.l @r2+, a1g - movs.l @r2+, m0 - movs.l @r2+, m1 - mov r2, r15 - - lds.l @r15+, a0 - lds.l @r15+, x0 - lds.l @r15+, x1 - lds.l @r15+, y0 - lds.l @r15+, y1 - lds.l @r15+, dsr - ldc.l @r15+, rs - ldc.l @r15+, re - ldc.l @r15+, mod - - mov k0, r2 ! Restore r2 -skip_restore: -#endif - ! ! Calculate new SR value mov k3, k2 ! original SR value mov #0xf0, k1 @@ -358,7 +324,7 @@ general_exception: add k0, k4 0: ! Setup stack and save DSP context (k0 contains original r15 on return) - bsr prepare_stack_save_dsp + bsr prepare_stack nop ! Save registers / Switch to bank 0 @@ -374,15 +340,14 @@ general_exception: 1: .long EXPEVT #endif -! prepare_stack_save_dsp() +! prepare_stack() ! - roll back gRB ! - switch to kernel stack -! - save DSP ! k0 returns original sp (after roll back) ! k1 trashed ! k2 trashed -prepare_stack_save_dsp: +prepare_stack: #ifdef CONFIG_GUSA ! Check for roll back gRB (User and Kernel) mov r15, k0 @@ -416,47 +381,9 @@ prepare_stack_save_dsp: mov k1, r15 ! change to kernel stack ! 1: -#ifdef CONFIG_SH_DSP - ! Save DSP context if needed - stc sr, k1 - mov #0x10, k2 - shll8 k2 ! DSP=1 (0x00001000) - tst k2, k1 ! Check if in DSP mode (passed in k2) - bt/s skip_save - mov #0, k1 ! Set marker for no stack frame - - mov k2, k1 ! Save has-frame marker - - ! Save DSP registers on stack - stc.l mod, @-r15 - stc.l re, @-r15 - stc.l rs, @-r15 - sts.l dsr, @-r15 - sts.l y1, @-r15 - sts.l y0, @-r15 - sts.l x1, @-r15 - sts.l x0, @-r15 - sts.l a0, @-r15 - - ! GAS is broken, does not generate correct "movs.l Ds,@-As" instr. - - ! FIXME: Make sure that this is still the case with newer toolchains, - ! as we're not at all interested in supporting ancient toolchains at - ! this point. -- PFM. - - mov r15, k2 - .word 0xf653 ! movs.l a1, @-r2 - .word 0xf6f3 ! movs.l a0g, @-r2 - .word 0xf6d3 ! movs.l a1g, @-r2 - .word 0xf6c3 ! movs.l m0, @-r2 - .word 0xf6e3 ! movs.l m1, @-r2 - mov k2, r15 - -skip_save: - mov.l k1, @-r15 ! Push DSP mode marker onto stack -#endif rts nop + ! ! 0x400: Instruction and Data TLB miss exception vector ! @@ -468,7 +395,7 @@ handle_exception: mova exception_data, k0 ! Setup stack and save DSP context (k0 contains original r15 on return) - bsr prepare_stack_save_dsp + bsr prepare_stack PREF(k0) ! Save registers / Switch to bank 0 @@ -572,7 +499,7 @@ ENTRY(handle_interrupt) mova exception_data, k0 ! Setup stack and save DSP context (k0 contains original r15 on return) - bsr prepare_stack_save_dsp + bsr prepare_stack PREF(k0) ! Save registers / Switch to bank 0 diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c index ddafbbbab2ab..0747fabd73a7 100644 --- a/arch/sh/kernel/process_32.c +++ b/arch/sh/kernel/process_32.c @@ -176,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; diff --git a/arch/sh/kernel/ptrace_32.c b/arch/sh/kernel/ptrace_32.c index 29ca09d24ef8..f7b22dd83b0c 100644 --- a/arch/sh/kernel/ptrace_32.c +++ b/arch/sh/kernel/ptrace_32.c @@ -200,7 +200,8 @@ static int dspregs_get(struct task_struct *target, unsigned int pos, unsigned int count, void *kbuf, void __user *ubuf) { - const struct pt_dspregs *regs = task_pt_dspregs(target); + const struct pt_dspregs *regs = + (struct pt_dspregs *)&target->thread.dsp_status.dsp_regs; int ret; ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, regs, @@ -217,7 +218,8 @@ static int dspregs_set(struct task_struct *target, unsigned int pos, unsigned int count, const void *kbuf, const void __user *ubuf) { - struct pt_dspregs *regs = task_pt_dspregs(target); + struct pt_dspregs *regs = + (struct pt_dspregs *)&target->thread.dsp_status.dsp_regs; int ret; ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, regs, diff --git a/arch/sh/kernel/traps_32.c b/arch/sh/kernel/traps_32.c index 60dcf87ed019..30ca9c51e52d 100644 --- a/arch/sh/kernel/traps_32.c +++ b/arch/sh/kernel/traps_32.c @@ -664,6 +664,8 @@ asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5, if (is_dsp_inst(regs)) { /* Enable DSP mode, and restart instruction. */ regs->sr |= SR_DSP; + /* Save DSP mode */ + tsk->thread.dsp_status.status |= SR_DSP; return; } #endif |