aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/sh/include/asm/fpu.h26
-rw-r--r--arch/sh/include/asm/processor_32.h3
-rw-r--r--arch/sh/include/asm/thread_info.h4
-rw-r--r--arch/sh/kernel/cpu/init.c4
-rw-r--r--arch/sh/kernel/cpu/sh2a/fpu.c11
-rw-r--r--arch/sh/kernel/cpu/sh4/fpu.c12
-rw-r--r--arch/sh/kernel/process_32.c24
-rw-r--r--arch/sh/math-emu/math.c6
8 files changed, 48 insertions, 42 deletions
diff --git a/arch/sh/include/asm/fpu.h b/arch/sh/include/asm/fpu.h
index bfd78e19de1b..d7709c06fac4 100644
--- a/arch/sh/include/asm/fpu.h
+++ b/arch/sh/include/asm/fpu.h
@@ -18,17 +18,14 @@ static inline void grab_fpu(struct pt_regs *regs)
18 18
19struct task_struct; 19struct task_struct;
20 20
21extern void save_fpu(struct task_struct *__tsk, struct pt_regs *regs); 21extern void save_fpu(struct task_struct *__tsk);
22void fpu_state_restore(struct pt_regs *regs); 22void fpu_state_restore(struct pt_regs *regs);
23#else 23#else
24 24
25#define save_fpu(tsk) do { } while (0)
25#define release_fpu(regs) do { } while (0) 26#define release_fpu(regs) do { } while (0)
26#define grab_fpu(regs) do { } while (0) 27#define grab_fpu(regs) do { } while (0)
27 28
28static inline void save_fpu(struct task_struct *tsk, struct pt_regs *regs)
29{
30 clear_tsk_thread_flag(tsk, TIF_USEDFPU);
31}
32#endif 29#endif
33 30
34struct user_regset; 31struct user_regset;
@@ -40,21 +37,28 @@ extern int fpregs_get(struct task_struct *target,
40 unsigned int pos, unsigned int count, 37 unsigned int pos, unsigned int count,
41 void *kbuf, void __user *ubuf); 38 void *kbuf, void __user *ubuf);
42 39
40static inline void __unlazy_fpu(struct task_struct *tsk, struct pt_regs *regs)
41{
42 if (task_thread_info(tsk)->status & TS_USEDFPU) {
43 task_thread_info(tsk)->status &= ~TS_USEDFPU;
44 save_fpu(tsk);
45 release_fpu(regs);
46 } else
47 tsk->fpu_counter = 0;
48}
49
43static inline void unlazy_fpu(struct task_struct *tsk, struct pt_regs *regs) 50static inline void unlazy_fpu(struct task_struct *tsk, struct pt_regs *regs)
44{ 51{
45 preempt_disable(); 52 preempt_disable();
46 if (test_tsk_thread_flag(tsk, TIF_USEDFPU)) 53 __unlazy_fpu(tsk, regs);
47 save_fpu(tsk, regs);
48 else
49 tsk->fpu_counter = 0;
50 preempt_enable(); 54 preempt_enable();
51} 55}
52 56
53static inline void clear_fpu(struct task_struct *tsk, struct pt_regs *regs) 57static inline void clear_fpu(struct task_struct *tsk, struct pt_regs *regs)
54{ 58{
55 preempt_disable(); 59 preempt_disable();
56 if (test_tsk_thread_flag(tsk, TIF_USEDFPU)) { 60 if (task_thread_info(tsk)->status & TS_USEDFPU) {
57 clear_tsk_thread_flag(tsk, TIF_USEDFPU); 61 task_thread_info(tsk)->status &= ~TS_USEDFPU;
58 release_fpu(regs); 62 release_fpu(regs);
59 } 63 }
60 preempt_enable(); 64 preempt_enable();
diff --git a/arch/sh/include/asm/processor_32.h b/arch/sh/include/asm/processor_32.h
index 9a8714945dc9..1f3d6fab660c 100644
--- a/arch/sh/include/asm/processor_32.h
+++ b/arch/sh/include/asm/processor_32.h
@@ -56,6 +56,7 @@ asmlinkage void __init sh_cpu_init(void);
56#define SR_DSP 0x00001000 56#define SR_DSP 0x00001000
57#define SR_IMASK 0x000000f0 57#define SR_IMASK 0x000000f0
58#define SR_FD 0x00008000 58#define SR_FD 0x00008000
59#define SR_MD 0x40000000
59 60
60/* 61/*
61 * DSP structure and data 62 * DSP structure and data
@@ -136,7 +137,7 @@ struct mm_struct;
136extern void release_thread(struct task_struct *); 137extern void release_thread(struct task_struct *);
137 138
138/* Prepare to copy thread state - unlazy all lazy status */ 139/* Prepare to copy thread state - unlazy all lazy status */
139#define prepare_to_copy(tsk) do { } while (0) 140void prepare_to_copy(struct task_struct *tsk);
140 141
141/* 142/*
142 * create a kernel thread without removing it from tasklists 143 * create a kernel thread without removing it from tasklists
diff --git a/arch/sh/include/asm/thread_info.h b/arch/sh/include/asm/thread_info.h
index 23eeed89467a..1f3d927e2265 100644
--- a/arch/sh/include/asm/thread_info.h
+++ b/arch/sh/include/asm/thread_info.h
@@ -51,6 +51,7 @@ struct thread_info {
51 .task = &tsk, \ 51 .task = &tsk, \
52 .exec_domain = &default_exec_domain, \ 52 .exec_domain = &default_exec_domain, \
53 .flags = 0, \ 53 .flags = 0, \
54 .status = 0, \
54 .cpu = 0, \ 55 .cpu = 0, \
55 .preempt_count = INIT_PREEMPT_COUNT, \ 56 .preempt_count = INIT_PREEMPT_COUNT, \
56 .addr_limit = KERNEL_DS, \ 57 .addr_limit = KERNEL_DS, \
@@ -117,7 +118,6 @@ extern void free_thread_info(struct thread_info *ti);
117#define TIF_SECCOMP 6 /* secure computing */ 118#define TIF_SECCOMP 6 /* secure computing */
118#define TIF_NOTIFY_RESUME 7 /* callback before returning to user */ 119#define TIF_NOTIFY_RESUME 7 /* callback before returning to user */
119#define TIF_SYSCALL_TRACEPOINT 8 /* for ftrace syscall instrumentation */ 120#define TIF_SYSCALL_TRACEPOINT 8 /* for ftrace syscall instrumentation */
120#define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */
121#define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling TIF_NEED_RESCHED */ 121#define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling TIF_NEED_RESCHED */
122#define TIF_MEMDIE 18 122#define TIF_MEMDIE 18
123#define TIF_FREEZE 19 /* Freezing for suspend */ 123#define TIF_FREEZE 19 /* Freezing for suspend */
@@ -130,7 +130,6 @@ extern void free_thread_info(struct thread_info *ti);
130#define _TIF_SECCOMP (1 << TIF_SECCOMP) 130#define _TIF_SECCOMP (1 << TIF_SECCOMP)
131#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) 131#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
132#define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT) 132#define _TIF_SYSCALL_TRACEPOINT (1 << TIF_SYSCALL_TRACEPOINT)
133#define _TIF_USEDFPU (1 << TIF_USEDFPU)
134#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) 133#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
135#define _TIF_FREEZE (1 << TIF_FREEZE) 134#define _TIF_FREEZE (1 << TIF_FREEZE)
136 135
@@ -163,6 +162,7 @@ extern void free_thread_info(struct thread_info *ti);
163 * have to worry about atomic accesses. 162 * have to worry about atomic accesses.
164 */ 163 */
165#define TS_RESTORE_SIGMASK 0x0001 /* restore signal mask in do_signal() */ 164#define TS_RESTORE_SIGMASK 0x0001 /* restore signal mask in do_signal() */
165#define TS_USEDFPU 0x0002 /* FPU used by this task this quantum */
166 166
167#ifndef __ASSEMBLY__ 167#ifndef __ASSEMBLY__
168#define HAVE_SET_RESTORE_SIGMASK 1 168#define HAVE_SET_RESTORE_SIGMASK 1
diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c
index 580d58b94cc5..ad9dfff9427c 100644
--- a/arch/sh/kernel/cpu/init.c
+++ b/arch/sh/kernel/cpu/init.c
@@ -311,12 +311,12 @@ asmlinkage void __init sh_cpu_init(void)
311 if (fpu_disabled) { 311 if (fpu_disabled) {
312 printk("FPU Disabled\n"); 312 printk("FPU Disabled\n");
313 current_cpu_data.flags &= ~CPU_HAS_FPU; 313 current_cpu_data.flags &= ~CPU_HAS_FPU;
314 disable_fpu();
315 } 314 }
316 315
317 /* FPU initialization */ 316 /* FPU initialization */
317 disable_fpu();
318 if ((current_cpu_data.flags & CPU_HAS_FPU)) { 318 if ((current_cpu_data.flags & CPU_HAS_FPU)) {
319 clear_thread_flag(TIF_USEDFPU); 319 current_thread_info()->status &= ~TS_USEDFPU;
320 clear_used_math(); 320 clear_used_math();
321 } 321 }
322 322
diff --git a/arch/sh/kernel/cpu/sh2a/fpu.c b/arch/sh/kernel/cpu/sh2a/fpu.c
index 6df2fb98eb30..13817ee49d52 100644
--- a/arch/sh/kernel/cpu/sh2a/fpu.c
+++ b/arch/sh/kernel/cpu/sh2a/fpu.c
@@ -25,14 +25,12 @@
25 25
26/* 26/*
27 * Save FPU registers onto task structure. 27 * Save FPU registers onto task structure.
28 * Assume called with FPU enabled (SR.FD=0).
29 */ 28 */
30void 29void
31save_fpu(struct task_struct *tsk, struct pt_regs *regs) 30save_fpu(struct task_struct *tsk)
32{ 31{
33 unsigned long dummy; 32 unsigned long dummy;
34 33
35 clear_tsk_thread_flag(tsk, TIF_USEDFPU);
36 enable_fpu(); 34 enable_fpu();
37 asm volatile("sts.l fpul, @-%0\n\t" 35 asm volatile("sts.l fpul, @-%0\n\t"
38 "sts.l fpscr, @-%0\n\t" 36 "sts.l fpscr, @-%0\n\t"
@@ -60,7 +58,6 @@ save_fpu(struct task_struct *tsk, struct pt_regs *regs)
60 : "memory"); 58 : "memory");
61 59
62 disable_fpu(); 60 disable_fpu();
63 release_fpu(regs);
64} 61}
65 62
66static void 63static void
@@ -598,13 +595,13 @@ BUILD_TRAP_HANDLER(fpu_error)
598 struct task_struct *tsk = current; 595 struct task_struct *tsk = current;
599 TRAP_HANDLER_DECL; 596 TRAP_HANDLER_DECL;
600 597
601 save_fpu(tsk, regs); 598 __unlazy_fpu(tsk, regs);
602 if (ieee_fpe_handler(regs)) { 599 if (ieee_fpe_handler(regs)) {
603 tsk->thread.fpu.hard.fpscr &= 600 tsk->thread.fpu.hard.fpscr &=
604 ~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK); 601 ~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK);
605 grab_fpu(regs); 602 grab_fpu(regs);
606 restore_fpu(tsk); 603 restore_fpu(tsk);
607 set_tsk_thread_flag(tsk, TIF_USEDFPU); 604 task_thread_info(tsk)->status |= TS_USEDFPU;
608 return; 605 return;
609 } 606 }
610 607
@@ -630,5 +627,5 @@ BUILD_TRAP_HANDLER(fpu_state_restore)
630 fpu_init(); 627 fpu_init();
631 set_used_math(); 628 set_used_math();
632 } 629 }
633 set_tsk_thread_flag(tsk, TIF_USEDFPU); 630 task_thread_info(tsk)->status |= TS_USEDFPU;
634} 631}
diff --git a/arch/sh/kernel/cpu/sh4/fpu.c b/arch/sh/kernel/cpu/sh4/fpu.c
index d79226fa59d1..e97857aec8a0 100644
--- a/arch/sh/kernel/cpu/sh4/fpu.c
+++ b/arch/sh/kernel/cpu/sh4/fpu.c
@@ -41,13 +41,11 @@ static unsigned int fpu_exception_flags;
41 41
42/* 42/*
43 * Save FPU registers onto task structure. 43 * Save FPU registers onto task structure.
44 * Assume called with FPU enabled (SR.FD=0).
45 */ 44 */
46void save_fpu(struct task_struct *tsk, struct pt_regs *regs) 45void save_fpu(struct task_struct *tsk)
47{ 46{
48 unsigned long dummy; 47 unsigned long dummy;
49 48
50 clear_tsk_thread_flag(tsk, TIF_USEDFPU);
51 enable_fpu(); 49 enable_fpu();
52 asm volatile ("sts.l fpul, @-%0\n\t" 50 asm volatile ("sts.l fpul, @-%0\n\t"
53 "sts.l fpscr, @-%0\n\t" 51 "sts.l fpscr, @-%0\n\t"
@@ -92,7 +90,6 @@ void save_fpu(struct task_struct *tsk, struct pt_regs *regs)
92 :"memory"); 90 :"memory");
93 91
94 disable_fpu(); 92 disable_fpu();
95 release_fpu(regs);
96} 93}
97 94
98static void restore_fpu(struct task_struct *tsk) 95static void restore_fpu(struct task_struct *tsk)
@@ -285,7 +282,6 @@ static int ieee_fpe_handler(struct pt_regs *regs)
285 /* fcnvsd */ 282 /* fcnvsd */
286 struct task_struct *tsk = current; 283 struct task_struct *tsk = current;
287 284
288 save_fpu(tsk, regs);
289 if ((tsk->thread.fpu.hard.fpscr & FPSCR_CAUSE_ERROR)) 285 if ((tsk->thread.fpu.hard.fpscr & FPSCR_CAUSE_ERROR))
290 /* FPU error */ 286 /* FPU error */
291 denormal_to_double(&tsk->thread.fpu.hard, 287 denormal_to_double(&tsk->thread.fpu.hard,
@@ -462,7 +458,7 @@ BUILD_TRAP_HANDLER(fpu_error)
462 struct task_struct *tsk = current; 458 struct task_struct *tsk = current;
463 TRAP_HANDLER_DECL; 459 TRAP_HANDLER_DECL;
464 460
465 save_fpu(tsk, regs); 461 __unlazy_fpu(tsk, regs);
466 fpu_exception_flags = 0; 462 fpu_exception_flags = 0;
467 if (ieee_fpe_handler(regs)) { 463 if (ieee_fpe_handler(regs)) {
468 tsk->thread.fpu.hard.fpscr &= 464 tsk->thread.fpu.hard.fpscr &=
@@ -473,7 +469,7 @@ BUILD_TRAP_HANDLER(fpu_error)
473 tsk->thread.fpu.hard.fpscr |= (fpu_exception_flags >> 10); 469 tsk->thread.fpu.hard.fpscr |= (fpu_exception_flags >> 10);
474 grab_fpu(regs); 470 grab_fpu(regs);
475 restore_fpu(tsk); 471 restore_fpu(tsk);
476 set_tsk_thread_flag(tsk, TIF_USEDFPU); 472 task_thread_info(tsk)->status |= TS_USEDFPU;
477 if ((((tsk->thread.fpu.hard.fpscr & FPSCR_ENABLE_MASK) >> 7) & 473 if ((((tsk->thread.fpu.hard.fpscr & FPSCR_ENABLE_MASK) >> 7) &
478 (fpu_exception_flags >> 2)) == 0) { 474 (fpu_exception_flags >> 2)) == 0) {
479 return; 475 return;
@@ -502,7 +498,7 @@ void fpu_state_restore(struct pt_regs *regs)
502 fpu_init(); 498 fpu_init();
503 set_used_math(); 499 set_used_math();
504 } 500 }
505 set_tsk_thread_flag(tsk, TIF_USEDFPU); 501 task_thread_info(tsk)->status |= TS_USEDFPU;
506 tsk->fpu_counter++; 502 tsk->fpu_counter++;
507} 503}
508 504
diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c
index 7733f5fa6bb5..d721f9297c09 100644
--- a/arch/sh/kernel/process_32.c
+++ b/arch/sh/kernel/process_32.c
@@ -134,7 +134,10 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
134 regs.regs[5] = (unsigned long)fn; 134 regs.regs[5] = (unsigned long)fn;
135 135
136 regs.pc = (unsigned long)kernel_thread_helper; 136 regs.pc = (unsigned long)kernel_thread_helper;
137 regs.sr = (1 << 30); 137 regs.sr = SR_MD;
138#if defined(CONFIG_SH_FPU)
139 regs.sr |= SR_FD;
140#endif
138 141
139 /* Ok, create the new process.. */ 142 /* Ok, create the new process.. */
140 pid = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, 143 pid = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
@@ -189,6 +192,15 @@ int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu)
189} 192}
190EXPORT_SYMBOL(dump_fpu); 193EXPORT_SYMBOL(dump_fpu);
191 194
195/*
196 * This gets called before we allocate a new thread and copy
197 * the current task into it.
198 */
199void prepare_to_copy(struct task_struct *tsk)
200{
201 unlazy_fpu(tsk, task_pt_regs(tsk));
202}
203
192asmlinkage void ret_from_fork(void); 204asmlinkage void ret_from_fork(void);
193 205
194int copy_thread(unsigned long clone_flags, unsigned long usp, 206int copy_thread(unsigned long clone_flags, unsigned long usp,
@@ -197,16 +209,10 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
197{ 209{
198 struct thread_info *ti = task_thread_info(p); 210 struct thread_info *ti = task_thread_info(p);
199 struct pt_regs *childregs; 211 struct pt_regs *childregs;
200#if defined(CONFIG_SH_FPU) || defined(CONFIG_SH_DSP) 212#if defined(CONFIG_SH_DSP)
201 struct task_struct *tsk = current; 213 struct task_struct *tsk = current;
202#endif 214#endif
203 215
204#if defined(CONFIG_SH_FPU)
205 unlazy_fpu(tsk, regs);
206 p->thread.fpu = tsk->thread.fpu;
207 copy_to_stopped_child_used_math(p);
208#endif
209
210#if defined(CONFIG_SH_DSP) 216#if defined(CONFIG_SH_DSP)
211 if (is_dsp_enabled(tsk)) { 217 if (is_dsp_enabled(tsk)) {
212 /* We can use the __save_dsp or just copy the struct: 218 /* We can use the __save_dsp or just copy the struct:
@@ -226,6 +232,8 @@ int copy_thread(unsigned long clone_flags, unsigned long usp,
226 } else { 232 } else {
227 childregs->regs[15] = (unsigned long)childregs; 233 childregs->regs[15] = (unsigned long)childregs;
228 ti->addr_limit = KERNEL_DS; 234 ti->addr_limit = KERNEL_DS;
235 ti->status &= ~TS_USEDFPU;
236 p->fpu_counter = 0;
229 } 237 }
230 238
231 if (clone_flags & CLONE_SETTLS) 239 if (clone_flags & CLONE_SETTLS)
diff --git a/arch/sh/math-emu/math.c b/arch/sh/math-emu/math.c
index ac2d7abd2567..d6c15cae0912 100644
--- a/arch/sh/math-emu/math.c
+++ b/arch/sh/math-emu/math.c
@@ -558,7 +558,7 @@ static int ieee_fpe_handler(struct pt_regs *regs)
558 (finsn >> 8) & 0xf); 558 (finsn >> 8) & 0xf);
559 tsk->thread.fpu.hard.fpscr &= 559 tsk->thread.fpu.hard.fpscr &=
560 ~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK); 560 ~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK);
561 set_tsk_thread_flag(tsk, TIF_USEDFPU); 561 task_thread_info(tsk)->status |= TS_USEDFPU;
562 } else { 562 } else {
563 info.si_signo = SIGFPE; 563 info.si_signo = SIGFPE;
564 info.si_errno = 0; 564 info.si_errno = 0;
@@ -619,10 +619,10 @@ int do_fpu_inst(unsigned short inst, struct pt_regs *regs)
619 struct task_struct *tsk = current; 619 struct task_struct *tsk = current;
620 struct sh_fpu_soft_struct *fpu = &(tsk->thread.fpu.soft); 620 struct sh_fpu_soft_struct *fpu = &(tsk->thread.fpu.soft);
621 621
622 if (!test_tsk_thread_flag(tsk, TIF_USEDFPU)) { 622 if (!(task_thread_info(tsk)->status & TS_USEDFPU)) {
623 /* initialize once. */ 623 /* initialize once. */
624 fpu_init(fpu); 624 fpu_init(fpu);
625 set_tsk_thread_flag(tsk, TIF_USEDFPU); 625 task_thread_info(tsk)->status |= TS_USEDFPU;
626 } 626 }
627 627
628 return fpu_emulate(inst, fpu, regs); 628 return fpu_emulate(inst, fpu, regs);