diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2005-04-28 13:39:10 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2005-10-29 19:31:12 +0100 |
commit | cd21dfcfbb5c43de54f6be795dde07397da2bc2f (patch) | |
tree | ed3a6c46fd6aabac95c99b1e816493fcb5f788f8 /arch/mips/kernel/traps.c | |
parent | 63b2d2f4d2073ac3452ce977d27cc81eabaa61a3 (diff) |
Fix preemption and SMP problems in the FP emulator code.
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/kernel/traps.c')
-rw-r--r-- | arch/mips/kernel/traps.c | 19 |
1 files changed, 17 insertions, 2 deletions
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 15fed020215..b3ecd02757c 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -551,6 +551,14 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) preempt_disable(); +#ifdef CONFIG_PREEMPT + if (!is_fpu_owner()) { + /* We might lose fpu before disabling preempt... */ + own_fpu(); + BUG_ON(!used_math()); + restore_fp(current); + } +#endif /* * Unimplemented operation exception. If we've got the full * software emulator on-board, let's use it... @@ -562,11 +570,18 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) * a bit extreme for what should be an infrequent event. */ save_fp(current); + /* Ensure 'resume' not overwrite saved fp context again. */ + lose_fpu(); + + preempt_enable(); /* Run the emulator */ sig = fpu_emulator_cop1Handler (0, regs, ¤t->thread.fpu.soft); + preempt_disable(); + + own_fpu(); /* Using the FPU again. */ /* * We can't allow the emulated instruction to leave any of * the cause bit set in $fcr31. @@ -712,6 +727,8 @@ asmlinkage void do_cpu(struct pt_regs *regs) set_used_math(); } + preempt_enable(); + if (!cpu_has_fpu) { int sig = fpu_emulator_cop1Handler(0, regs, ¤t->thread.fpu.soft); @@ -719,8 +736,6 @@ asmlinkage void do_cpu(struct pt_regs *regs) force_sig(sig, current); } - preempt_enable(); - return; case 2: |