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>
diff --git a/arch/sh/kernel/cpu/sh3/entry.S b/arch/sh/kernel/cpu/sh3/entry.S
index 55da0ff..3cb531f 100644
--- a/arch/sh/kernel/cpu/sh3/entry.S
+++ b/arch/sh/kernel/cpu/sh3/entry.S
@@ -254,40 +254,6 @@
 
 	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 @@
 	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 @@
 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 @@
 	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 @@
 	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 @@
 	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 ddafbbb..0747fab 100644
--- a/arch/sh/kernel/process_32.c
+++ b/arch/sh/kernel/process_32.c
@@ -176,14 +176,26 @@
 {
 	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 29ca09d..f7b22dd 100644
--- a/arch/sh/kernel/ptrace_32.c
+++ b/arch/sh/kernel/ptrace_32.c
@@ -200,7 +200,8 @@
 		       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 @@
 		       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 60dcf87..30ca9c5 100644
--- a/arch/sh/kernel/traps_32.c
+++ b/arch/sh/kernel/traps_32.c
@@ -664,6 +664,8 @@
 	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