aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/sh/include/asm/fpu.h3
-rw-r--r--arch/sh/kernel/cpu/sh4/fpu.c16
-rw-r--r--arch/sh/kernel/process_32.c16
3 files changed, 31 insertions, 4 deletions
diff --git a/arch/sh/include/asm/fpu.h b/arch/sh/include/asm/fpu.h
index 1d3aee04b5cc..bfd78e19de1b 100644
--- a/arch/sh/include/asm/fpu.h
+++ b/arch/sh/include/asm/fpu.h
@@ -19,6 +19,7 @@ static inline void grab_fpu(struct pt_regs *regs)
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, struct pt_regs *regs);
22void fpu_state_restore(struct pt_regs *regs);
22#else 23#else
23 24
24#define release_fpu(regs) do { } while (0) 25#define release_fpu(regs) do { } while (0)
@@ -44,6 +45,8 @@ static inline void unlazy_fpu(struct task_struct *tsk, struct pt_regs *regs)
44 preempt_disable(); 45 preempt_disable();
45 if (test_tsk_thread_flag(tsk, TIF_USEDFPU)) 46 if (test_tsk_thread_flag(tsk, TIF_USEDFPU))
46 save_fpu(tsk, regs); 47 save_fpu(tsk, regs);
48 else
49 tsk->fpu_counter = 0;
47 preempt_enable(); 50 preempt_enable();
48} 51}
49 52
diff --git a/arch/sh/kernel/cpu/sh4/fpu.c b/arch/sh/kernel/cpu/sh4/fpu.c
index e3ea5411da6d..d79226fa59d1 100644
--- a/arch/sh/kernel/cpu/sh4/fpu.c
+++ b/arch/sh/kernel/cpu/sh4/fpu.c
@@ -483,18 +483,18 @@ BUILD_TRAP_HANDLER(fpu_error)
483 force_sig(SIGFPE, tsk); 483 force_sig(SIGFPE, tsk);
484} 484}
485 485
486BUILD_TRAP_HANDLER(fpu_state_restore) 486void fpu_state_restore(struct pt_regs *regs)
487{ 487{
488 struct task_struct *tsk = current; 488 struct task_struct *tsk = current;
489 TRAP_HANDLER_DECL;
490 489
491 grab_fpu(regs); 490 grab_fpu(regs);
492 if (!user_mode(regs)) { 491 if (unlikely(!user_mode(regs))) {
493 printk(KERN_ERR "BUG: FPU is used in kernel mode.\n"); 492 printk(KERN_ERR "BUG: FPU is used in kernel mode.\n");
493 BUG();
494 return; 494 return;
495 } 495 }
496 496
497 if (used_math()) { 497 if (likely(used_math())) {
498 /* Using the FPU again. */ 498 /* Using the FPU again. */
499 restore_fpu(tsk); 499 restore_fpu(tsk);
500 } else { 500 } else {
@@ -503,4 +503,12 @@ BUILD_TRAP_HANDLER(fpu_state_restore)
503 set_used_math(); 503 set_used_math();
504 } 504 }
505 set_tsk_thread_flag(tsk, TIF_USEDFPU); 505 set_tsk_thread_flag(tsk, TIF_USEDFPU);
506 tsk->fpu_counter++;
507}
508
509BUILD_TRAP_HANDLER(fpu_state_restore)
510{
511 TRAP_HANDLER_DECL;
512
513 fpu_state_restore(regs);
506} 514}
diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c
index 0673c4746be3..aff5fe02e393 100644
--- a/arch/sh/kernel/process_32.c
+++ b/arch/sh/kernel/process_32.c
@@ -288,8 +288,14 @@ static void ubc_set_tracing(int asid, unsigned long pc)
288__notrace_funcgraph struct task_struct * 288__notrace_funcgraph struct task_struct *
289__switch_to(struct task_struct *prev, struct task_struct *next) 289__switch_to(struct task_struct *prev, struct task_struct *next)
290{ 290{
291 struct thread_struct *next_t = &next->thread;
292
291#if defined(CONFIG_SH_FPU) 293#if defined(CONFIG_SH_FPU)
292 unlazy_fpu(prev, task_pt_regs(prev)); 294 unlazy_fpu(prev, task_pt_regs(prev));
295
296 /* we're going to use this soon, after a few expensive things */
297 if (next->fpu_counter > 5)
298 prefetch(&next_t->fpu.hard);
293#endif 299#endif
294 300
295#ifdef CONFIG_MMU 301#ifdef CONFIG_MMU
@@ -321,6 +327,16 @@ __switch_to(struct task_struct *prev, struct task_struct *next)
321#endif 327#endif
322 } 328 }
323 329
330#if defined(CONFIG_SH_FPU)
331 /* If the task has used fpu the last 5 timeslices, just do a full
332 * restore of the math state immediately to avoid the trap; the
333 * chances of needing FPU soon are obviously high now
334 */
335 if (next->fpu_counter > 5) {
336 fpu_state_restore(task_pt_regs(next));
337 }
338#endif
339
324 return prev; 340 return prev;
325} 341}
326 342