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/math-emu/cp1emu.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/math-emu/cp1emu.c')
-rw-r--r-- | arch/mips/math-emu/cp1emu.c | 41 |
1 files changed, 27 insertions, 14 deletions
diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index c70f25f5889e..6fed6ce43c4e 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c | |||
@@ -79,7 +79,17 @@ struct mips_fpu_emulator_private fpuemuprivate; | |||
79 | 79 | ||
80 | /* Convert Mips rounding mode (0..3) to IEEE library modes. */ | 80 | /* Convert Mips rounding mode (0..3) to IEEE library modes. */ |
81 | static const unsigned char ieee_rm[4] = { | 81 | static const unsigned char ieee_rm[4] = { |
82 | IEEE754_RN, IEEE754_RZ, IEEE754_RU, IEEE754_RD | 82 | [FPU_CSR_RN] = IEEE754_RN, |
83 | [FPU_CSR_RZ] = IEEE754_RZ, | ||
84 | [FPU_CSR_RU] = IEEE754_RU, | ||
85 | [FPU_CSR_RD] = IEEE754_RD, | ||
86 | }; | ||
87 | /* Convert IEEE library modes to Mips rounding mode (0..3). */ | ||
88 | static const unsigned char mips_rm[4] = { | ||
89 | [IEEE754_RN] = FPU_CSR_RN, | ||
90 | [IEEE754_RZ] = FPU_CSR_RZ, | ||
91 | [IEEE754_RD] = FPU_CSR_RD, | ||
92 | [IEEE754_RU] = FPU_CSR_RU, | ||
83 | }; | 93 | }; |
84 | 94 | ||
85 | #if __mips >= 4 | 95 | #if __mips >= 4 |
@@ -368,6 +378,7 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx) | |||
368 | } | 378 | } |
369 | if (MIPSInst_RD(ir) == FPCREG_CSR) { | 379 | if (MIPSInst_RD(ir) == FPCREG_CSR) { |
370 | value = ctx->fcr31; | 380 | value = ctx->fcr31; |
381 | value = (value & ~0x3) | mips_rm[value & 0x3]; | ||
371 | #ifdef CSRTRACE | 382 | #ifdef CSRTRACE |
372 | printk("%p gpr[%d]<-csr=%08x\n", | 383 | printk("%p gpr[%d]<-csr=%08x\n", |
373 | (void *) (xcp->cp0_epc), | 384 | (void *) (xcp->cp0_epc), |
@@ -400,11 +411,10 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx) | |||
400 | (void *) (xcp->cp0_epc), | 411 | (void *) (xcp->cp0_epc), |
401 | MIPSInst_RT(ir), value); | 412 | MIPSInst_RT(ir), value); |
402 | #endif | 413 | #endif |
403 | ctx->fcr31 = value; | 414 | value &= (FPU_CSR_FLUSH | FPU_CSR_ALL_E | FPU_CSR_ALL_S | 0x03); |
404 | /* copy new rounding mode and | 415 | ctx->fcr31 &= ~(FPU_CSR_FLUSH | FPU_CSR_ALL_E | FPU_CSR_ALL_S | 0x03); |
405 | flush bit to ieee library state! */ | 416 | /* convert to ieee library modes */ |
406 | ieee754_csr.nod = (ctx->fcr31 & 0x1000000) != 0; | 417 | ctx->fcr31 |= (value & ~0x3) | ieee_rm[value & 0x3]; |
407 | ieee754_csr.rm = ieee_rm[value & 0x3]; | ||
408 | } | 418 | } |
409 | if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { | 419 | if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { |
410 | return SIGFPE; | 420 | return SIGFPE; |
@@ -570,7 +580,7 @@ static const unsigned char cmptab[8] = { | |||
570 | static ieee754##p fpemu_##p##_##name (ieee754##p r, ieee754##p s, \ | 580 | static ieee754##p fpemu_##p##_##name (ieee754##p r, ieee754##p s, \ |
571 | ieee754##p t) \ | 581 | ieee754##p t) \ |
572 | { \ | 582 | { \ |
573 | struct ieee754_csr ieee754_csr_save; \ | 583 | struct _ieee754_csr ieee754_csr_save; \ |
574 | s = f1 (s, t); \ | 584 | s = f1 (s, t); \ |
575 | ieee754_csr_save = ieee754_csr; \ | 585 | ieee754_csr_save = ieee754_csr; \ |
576 | s = f2 (s, r); \ | 586 | s = f2 (s, r); \ |
@@ -699,8 +709,6 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_soft_struct *ctx, | |||
699 | rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S; | 709 | rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S; |
700 | 710 | ||
701 | ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr; | 711 | ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr; |
702 | if (ieee754_csr.nod) | ||
703 | ctx->fcr31 |= 0x1000000; | ||
704 | if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { | 712 | if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { |
705 | /*printk ("SIGFPE: fpu csr = %08x\n", | 713 | /*printk ("SIGFPE: fpu csr = %08x\n", |
706 | ctx->fcr31); */ | 714 | ctx->fcr31); */ |
@@ -1297,12 +1305,17 @@ int fpu_emulator_cop1Handler(int xcptno, struct pt_regs *xcp, | |||
1297 | if (insn == 0) | 1305 | if (insn == 0) |
1298 | xcp->cp0_epc += 4; /* skip nops */ | 1306 | xcp->cp0_epc += 4; /* skip nops */ |
1299 | else { | 1307 | else { |
1300 | /* Update ieee754_csr. Only relevant if we have a | 1308 | /* |
1301 | h/w FPU */ | 1309 | * The 'ieee754_csr' is an alias of |
1302 | ieee754_csr.nod = (ctx->fcr31 & 0x1000000) != 0; | 1310 | * ctx->fcr31. No need to copy ctx->fcr31 to |
1303 | ieee754_csr.rm = ieee_rm[ctx->fcr31 & 0x3]; | 1311 | * ieee754_csr. But ieee754_csr.rm is ieee |
1304 | ieee754_csr.cx = (ctx->fcr31 >> 12) & 0x1f; | 1312 | * library modes. (not mips rounding mode) |
1313 | */ | ||
1314 | /* convert to ieee library modes */ | ||
1315 | ieee754_csr.rm = ieee_rm[ieee754_csr.rm]; | ||
1305 | sig = cop1Emulate(xcp, ctx); | 1316 | sig = cop1Emulate(xcp, ctx); |
1317 | /* revert to mips rounding mode */ | ||
1318 | ieee754_csr.rm = mips_rm[ieee754_csr.rm]; | ||
1306 | } | 1319 | } |
1307 | 1320 | ||
1308 | if (cpu_has_fpu) | 1321 | if (cpu_has_fpu) |