Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Fix preemption and SMP problems in the FP emulator code.

Signed-off-by: Ralf Baechle <ralf@linux-mips.org>

+120 -117
+17 -2
arch/mips/kernel/traps.c
··· 551 551 552 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 563 * Unimplemented operation exception. If we've got the full 556 564 * software emulator on-board, let's use it... ··· 570 562 * a bit extreme for what should be an infrequent event. 571 563 */ 572 564 save_fp(current); 565 + /* Ensure 'resume' not overwrite saved fp context again. */ 566 + lose_fpu(); 567 + 568 + preempt_enable(); 573 569 574 570 /* Run the emulator */ 575 571 sig = fpu_emulator_cop1Handler (0, regs, 576 572 &current->thread.fpu.soft); 577 573 574 + preempt_disable(); 575 + 576 + own_fpu(); /* Using the FPU again. */ 578 577 /* 579 578 * We can't allow the emulated instruction to leave any of 580 579 * the cause bit set in $fcr31. ··· 727 712 set_used_math(); 728 713 } 729 714 715 + preempt_enable(); 716 + 730 717 if (!cpu_has_fpu) { 731 718 int sig = fpu_emulator_cop1Handler(0, regs, 732 719 &current->thread.fpu.soft); 733 720 if (sig) 734 721 force_sig(sig, current); 735 722 } 736 - 737 - preempt_enable(); 738 723 739 724 return; 740 725
+27 -14
arch/mips/math-emu/cp1emu.c
··· 79 79 80 80 /* Convert Mips rounding mode (0..3) to IEEE library modes. */ 81 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 95 #if __mips >= 4 ··· 378 368 } 379 369 if (MIPSInst_RD(ir) == FPCREG_CSR) { 380 370 value = ctx->fcr31; 371 + value = (value & ~0x3) | mips_rm[value & 0x3]; 381 372 #ifdef CSRTRACE 382 373 printk("%p gpr[%d]<-csr=%08x\n", 383 374 (void *) (xcp->cp0_epc), ··· 411 400 (void *) (xcp->cp0_epc), 412 401 MIPSInst_RT(ir), value); 413 402 #endif 414 - ctx->fcr31 = value; 415 - /* copy new rounding mode and 416 - flush bit to ieee library state! */ 417 - ieee754_csr.nod = (ctx->fcr31 & 0x1000000) != 0; 418 - ieee754_csr.rm = ieee_rm[value & 0x3]; 403 + value &= (FPU_CSR_FLUSH | FPU_CSR_ALL_E | FPU_CSR_ALL_S | 0x03); 404 + ctx->fcr31 &= ~(FPU_CSR_FLUSH | FPU_CSR_ALL_E | FPU_CSR_ALL_S | 0x03); 405 + /* convert to ieee library modes */ 406 + ctx->fcr31 |= (value & ~0x3) | ieee_rm[value & 0x3]; 419 407 } 420 408 if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { 421 409 return SIGFPE; ··· 580 570 static ieee754##p fpemu_##p##_##name (ieee754##p r, ieee754##p s, \ 581 571 ieee754##p t) \ 582 572 { \ 583 - struct ieee754_csr ieee754_csr_save; \ 573 + struct _ieee754_csr ieee754_csr_save; \ 584 574 s = f1 (s, t); \ 585 575 ieee754_csr_save = ieee754_csr; \ 586 576 s = f2 (s, r); \ ··· 709 699 rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S; 710 700 711 701 ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr; 712 - if (ieee754_csr.nod) 713 - ctx->fcr31 |= 0x1000000; 714 702 if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) { 715 703 /*printk ("SIGFPE: fpu csr = %08x\n", 716 704 ctx->fcr31); */ ··· 1305 1297 if (insn == 0) 1306 1298 xcp->cp0_epc += 4; /* skip nops */ 1307 1299 else { 1308 - /* Update ieee754_csr. Only relevant if we have a 1309 - h/w FPU */ 1310 - ieee754_csr.nod = (ctx->fcr31 & 0x1000000) != 0; 1311 - ieee754_csr.rm = ieee_rm[ctx->fcr31 & 0x3]; 1312 - ieee754_csr.cx = (ctx->fcr31 >> 12) & 0x1f; 1300 + /* 1301 + * The 'ieee754_csr' is an alias of 1302 + * ctx->fcr31. No need to copy ctx->fcr31 to 1303 + * ieee754_csr. But ieee754_csr.rm is ieee 1304 + * library modes. (not mips rounding mode) 1305 + */ 1306 + /* convert to ieee library modes */ 1307 + ieee754_csr.rm = ieee_rm[ieee754_csr.rm]; 1313 1308 sig = cop1Emulate(xcp, ctx); 1309 + /* revert to mips rounding mode */ 1310 + ieee754_csr.rm = mips_rm[ieee754_csr.rm]; 1314 1311 } 1315 1312 1316 1313 if (cpu_has_fpu)
+1 -1
arch/mips/math-emu/dp_sqrt.c
··· 37 37 38 38 ieee754dp ieee754dp_sqrt(ieee754dp x) 39 39 { 40 - struct ieee754_csr oldcsr; 40 + struct _ieee754_csr oldcsr; 41 41 ieee754dp y, z, t; 42 42 unsigned scalx, yh; 43 43 COMPXDP;
-4
arch/mips/math-emu/ieee754.c
··· 50 50 "SNaN", 51 51 }; 52 52 53 - /* the control status register 54 - */ 55 - struct ieee754_csr ieee754_csr; 56 - 57 53 /* special constants 58 54 */ 59 55
+75 -96
arch/mips/math-emu/ieee754.h
··· 1 - /* single and double precision fp ops 2 - * missing extended precision. 3 - */ 4 1 /* 5 2 * MIPS floating point support 6 3 * Copyright (C) 1994-2000 Algorithmics Ltd. 7 4 * http://www.algor.co.uk 8 - * 9 - * ######################################################################## 10 5 * 11 6 * This program is free software; you can distribute it and/or modify it 12 7 * under the terms of the GNU General Public License (Version 2) as ··· 16 21 * with this program; if not, write to the Free Software Foundation, Inc., 17 22 * 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. 18 23 * 19 - * ######################################################################## 20 - */ 21 - 22 - /************************************************************************** 23 24 * Nov 7, 2000 24 25 * Modification to allow integration with Linux kernel 25 26 * 26 27 * Kevin D. Kissell, kevink@mips.com and Carsten Langgard, carstenl@mips.com 27 28 * Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. 28 - *************************************************************************/ 29 + */ 29 30 30 - #ifdef __KERNEL__ 31 - /* Going from Algorithmics to Linux native environment, add this */ 31 + #include <asm/byteorder.h> 32 32 #include <linux/types.h> 33 + #include <linux/sched.h> 33 34 34 35 /* 35 36 * Not very pretty, but the Linux kernel's normal va_list definition ··· 35 44 #include <stdarg.h> 36 45 #endif 37 46 38 - #else 39 - 40 - /* Note that __KERNEL__ is taken to mean Linux kernel */ 41 - 42 - #if #system(OpenBSD) 43 - #include <machine/types.h> 44 - #endif 45 - #include <machine/endian.h> 46 - 47 - #endif /* __KERNEL__ */ 48 - 49 - #if (defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN) || defined(__MIPSEL__) 47 + #ifdef __LITTLE_ENDIAN 50 48 struct ieee754dp_konst { 51 49 unsigned mantlo:32; 52 50 unsigned manthi:20; ··· 66 86 } ieee754sp; 67 87 #endif 68 88 69 - #if (defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) || defined(__MIPSEB__) 89 + #ifdef __BIG_ENDIAN 70 90 struct ieee754dp_konst { 71 91 unsigned sign:1; 72 92 unsigned bexp:11; 73 93 unsigned manthi:20; 74 94 unsigned mantlo:32; 75 95 }; 96 + 76 97 typedef union _ieee754dp { 77 98 struct ieee754dp_konst oparts; 78 99 struct { ··· 232 251 233 252 /* "normal" comparisons 234 253 */ 235 - static __inline int ieee754sp_eq(ieee754sp x, ieee754sp y) 254 + static inline int ieee754sp_eq(ieee754sp x, ieee754sp y) 236 255 { 237 256 return ieee754sp_cmp(x, y, IEEE754_CEQ, 0); 238 257 } 239 258 240 - static __inline int ieee754sp_ne(ieee754sp x, ieee754sp y) 259 + static inline int ieee754sp_ne(ieee754sp x, ieee754sp y) 241 260 { 242 261 return ieee754sp_cmp(x, y, 243 262 IEEE754_CLT | IEEE754_CGT | IEEE754_CUN, 0); 244 263 } 245 264 246 - static __inline int ieee754sp_lt(ieee754sp x, ieee754sp y) 265 + static inline int ieee754sp_lt(ieee754sp x, ieee754sp y) 247 266 { 248 267 return ieee754sp_cmp(x, y, IEEE754_CLT, 0); 249 268 } 250 269 251 - static __inline int ieee754sp_le(ieee754sp x, ieee754sp y) 270 + static inline int ieee754sp_le(ieee754sp x, ieee754sp y) 252 271 { 253 272 return ieee754sp_cmp(x, y, IEEE754_CLT | IEEE754_CEQ, 0); 254 273 } 255 274 256 - static __inline int ieee754sp_gt(ieee754sp x, ieee754sp y) 275 + static inline int ieee754sp_gt(ieee754sp x, ieee754sp y) 257 276 { 258 277 return ieee754sp_cmp(x, y, IEEE754_CGT, 0); 259 278 } 260 279 261 280 262 - static __inline int ieee754sp_ge(ieee754sp x, ieee754sp y) 281 + static inline int ieee754sp_ge(ieee754sp x, ieee754sp y) 263 282 { 264 283 return ieee754sp_cmp(x, y, IEEE754_CGT | IEEE754_CEQ, 0); 265 284 } 266 285 267 - static __inline int ieee754dp_eq(ieee754dp x, ieee754dp y) 286 + static inline int ieee754dp_eq(ieee754dp x, ieee754dp y) 268 287 { 269 288 return ieee754dp_cmp(x, y, IEEE754_CEQ, 0); 270 289 } 271 290 272 - static __inline int ieee754dp_ne(ieee754dp x, ieee754dp y) 291 + static inline int ieee754dp_ne(ieee754dp x, ieee754dp y) 273 292 { 274 293 return ieee754dp_cmp(x, y, 275 294 IEEE754_CLT | IEEE754_CGT | IEEE754_CUN, 0); 276 295 } 277 296 278 - static __inline int ieee754dp_lt(ieee754dp x, ieee754dp y) 297 + static inline int ieee754dp_lt(ieee754dp x, ieee754dp y) 279 298 { 280 299 return ieee754dp_cmp(x, y, IEEE754_CLT, 0); 281 300 } 282 301 283 - static __inline int ieee754dp_le(ieee754dp x, ieee754dp y) 302 + static inline int ieee754dp_le(ieee754dp x, ieee754dp y) 284 303 { 285 304 return ieee754dp_cmp(x, y, IEEE754_CLT | IEEE754_CEQ, 0); 286 305 } 287 306 288 - static __inline int ieee754dp_gt(ieee754dp x, ieee754dp y) 307 + static inline int ieee754dp_gt(ieee754dp x, ieee754dp y) 289 308 { 290 309 return ieee754dp_cmp(x, y, IEEE754_CGT, 0); 291 310 } 292 311 293 - static __inline int ieee754dp_ge(ieee754dp x, ieee754dp y) 312 + static inline int ieee754dp_ge(ieee754dp x, ieee754dp y) 294 313 { 295 314 return ieee754dp_cmp(x, y, IEEE754_CGT | IEEE754_CEQ, 0); 296 315 } 297 316 298 317 299 - /* like strtod 300 - */ 318 + /* 319 + * Like strtod 320 + */ 301 321 ieee754dp ieee754dp_fstr(const char *s, char **endp); 302 322 char *ieee754dp_tstr(ieee754dp x, int prec, int fmt, int af); 303 323 304 324 305 - /* the control status register 306 - */ 307 - struct ieee754_csr { 308 - unsigned pad:13; 325 + /* 326 + * The control status register 327 + */ 328 + struct _ieee754_csr { 329 + #ifdef __BIG_ENDIAN 330 + unsigned pad0:7; 309 331 unsigned nod:1; /* set 1 for no denormalised numbers */ 310 - unsigned cx:5; /* exceptions this operation */ 332 + unsigned c:1; /* condition */ 333 + unsigned pad1:5; 334 + unsigned cx:6; /* exceptions this operation */ 311 335 unsigned mx:5; /* exception enable mask */ 312 336 unsigned sx:5; /* exceptions total */ 313 337 unsigned rm:2; /* current rounding mode */ 338 + #endif 339 + #ifdef __LITTLE_ENDIAN 340 + unsigned rm:2; /* current rounding mode */ 341 + unsigned sx:5; /* exceptions total */ 342 + unsigned mx:5; /* exception enable mask */ 343 + unsigned cx:6; /* exceptions this operation */ 344 + unsigned pad1:5; 345 + unsigned c:1; /* condition */ 346 + unsigned nod:1; /* set 1 for no denormalised numbers */ 347 + unsigned pad0:7; 348 + #endif 314 349 }; 315 - extern struct ieee754_csr ieee754_csr; 350 + #define ieee754_csr (*(struct _ieee754_csr *)(&current->thread.fpu.soft.fcr31)) 316 351 317 - static __inline unsigned ieee754_getrm(void) 352 + static inline unsigned ieee754_getrm(void) 318 353 { 319 354 return (ieee754_csr.rm); 320 355 } 321 - static __inline unsigned ieee754_setrm(unsigned rm) 356 + static inline unsigned ieee754_setrm(unsigned rm) 322 357 { 323 358 return (ieee754_csr.rm = rm); 324 359 } ··· 342 345 /* 343 346 * get current exceptions 344 347 */ 345 - static __inline unsigned ieee754_getcx(void) 348 + static inline unsigned ieee754_getcx(void) 346 349 { 347 350 return (ieee754_csr.cx); 348 351 } 349 352 350 353 /* test for current exception condition 351 354 */ 352 - static __inline int ieee754_cxtest(unsigned n) 355 + static inline int ieee754_cxtest(unsigned n) 353 356 { 354 357 return (ieee754_csr.cx & n); 355 358 } ··· 357 360 /* 358 361 * get sticky exceptions 359 362 */ 360 - static __inline unsigned ieee754_getsx(void) 363 + static inline unsigned ieee754_getsx(void) 361 364 { 362 365 return (ieee754_csr.sx); 363 366 } 364 367 365 368 /* clear sticky conditions 366 369 */ 367 - static __inline unsigned ieee754_clrsx(void) 370 + static inline unsigned ieee754_clrsx(void) 368 371 { 369 372 return (ieee754_csr.sx = 0); 370 373 } 371 374 372 375 /* test for sticky exception condition 373 376 */ 374 - static __inline int ieee754_sxtest(unsigned n) 377 + static inline int ieee754_sxtest(unsigned n) 375 378 { 376 379 return (ieee754_csr.sx & n); 377 380 } ··· 403 406 #define ieee754dp_spcvals ((const ieee754dp *)__ieee754dp_spcvals) 404 407 #define ieee754sp_spcvals ((const ieee754sp *)__ieee754sp_spcvals) 405 408 406 - /* return infinity with given sign 407 - */ 408 - #define ieee754dp_inf(sn) \ 409 - (ieee754dp_spcvals[IEEE754_SPCVAL_PINFINITY+(sn)]) 410 - #define ieee754dp_zero(sn) \ 411 - (ieee754dp_spcvals[IEEE754_SPCVAL_PZERO+(sn)]) 412 - #define ieee754dp_one(sn) \ 413 - (ieee754dp_spcvals[IEEE754_SPCVAL_PONE+(sn)]) 414 - #define ieee754dp_ten(sn) \ 415 - (ieee754dp_spcvals[IEEE754_SPCVAL_PTEN+(sn)]) 416 - #define ieee754dp_indef() \ 417 - (ieee754dp_spcvals[IEEE754_SPCVAL_INDEF]) 418 - #define ieee754dp_max(sn) \ 419 - (ieee754dp_spcvals[IEEE754_SPCVAL_PMAX+(sn)]) 420 - #define ieee754dp_min(sn) \ 421 - (ieee754dp_spcvals[IEEE754_SPCVAL_PMIN+(sn)]) 422 - #define ieee754dp_mind(sn) \ 423 - (ieee754dp_spcvals[IEEE754_SPCVAL_PMIND+(sn)]) 424 - #define ieee754dp_1e31() \ 425 - (ieee754dp_spcvals[IEEE754_SPCVAL_P1E31]) 426 - #define ieee754dp_1e63() \ 427 - (ieee754dp_spcvals[IEEE754_SPCVAL_P1E63]) 409 + /* 410 + * Return infinity with given sign 411 + */ 412 + #define ieee754dp_inf(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PINFINITY+(sn)]) 413 + #define ieee754dp_zero(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PZERO+(sn)]) 414 + #define ieee754dp_one(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PONE+(sn)]) 415 + #define ieee754dp_ten(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PTEN+(sn)]) 416 + #define ieee754dp_indef() (ieee754dp_spcvals[IEEE754_SPCVAL_INDEF]) 417 + #define ieee754dp_max(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PMAX+(sn)]) 418 + #define ieee754dp_min(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PMIN+(sn)]) 419 + #define ieee754dp_mind(sn) (ieee754dp_spcvals[IEEE754_SPCVAL_PMIND+(sn)]) 420 + #define ieee754dp_1e31() (ieee754dp_spcvals[IEEE754_SPCVAL_P1E31]) 421 + #define ieee754dp_1e63() (ieee754dp_spcvals[IEEE754_SPCVAL_P1E63]) 428 422 429 - #define ieee754sp_inf(sn) \ 430 - (ieee754sp_spcvals[IEEE754_SPCVAL_PINFINITY+(sn)]) 431 - #define ieee754sp_zero(sn) \ 432 - (ieee754sp_spcvals[IEEE754_SPCVAL_PZERO+(sn)]) 433 - #define ieee754sp_one(sn) \ 434 - (ieee754sp_spcvals[IEEE754_SPCVAL_PONE+(sn)]) 435 - #define ieee754sp_ten(sn) \ 436 - (ieee754sp_spcvals[IEEE754_SPCVAL_PTEN+(sn)]) 437 - #define ieee754sp_indef() \ 438 - (ieee754sp_spcvals[IEEE754_SPCVAL_INDEF]) 439 - #define ieee754sp_max(sn) \ 440 - (ieee754sp_spcvals[IEEE754_SPCVAL_PMAX+(sn)]) 441 - #define ieee754sp_min(sn) \ 442 - (ieee754sp_spcvals[IEEE754_SPCVAL_PMIN+(sn)]) 443 - #define ieee754sp_mind(sn) \ 444 - (ieee754sp_spcvals[IEEE754_SPCVAL_PMIND+(sn)]) 445 - #define ieee754sp_1e31() \ 446 - (ieee754sp_spcvals[IEEE754_SPCVAL_P1E31]) 447 - #define ieee754sp_1e63() \ 448 - (ieee754sp_spcvals[IEEE754_SPCVAL_P1E63]) 423 + #define ieee754sp_inf(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PINFINITY+(sn)]) 424 + #define ieee754sp_zero(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PZERO+(sn)]) 425 + #define ieee754sp_one(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PONE+(sn)]) 426 + #define ieee754sp_ten(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PTEN+(sn)]) 427 + #define ieee754sp_indef() (ieee754sp_spcvals[IEEE754_SPCVAL_INDEF]) 428 + #define ieee754sp_max(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PMAX+(sn)]) 429 + #define ieee754sp_min(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PMIN+(sn)]) 430 + #define ieee754sp_mind(sn) (ieee754sp_spcvals[IEEE754_SPCVAL_PMIND+(sn)]) 431 + #define ieee754sp_1e31() (ieee754sp_spcvals[IEEE754_SPCVAL_P1E31]) 432 + #define ieee754sp_1e63() (ieee754sp_spcvals[IEEE754_SPCVAL_P1E63]) 449 433 450 - /* indefinite integer value 451 - */ 434 + /* 435 + * Indefinite integer value 436 + */ 452 437 #define ieee754si_indef() INT_MAX 453 438 #ifdef LONG_LONG_MAX 454 439 #define ieee754di_indef() LONG_LONG_MAX