diff options
author | Atsushi Nemoto <anemo@mba.ocn.ne.jp> | 2007-03-09 11:07:45 -0500 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2007-03-16 21:03:26 -0400 |
commit | 53dc80287da43b75df2fe2658651d3c5160dad8e (patch) | |
tree | 3c4c97534c379709cd2a1dae5b90df626349f21d /arch/mips/kernel/traps.c | |
parent | c6a2f4679331206ef5d353fc9a6cda2fa4aef8c6 (diff) |
[MIPS] FPU ownership management & preemption fixes
Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
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 | 84 |
1 files changed, 37 insertions, 47 deletions
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 18f56a9dbcfa..7d76a85422b2 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c | |||
@@ -610,16 +610,6 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) | |||
610 | if (fcr31 & FPU_CSR_UNI_X) { | 610 | if (fcr31 & FPU_CSR_UNI_X) { |
611 | int sig; | 611 | int sig; |
612 | 612 | ||
613 | preempt_disable(); | ||
614 | |||
615 | #ifdef CONFIG_PREEMPT | ||
616 | if (!is_fpu_owner()) { | ||
617 | /* We might lose fpu before disabling preempt... */ | ||
618 | own_fpu(); | ||
619 | BUG_ON(!used_math()); | ||
620 | restore_fp(current); | ||
621 | } | ||
622 | #endif | ||
623 | /* | 613 | /* |
624 | * Unimplemented operation exception. If we've got the full | 614 | * Unimplemented operation exception. If we've got the full |
625 | * software emulator on-board, let's use it... | 615 | * software emulator on-board, let's use it... |
@@ -630,18 +620,12 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) | |||
630 | * register operands before invoking the emulator, which seems | 620 | * register operands before invoking the emulator, which seems |
631 | * a bit extreme for what should be an infrequent event. | 621 | * a bit extreme for what should be an infrequent event. |
632 | */ | 622 | */ |
633 | save_fp(current); | ||
634 | /* Ensure 'resume' not overwrite saved fp context again. */ | 623 | /* Ensure 'resume' not overwrite saved fp context again. */ |
635 | lose_fpu(); | 624 | lose_fpu(1); |
636 | |||
637 | preempt_enable(); | ||
638 | 625 | ||
639 | /* Run the emulator */ | 626 | /* Run the emulator */ |
640 | sig = fpu_emulator_cop1Handler (regs, ¤t->thread.fpu, 1); | 627 | sig = fpu_emulator_cop1Handler (regs, ¤t->thread.fpu, 1); |
641 | 628 | ||
642 | preempt_disable(); | ||
643 | |||
644 | own_fpu(); /* Using the FPU again. */ | ||
645 | /* | 629 | /* |
646 | * We can't allow the emulated instruction to leave any of | 630 | * We can't allow the emulated instruction to leave any of |
647 | * the cause bit set in $fcr31. | 631 | * the cause bit set in $fcr31. |
@@ -649,9 +633,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) | |||
649 | current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X; | 633 | current->thread.fpu.fcr31 &= ~FPU_CSR_ALL_X; |
650 | 634 | ||
651 | /* Restore the hardware register state */ | 635 | /* Restore the hardware register state */ |
652 | restore_fp(current); | 636 | own_fpu(1); /* Using the FPU again. */ |
653 | |||
654 | preempt_enable(); | ||
655 | 637 | ||
656 | /* If something went wrong, signal */ | 638 | /* If something went wrong, signal */ |
657 | if (sig) | 639 | if (sig) |
@@ -775,12 +757,11 @@ asmlinkage void do_cpu(struct pt_regs *regs) | |||
775 | { | 757 | { |
776 | unsigned int cpid; | 758 | unsigned int cpid; |
777 | 759 | ||
778 | die_if_kernel("do_cpu invoked from kernel context!", regs); | ||
779 | |||
780 | cpid = (regs->cp0_cause >> CAUSEB_CE) & 3; | 760 | cpid = (regs->cp0_cause >> CAUSEB_CE) & 3; |
781 | 761 | ||
782 | switch (cpid) { | 762 | switch (cpid) { |
783 | case 0: | 763 | case 0: |
764 | die_if_kernel("do_cpu invoked from kernel context!", regs); | ||
784 | if (!cpu_has_llsc) | 765 | if (!cpu_has_llsc) |
785 | if (!simulate_llsc(regs)) | 766 | if (!simulate_llsc(regs)) |
786 | return; | 767 | return; |
@@ -791,21 +772,30 @@ asmlinkage void do_cpu(struct pt_regs *regs) | |||
791 | break; | 772 | break; |
792 | 773 | ||
793 | case 1: | 774 | case 1: |
794 | preempt_disable(); | 775 | if (!test_thread_flag(TIF_ALLOW_FP_IN_KERNEL)) |
795 | 776 | die_if_kernel("do_cpu invoked from kernel context!", | |
796 | own_fpu(); | 777 | regs); |
797 | if (used_math()) { /* Using the FPU again. */ | 778 | if (used_math()) /* Using the FPU again. */ |
798 | restore_fp(current); | 779 | own_fpu(1); |
799 | } else { /* First time FPU user. */ | 780 | else { /* First time FPU user. */ |
800 | init_fpu(); | 781 | init_fpu(); |
801 | set_used_math(); | 782 | set_used_math(); |
802 | } | 783 | } |
803 | 784 | ||
804 | if (cpu_has_fpu) { | 785 | if (raw_cpu_has_fpu) { |
805 | preempt_enable(); | 786 | if (test_thread_flag(TIF_ALLOW_FP_IN_KERNEL)) { |
787 | local_irq_disable(); | ||
788 | if (cpu_has_fpu) | ||
789 | regs->cp0_status |= ST0_CU1; | ||
790 | /* | ||
791 | * We must return without enabling | ||
792 | * interrupts to ensure keep FPU | ||
793 | * ownership until resume. | ||
794 | */ | ||
795 | return; | ||
796 | } | ||
806 | } else { | 797 | } else { |
807 | int sig; | 798 | int sig; |
808 | preempt_enable(); | ||
809 | sig = fpu_emulator_cop1Handler(regs, | 799 | sig = fpu_emulator_cop1Handler(regs, |
810 | ¤t->thread.fpu, 0); | 800 | ¤t->thread.fpu, 0); |
811 | if (sig) | 801 | if (sig) |
@@ -1259,26 +1249,26 @@ static inline void mips_srs_init(void) | |||
1259 | /* | 1249 | /* |
1260 | * This is used by native signal handling | 1250 | * This is used by native signal handling |
1261 | */ | 1251 | */ |
1262 | asmlinkage int (*save_fp_context)(struct sigcontext *sc); | 1252 | asmlinkage int (*save_fp_context)(struct sigcontext __user *sc); |
1263 | asmlinkage int (*restore_fp_context)(struct sigcontext *sc); | 1253 | asmlinkage int (*restore_fp_context)(struct sigcontext __user *sc); |
1264 | 1254 | ||
1265 | extern asmlinkage int _save_fp_context(struct sigcontext *sc); | 1255 | extern asmlinkage int _save_fp_context(struct sigcontext __user *sc); |
1266 | extern asmlinkage int _restore_fp_context(struct sigcontext *sc); | 1256 | extern asmlinkage int _restore_fp_context(struct sigcontext __user *sc); |
1267 | 1257 | ||
1268 | extern asmlinkage int fpu_emulator_save_context(struct sigcontext *sc); | 1258 | extern asmlinkage int fpu_emulator_save_context(struct sigcontext __user *sc); |
1269 | extern asmlinkage int fpu_emulator_restore_context(struct sigcontext *sc); | 1259 | extern asmlinkage int fpu_emulator_restore_context(struct sigcontext __user *sc); |
1270 | 1260 | ||
1271 | #ifdef CONFIG_SMP | 1261 | #ifdef CONFIG_SMP |
1272 | static int smp_save_fp_context(struct sigcontext *sc) | 1262 | static int smp_save_fp_context(struct sigcontext __user *sc) |
1273 | { | 1263 | { |
1274 | return cpu_has_fpu | 1264 | return raw_cpu_has_fpu |
1275 | ? _save_fp_context(sc) | 1265 | ? _save_fp_context(sc) |
1276 | : fpu_emulator_save_context(sc); | 1266 | : fpu_emulator_save_context(sc); |
1277 | } | 1267 | } |
1278 | 1268 | ||
1279 | static int smp_restore_fp_context(struct sigcontext *sc) | 1269 | static int smp_restore_fp_context(struct sigcontext __user *sc) |
1280 | { | 1270 | { |
1281 | return cpu_has_fpu | 1271 | return raw_cpu_has_fpu |
1282 | ? _restore_fp_context(sc) | 1272 | ? _restore_fp_context(sc) |
1283 | : fpu_emulator_restore_context(sc); | 1273 | : fpu_emulator_restore_context(sc); |
1284 | } | 1274 | } |
@@ -1306,14 +1296,14 @@ static inline void signal_init(void) | |||
1306 | /* | 1296 | /* |
1307 | * This is used by 32-bit signal stuff on the 64-bit kernel | 1297 | * This is used by 32-bit signal stuff on the 64-bit kernel |
1308 | */ | 1298 | */ |
1309 | asmlinkage int (*save_fp_context32)(struct sigcontext32 *sc); | 1299 | asmlinkage int (*save_fp_context32)(struct sigcontext32 __user *sc); |
1310 | asmlinkage int (*restore_fp_context32)(struct sigcontext32 *sc); | 1300 | asmlinkage int (*restore_fp_context32)(struct sigcontext32 __user *sc); |
1311 | 1301 | ||
1312 | extern asmlinkage int _save_fp_context32(struct sigcontext32 *sc); | 1302 | extern asmlinkage int _save_fp_context32(struct sigcontext32 __user *sc); |
1313 | extern asmlinkage int _restore_fp_context32(struct sigcontext32 *sc); | 1303 | extern asmlinkage int _restore_fp_context32(struct sigcontext32 __user *sc); |
1314 | 1304 | ||
1315 | extern asmlinkage int fpu_emulator_save_context32(struct sigcontext32 *sc); | 1305 | extern asmlinkage int fpu_emulator_save_context32(struct sigcontext32 __user *sc); |
1316 | extern asmlinkage int fpu_emulator_restore_context32(struct sigcontext32 *sc); | 1306 | extern asmlinkage int fpu_emulator_restore_context32(struct sigcontext32 __user *sc); |
1317 | 1307 | ||
1318 | static inline void signal32_init(void) | 1308 | static inline void signal32_init(void) |
1319 | { | 1309 | { |