diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2005-04-28 09:39:10 -0400 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2005-10-29 14:31:12 -0400 |
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 15fed0202154..b3ecd02757cb 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) | |||
551 | 551 | ||
552 | preempt_disable(); | 552 | preempt_disable(); |
553 | 553 | ||
554 | #ifdef CONFIG_PREEMPT | ||
555 | if (!is_fpu_owner()) { | ||
556 | /* We might lose fpu before disabling preempt... */ | ||
557 | own_fpu(); | ||
558 | BUG_ON(!used_math()); | ||
559 | restore_fp(current); | ||
560 | } | ||
561 | #endif | ||
554 | /* | 562 | /* |
555 | * Unimplemented operation exception. If we've got the full | 563 | * Unimplemented operation exception. If we've got the full |
556 | * software emulator on-board, let's use it... | 564 | * software emulator on-board, let's use it... |
@@ -562,11 +570,18 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) | |||
562 | * a bit extreme for what should be an infrequent event. | 570 | * a bit extreme for what should be an infrequent event. |
563 | */ | 571 | */ |
564 | save_fp(current); | 572 | save_fp(current); |
573 | /* Ensure 'resume' not overwrite saved fp context again. */ | ||
574 | lose_fpu(); | ||
575 | |||
576 | preempt_enable(); | ||
565 | 577 | ||
566 | /* Run the emulator */ | 578 | /* Run the emulator */ |
567 | sig = fpu_emulator_cop1Handler (0, regs, | 579 | sig = fpu_emulator_cop1Handler (0, regs, |
568 | ¤t->thread.fpu.soft); | 580 | ¤t->thread.fpu.soft); |
569 | 581 | ||
582 | preempt_disable(); | ||
583 | |||
584 | own_fpu(); /* Using the FPU again. */ | ||
570 | /* | 585 | /* |
571 | * We can't allow the emulated instruction to leave any of | 586 | * We can't allow the emulated instruction to leave any of |
572 | * the cause bit set in $fcr31. | 587 | * the cause bit set in $fcr31. |
@@ -712,6 +727,8 @@ asmlinkage void do_cpu(struct pt_regs *regs) | |||
712 | set_used_math(); | 727 | set_used_math(); |
713 | } | 728 | } |
714 | 729 | ||
730 | preempt_enable(); | ||
731 | |||
715 | if (!cpu_has_fpu) { | 732 | if (!cpu_has_fpu) { |
716 | int sig = fpu_emulator_cop1Handler(0, regs, | 733 | int sig = fpu_emulator_cop1Handler(0, regs, |
717 | ¤t->thread.fpu.soft); | 734 | ¤t->thread.fpu.soft); |
@@ -719,8 +736,6 @@ asmlinkage void do_cpu(struct pt_regs *regs) | |||
719 | force_sig(sig, current); | 736 | force_sig(sig, current); |
720 | } | 737 | } |
721 | 738 | ||
722 | preempt_enable(); | ||
723 | |||
724 | return; | 739 | return; |
725 | 740 | ||
726 | case 2: | 741 | case 2: |