aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh
diff options
context:
space:
mode:
authorMichael Trimarchi <trimarchi@gandalf.sssup.it>2009-04-03 13:32:33 -0400
committerPaul Mundt <lethal@linux-sh.org>2009-04-04 11:48:11 -0400
commit01ab10393c510342ec4ce85df11ccfa3df06bbb2 (patch)
treeebf0493fa7b53941f830f8b300037f834eb85e59 /arch/sh
parenta27873cd234b4248dda342721d6262943e5fa235 (diff)
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')
-rw-r--r--arch/sh/include/asm/processor_32.h13
-rw-r--r--arch/sh/include/asm/ptrace.h8
-rw-r--r--arch/sh/include/asm/system_32.h170
-rw-r--r--arch/sh/kernel/cpu/sh3/entry.S85
-rw-r--r--arch/sh/kernel/process_32.c14
-rw-r--r--arch/sh/kernel/ptrace_32.c6
-rw-r--r--arch/sh/kernel/traps_32.c2
7 files changed, 161 insertions, 137 deletions
diff --git a/arch/sh/include/asm/processor_32.h b/arch/sh/include/asm/processor_32.h
index efdd78a53b11..9a8714945dc9 100644
--- a/arch/sh/include/asm/processor_32.h
+++ b/arch/sh/include/asm/processor_32.h
@@ -58,6 +58,14 @@ asmlinkage void __init sh_cpu_init(void);
58#define SR_FD 0x00008000 58#define SR_FD 0x00008000
59 59
60/* 60/*
61 * DSP structure and data
62 */
63struct sh_dsp_struct {
64 unsigned long dsp_regs[14];
65 long status;
66};
67
68/*
61 * FPU structure and data 69 * FPU structure and data
62 */ 70 */
63 71
@@ -96,6 +104,11 @@ struct thread_struct {
96 104
97 /* floating point info */ 105 /* floating point info */
98 union sh_fpu_union fpu; 106 union sh_fpu_union fpu;
107
108#ifdef CONFIG_SH_DSP
109 /* Dsp status information */
110 struct sh_dsp_struct dsp_status;
111#endif
99}; 112};
100 113
101/* Count of active tasks with UBC settings */ 114/* Count of active tasks with UBC settings */
diff --git a/arch/sh/include/asm/ptrace.h b/arch/sh/include/asm/ptrace.h
index 81c6568fdb3e..d3f6caa936b0 100644
--- a/arch/sh/include/asm/ptrace.h
+++ b/arch/sh/include/asm/ptrace.h
@@ -119,16 +119,8 @@ struct task_struct;
119extern void user_enable_single_step(struct task_struct *); 119extern void user_enable_single_step(struct task_struct *);
120extern void user_disable_single_step(struct task_struct *); 120extern void user_disable_single_step(struct task_struct *);
121 121
122#ifdef CONFIG_SH_DSP
123#define task_pt_regs(task) \
124 ((struct pt_regs *) (task_stack_page(task) + THREAD_SIZE \
125 - sizeof(struct pt_dspregs)) - 1)
126#define task_pt_dspregs(task) \
127 ((struct pt_dspregs *) (task_stack_page(task) + THREAD_SIZE) - 1)
128#else
129#define task_pt_regs(task) \ 122#define task_pt_regs(task) \
130 ((struct pt_regs *) (task_stack_page(task) + THREAD_SIZE) - 1) 123 ((struct pt_regs *) (task_stack_page(task) + THREAD_SIZE) - 1)
131#endif
132 124
133static inline unsigned long profile_pc(struct pt_regs *regs) 125static inline unsigned long profile_pc(struct pt_regs *regs)
134{ 126{
diff --git a/arch/sh/include/asm/system_32.h b/arch/sh/include/asm/system_32.h
index a726d5d07277..240b31e1142c 100644
--- a/arch/sh/include/asm/system_32.h
+++ b/arch/sh/include/asm/system_32.h
@@ -3,59 +3,135 @@
3 3
4#include <linux/types.h> 4#include <linux/types.h>
5 5
6#ifdef CONFIG_SH_DSP
7
8#define is_dsp_enabled(tsk) \
9 (!!(tsk->thread.dsp_status.status & SR_DSP))
10
11#define __restore_dsp(tsk) \
12do { \
13 register u32 *__ts2 __asm__ ("r2") = \
14 (u32 *)&tsk->thread.dsp_status; \
15 __asm__ __volatile__ ( \
16 ".balign 4\n\t" \
17 "movs.l @r2+, a1\n\t" \
18 "movs.l @r2+, a0g\n\t" \
19 "movs.l @r2+, a1g\n\t" \
20 "movs.l @r2+, m0\n\t" \
21 "movs.l @r2+, m1\n\t" \
22 "movs.l @r2+, a0\n\t" \
23 "movs.l @r2+, x0\n\t" \
24 "movs.l @r2+, x1\n\t" \
25 "movs.l @r2+, y0\n\t" \
26 "movs.l @r2+, y1\n\t" \
27 "lds.l @r2+, dsr\n\t" \
28 "ldc.l @r2+, rs\n\t" \
29 "ldc.l @r2+, re\n\t" \
30 "ldc.l @r2+, mod\n\t" \
31 : : "r" (__ts2)); \
32} while (0)
33
34
35#define __save_dsp(tsk) \
36do { \
37 register u32 *__ts2 __asm__ ("r2") = \
38 (u32 *)&tsk->thread.dsp_status + 14; \
39 \
40 __asm__ __volatile__ ( \
41 ".balign 4\n\t" \
42 "stc.l mod, @-r2\n\t" \
43 "stc.l re, @-r2\n\t" \
44 "stc.l rs, @-r2\n\t" \
45 "sts.l dsr, @-r2\n\t" \
46 "sts.l y1, @-r2\n\t" \
47 "sts.l y0, @-r2\n\t" \
48 "sts.l x1, @-r2\n\t" \
49 "sts.l x0, @-r2\n\t" \
50 "sts.l a0, @-r2\n\t" \
51 ".word 0xf653 ! movs.l a1, @-r2\n\t" \
52 ".word 0xf6f3 ! movs.l a0g, @-r2\n\t" \
53 ".word 0xf6d3 ! movs.l a1g, @-r2\n\t" \
54 ".word 0xf6c3 ! movs.l m0, @-r2\n\t" \
55 ".word 0xf6e3 ! movs.l m1, @-r2\n\t" \
56 : : "r" (__ts2)); \
57} while (0)
58
59#else
60
61#define is_dsp_enabled(tsk) (0)
62#define __save_dsp(tsk) do { } while (0)
63#define __restore_dsp(tsk) do { } while (0)
64#endif
65
6struct task_struct *__switch_to(struct task_struct *prev, 66struct task_struct *__switch_to(struct task_struct *prev,
7 struct task_struct *next); 67 struct task_struct *next);
8 68
9/* 69/*
10 * switch_to() should switch tasks to task nr n, first 70 * switch_to() should switch tasks to task nr n, first
11 */ 71 */
12#define switch_to(prev, next, last) \ 72#define switch_to(prev, next, last) \
13do { \ 73do { \
14 register u32 *__ts1 __asm__ ("r1") = (u32 *)&prev->thread.sp; \ 74 register u32 *__ts1 __asm__ ("r1"); \
15 register u32 *__ts2 __asm__ ("r2") = (u32 *)&prev->thread.pc; \ 75 register u32 *__ts2 __asm__ ("r2"); \
16 register u32 *__ts4 __asm__ ("r4") = (u32 *)prev; \ 76 register u32 *__ts4 __asm__ ("r4"); \
17 register u32 *__ts5 __asm__ ("r5") = (u32 *)next; \ 77 register u32 *__ts5 __asm__ ("r5"); \
18 register u32 *__ts6 __asm__ ("r6") = (u32 *)&next->thread.sp; \ 78 register u32 *__ts6 __asm__ ("r6"); \
19 register u32 __ts7 __asm__ ("r7") = next->thread.pc; \ 79 register u32 __ts7 __asm__ ("r7"); \
20 struct task_struct *__last; \ 80 struct task_struct *__last; \
21 \ 81 \
22 __asm__ __volatile__ ( \ 82 if (is_dsp_enabled(prev)) \
23 ".balign 4\n\t" \ 83 __save_dsp(prev); \
24 "stc.l gbr, @-r15\n\t" \ 84 \
25 "sts.l pr, @-r15\n\t" \ 85 __ts1 = (u32 *)&prev->thread.sp; \
26 "mov.l r8, @-r15\n\t" \ 86 __ts2 = (u32 *)&prev->thread.pc; \
27 "mov.l r9, @-r15\n\t" \ 87 __ts4 = (u32 *)prev; \
28 "mov.l r10, @-r15\n\t" \ 88 __ts5 = (u32 *)next; \
29 "mov.l r11, @-r15\n\t" \ 89 __ts6 = (u32 *)&next->thread.sp; \
30 "mov.l r12, @-r15\n\t" \ 90 __ts7 = next->thread.pc; \
31 "mov.l r13, @-r15\n\t" \ 91 \
32 "mov.l r14, @-r15\n\t" \ 92 __asm__ __volatile__ ( \
33 "mov.l r15, @r1\t! save SP\n\t" \ 93 ".balign 4\n\t" \
34 "mov.l @r6, r15\t! change to new stack\n\t" \ 94 "stc.l gbr, @-r15\n\t" \
35 "mova 1f, %0\n\t" \ 95 "sts.l pr, @-r15\n\t" \
36 "mov.l %0, @r2\t! save PC\n\t" \ 96 "mov.l r8, @-r15\n\t" \
37 "mov.l 2f, %0\n\t" \ 97 "mov.l r9, @-r15\n\t" \
38 "jmp @%0\t! call __switch_to\n\t" \ 98 "mov.l r10, @-r15\n\t" \
39 " lds r7, pr\t! with return to new PC\n\t" \ 99 "mov.l r11, @-r15\n\t" \
40 ".balign 4\n" \ 100 "mov.l r12, @-r15\n\t" \
41 "2:\n\t" \ 101 "mov.l r13, @-r15\n\t" \
42 ".long __switch_to\n" \ 102 "mov.l r14, @-r15\n\t" \
43 "1:\n\t" \ 103 "mov.l r15, @r1\t! save SP\n\t" \
44 "mov.l @r15+, r14\n\t" \ 104 "mov.l @r6, r15\t! change to new stack\n\t" \
45 "mov.l @r15+, r13\n\t" \ 105 "mova 1f, %0\n\t" \
46 "mov.l @r15+, r12\n\t" \ 106 "mov.l %0, @r2\t! save PC\n\t" \
47 "mov.l @r15+, r11\n\t" \ 107 "mov.l 2f, %0\n\t" \
48 "mov.l @r15+, r10\n\t" \ 108 "jmp @%0\t! call __switch_to\n\t" \
49 "mov.l @r15+, r9\n\t" \ 109 " lds r7, pr\t! with return to new PC\n\t" \
50 "mov.l @r15+, r8\n\t" \ 110 ".balign 4\n" \
51 "lds.l @r15+, pr\n\t" \ 111 "2:\n\t" \
52 "ldc.l @r15+, gbr\n\t" \ 112 ".long __switch_to\n" \
53 : "=z" (__last) \ 113 "1:\n\t" \
54 : "r" (__ts1), "r" (__ts2), "r" (__ts4), \ 114 "mov.l @r15+, r14\n\t" \
55 "r" (__ts5), "r" (__ts6), "r" (__ts7) \ 115 "mov.l @r15+, r13\n\t" \
56 : "r3", "t"); \ 116 "mov.l @r15+, r12\n\t" \
57 \ 117 "mov.l @r15+, r11\n\t" \
58 last = __last; \ 118 "mov.l @r15+, r10\n\t" \
119 "mov.l @r15+, r9\n\t" \
120 "mov.l @r15+, r8\n\t" \
121 "lds.l @r15+, pr\n\t" \
122 "ldc.l @r15+, gbr\n\t" \
123 : "=z" (__last) \
124 : "r" (__ts1), "r" (__ts2), "r" (__ts4), \
125 "r" (__ts5), "r" (__ts6), "r" (__ts7) \
126 : "r3", "t"); \
127 \
128 last = __last; \
129} while (0)
130
131#define finish_arch_switch(prev) \
132do { \
133 if (is_dsp_enabled(prev)) \
134 __restore_dsp(prev); \
59} while (0) 135} while (0)
60 136
61#define __uses_jump_to_uncached \ 137#define __uses_jump_to_uncached \
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:
254 254
255 lds k2, pr ! restore pr 255 lds k2, pr ! restore pr
256 ! 256 !
257#ifdef CONFIG_SH_DSP
258 mov.l @r15+, k0 ! DSP mode marker
259 mov.l 5f, k1
260 cmp/eq k0, k1 ! Do we have a DSP stack frame?
261 bf skip_restore
262
263 stc sr, k0 ! Enable CPU DSP mode
264 or k1, k0 ! (within kernel it may be disabled)
265 ldc k0, sr
266 mov r2, k0 ! Backup r2
267
268 ! Restore DSP registers from stack
269 mov r15, r2
270 movs.l @r2+, a1
271 movs.l @r2+, a0g
272 movs.l @r2+, a1g
273 movs.l @r2+, m0
274 movs.l @r2+, m1
275 mov r2, r15
276
277 lds.l @r15+, a0
278 lds.l @r15+, x0
279 lds.l @r15+, x1
280 lds.l @r15+, y0
281 lds.l @r15+, y1
282 lds.l @r15+, dsr
283 ldc.l @r15+, rs
284 ldc.l @r15+, re
285 ldc.l @r15+, mod
286
287 mov k0, r2 ! Restore r2
288skip_restore:
289#endif
290 !
291 ! Calculate new SR value 257 ! Calculate new SR value
292 mov k3, k2 ! original SR value 258 mov k3, k2 ! original SR value
293 mov #0xf0, k1 259 mov #0xf0, k1
@@ -358,7 +324,7 @@ general_exception:
358 add k0, k4 324 add k0, k4
3590: 3250:
360 ! Setup stack and save DSP context (k0 contains original r15 on return) 326 ! Setup stack and save DSP context (k0 contains original r15 on return)
361 bsr prepare_stack_save_dsp 327 bsr prepare_stack
362 nop 328 nop
363 329
364 ! Save registers / Switch to bank 0 330 ! Save registers / Switch to bank 0
@@ -374,15 +340,14 @@ general_exception:
3741: .long EXPEVT 3401: .long EXPEVT
375#endif 341#endif
376 342
377! prepare_stack_save_dsp() 343! prepare_stack()
378! - roll back gRB 344! - roll back gRB
379! - switch to kernel stack 345! - switch to kernel stack
380! - save DSP
381! k0 returns original sp (after roll back) 346! k0 returns original sp (after roll back)
382! k1 trashed 347! k1 trashed
383! k2 trashed 348! k2 trashed
384 349
385prepare_stack_save_dsp: 350prepare_stack:
386#ifdef CONFIG_GUSA 351#ifdef CONFIG_GUSA
387 ! Check for roll back gRB (User and Kernel) 352 ! Check for roll back gRB (User and Kernel)
388 mov r15, k0 353 mov r15, k0
@@ -416,47 +381,9 @@ prepare_stack_save_dsp:
416 mov k1, r15 ! change to kernel stack 381 mov k1, r15 ! change to kernel stack
417 ! 382 !
4181: 3831:
419#ifdef CONFIG_SH_DSP
420 ! Save DSP context if needed
421 stc sr, k1
422 mov #0x10, k2
423 shll8 k2 ! DSP=1 (0x00001000)
424 tst k2, k1 ! Check if in DSP mode (passed in k2)
425 bt/s skip_save
426 mov #0, k1 ! Set marker for no stack frame
427
428 mov k2, k1 ! Save has-frame marker
429
430 ! Save DSP registers on stack
431 stc.l mod, @-r15
432 stc.l re, @-r15
433 stc.l rs, @-r15
434 sts.l dsr, @-r15
435 sts.l y1, @-r15
436 sts.l y0, @-r15
437 sts.l x1, @-r15
438 sts.l x0, @-r15
439 sts.l a0, @-r15
440
441 ! GAS is broken, does not generate correct "movs.l Ds,@-As" instr.
442
443 ! FIXME: Make sure that this is still the case with newer toolchains,
444 ! as we're not at all interested in supporting ancient toolchains at
445 ! this point. -- PFM.
446
447 mov r15, k2
448 .word 0xf653 ! movs.l a1, @-r2
449 .word 0xf6f3 ! movs.l a0g, @-r2
450 .word 0xf6d3 ! movs.l a1g, @-r2
451 .word 0xf6c3 ! movs.l m0, @-r2
452 .word 0xf6e3 ! movs.l m1, @-r2
453 mov k2, r15
454
455skip_save:
456 mov.l k1, @-r15 ! Push DSP mode marker onto stack
457#endif
458 rts 384 rts
459 nop 385 nop
386
460! 387!
461! 0x400: Instruction and Data TLB miss exception vector 388! 0x400: Instruction and Data TLB miss exception vector
462! 389!
@@ -468,7 +395,7 @@ handle_exception:
468 mova exception_data, k0 395 mova exception_data, k0
469 396
470 ! Setup stack and save DSP context (k0 contains original r15 on return) 397 ! Setup stack and save DSP context (k0 contains original r15 on return)
471 bsr prepare_stack_save_dsp 398 bsr prepare_stack
472 PREF(k0) 399 PREF(k0)
473 400
474 ! Save registers / Switch to bank 0 401 ! Save registers / Switch to bank 0
@@ -572,7 +499,7 @@ ENTRY(handle_interrupt)
572 mova exception_data, k0 499 mova exception_data, k0
573 500
574 ! Setup stack and save DSP context (k0 contains original r15 on return) 501 ! Setup stack and save DSP context (k0 contains original r15 on return)
575 bsr prepare_stack_save_dsp 502 bsr prepare_stack
576 PREF(k0) 503 PREF(k0)
577 504
578 ! Save registers / Switch to bank 0 505 ! 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,
176{ 176{
177 struct thread_info *ti = task_thread_info(p); 177 struct thread_info *ti = task_thread_info(p);
178 struct pt_regs *childregs; 178 struct pt_regs *childregs;
179#if defined(CONFIG_SH_FPU) 179#if defined(CONFIG_SH_FPU) || defined(CONFIG_SH_DSP)
180 struct task_struct *tsk = current; 180 struct task_struct *tsk = current;
181#endif
181 182
183#if defined(CONFIG_SH_FPU)
182 unlazy_fpu(tsk, regs); 184 unlazy_fpu(tsk, regs);
183 p->thread.fpu = tsk->thread.fpu; 185 p->thread.fpu = tsk->thread.fpu;
184 copy_to_stopped_child_used_math(p); 186 copy_to_stopped_child_used_math(p);
185#endif 187#endif
186 188
189#if defined(CONFIG_SH_DSP)
190 if (is_dsp_enabled(tsk)) {
191 /* We can use the __save_dsp or just copy the struct:
192 * __save_dsp(p);
193 * p->thread.dsp_status.status |= SR_DSP
194 */
195 p->thread.dsp_status = tsk->thread.dsp_status;
196 }
197#endif
198
187 childregs = task_pt_regs(p); 199 childregs = task_pt_regs(p);
188 *childregs = *regs; 200 *childregs = *regs;
189 201
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,
200 unsigned int pos, unsigned int count, 200 unsigned int pos, unsigned int count,
201 void *kbuf, void __user *ubuf) 201 void *kbuf, void __user *ubuf)
202{ 202{
203 const struct pt_dspregs *regs = task_pt_dspregs(target); 203 const struct pt_dspregs *regs =
204 (struct pt_dspregs *)&target->thread.dsp_status.dsp_regs;
204 int ret; 205 int ret;
205 206
206 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, regs, 207 ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, regs,
@@ -217,7 +218,8 @@ static int dspregs_set(struct task_struct *target,
217 unsigned int pos, unsigned int count, 218 unsigned int pos, unsigned int count,
218 const void *kbuf, const void __user *ubuf) 219 const void *kbuf, const void __user *ubuf)
219{ 220{
220 struct pt_dspregs *regs = task_pt_dspregs(target); 221 struct pt_dspregs *regs =
222 (struct pt_dspregs *)&target->thread.dsp_status.dsp_regs;
221 int ret; 223 int ret;
222 224
223 ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, regs, 225 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,
664 if (is_dsp_inst(regs)) { 664 if (is_dsp_inst(regs)) {
665 /* Enable DSP mode, and restart instruction. */ 665 /* Enable DSP mode, and restart instruction. */
666 regs->sr |= SR_DSP; 666 regs->sr |= SR_DSP;
667 /* Save DSP mode */
668 tsk->thread.dsp_status.status |= SR_DSP;
667 return; 669 return;
668 } 670 }
669#endif 671#endif