aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh
diff options
context:
space:
mode:
authorStuart Menefy <stuart.menefy@st.com>2009-09-25 13:25:10 -0400
committerPaul Mundt <lethal@linux-sh.org>2009-11-24 03:45:38 -0500
commitd3ea9fa0a563620fe9f416f94bb8927c64390917 (patch)
tree0aa1278ac7929f936fc4fd8daf235930f6164d18 /arch/sh
parent39ac11c1607f1d566e7cf885acd403fa4f07f8a2 (diff)
sh: Minor optimisations to FPU handling
A number of small optimisations to FPU handling, in particular: - move the task USEDFPU flag from the thread_info flags field (which is accessed asynchronously to the thread) to a new status field, which is only accessed by the thread itself. This allows locking to be removed in most cases, or can be reduced to a preempt_lock(). This mimics the i386 behaviour. - move the modification of regs->sr and thread_info->status flags out of save_fpu() to __unlazy_fpu(). This gives the compiler a better chance to optimise things, as well as making save_fpu() symmetrical with restore_fpu() and init_fpu(). - implement prepare_to_copy(), so that when creating a thread, we can unlazy the FPU prior to copying the thread data structures. Also make sure that the FPU is disabled while in the kernel, in particular while booting, and for newly created kernel threads, In a very artificial benchmark, the execution time for 2500000 context switches was reduced from 50 to 45 seconds. Signed-off-by: Stuart Menefy <stuart.menefy@st.com> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'arch/sh')
-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);