aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/traps.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/kernel/traps.c')
-rw-r--r--arch/mips/kernel/traps.c84
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, &current->thread.fpu, 1); 627 sig = fpu_emulator_cop1Handler (regs, &current->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 &current->thread.fpu, 0); 800 &current->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 */
1262asmlinkage int (*save_fp_context)(struct sigcontext *sc); 1252asmlinkage int (*save_fp_context)(struct sigcontext __user *sc);
1263asmlinkage int (*restore_fp_context)(struct sigcontext *sc); 1253asmlinkage int (*restore_fp_context)(struct sigcontext __user *sc);
1264 1254
1265extern asmlinkage int _save_fp_context(struct sigcontext *sc); 1255extern asmlinkage int _save_fp_context(struct sigcontext __user *sc);
1266extern asmlinkage int _restore_fp_context(struct sigcontext *sc); 1256extern asmlinkage int _restore_fp_context(struct sigcontext __user *sc);
1267 1257
1268extern asmlinkage int fpu_emulator_save_context(struct sigcontext *sc); 1258extern asmlinkage int fpu_emulator_save_context(struct sigcontext __user *sc);
1269extern asmlinkage int fpu_emulator_restore_context(struct sigcontext *sc); 1259extern asmlinkage int fpu_emulator_restore_context(struct sigcontext __user *sc);
1270 1260
1271#ifdef CONFIG_SMP 1261#ifdef CONFIG_SMP
1272static int smp_save_fp_context(struct sigcontext *sc) 1262static 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
1279static int smp_restore_fp_context(struct sigcontext *sc) 1269static 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 */
1309asmlinkage int (*save_fp_context32)(struct sigcontext32 *sc); 1299asmlinkage int (*save_fp_context32)(struct sigcontext32 __user *sc);
1310asmlinkage int (*restore_fp_context32)(struct sigcontext32 *sc); 1300asmlinkage int (*restore_fp_context32)(struct sigcontext32 __user *sc);
1311 1301
1312extern asmlinkage int _save_fp_context32(struct sigcontext32 *sc); 1302extern asmlinkage int _save_fp_context32(struct sigcontext32 __user *sc);
1313extern asmlinkage int _restore_fp_context32(struct sigcontext32 *sc); 1303extern asmlinkage int _restore_fp_context32(struct sigcontext32 __user *sc);
1314 1304
1315extern asmlinkage int fpu_emulator_save_context32(struct sigcontext32 *sc); 1305extern asmlinkage int fpu_emulator_save_context32(struct sigcontext32 __user *sc);
1316extern asmlinkage int fpu_emulator_restore_context32(struct sigcontext32 *sc); 1306extern asmlinkage int fpu_emulator_restore_context32(struct sigcontext32 __user *sc);
1317 1307
1318static inline void signal32_init(void) 1308static inline void signal32_init(void)
1319{ 1309{