diff options
Diffstat (limited to 'arch/sh/kernel/cpu/sh2a/fpu.c')
-rw-r--r-- | arch/sh/kernel/cpu/sh2a/fpu.c | 111 |
1 files changed, 23 insertions, 88 deletions
diff --git a/arch/sh/kernel/cpu/sh2a/fpu.c b/arch/sh/kernel/cpu/sh2a/fpu.c index d395ce5740e7..488d24e0cdf0 100644 --- a/arch/sh/kernel/cpu/sh2a/fpu.c +++ b/arch/sh/kernel/cpu/sh2a/fpu.c | |||
@@ -26,8 +26,7 @@ | |||
26 | /* | 26 | /* |
27 | * Save FPU registers onto task structure. | 27 | * Save FPU registers onto task structure. |
28 | */ | 28 | */ |
29 | void | 29 | void save_fpu(struct task_struct *tsk) |
30 | save_fpu(struct task_struct *tsk) | ||
31 | { | 30 | { |
32 | unsigned long dummy; | 31 | unsigned long dummy; |
33 | 32 | ||
@@ -52,7 +51,7 @@ save_fpu(struct task_struct *tsk) | |||
52 | "fmov.s fr0, @-%0\n\t" | 51 | "fmov.s fr0, @-%0\n\t" |
53 | "lds %3, fpscr\n\t" | 52 | "lds %3, fpscr\n\t" |
54 | : "=r" (dummy) | 53 | : "=r" (dummy) |
55 | : "0" ((char *)(&tsk->thread.fpu.hard.status)), | 54 | : "0" ((char *)(&tsk->thread.xstate->hardfpu.status)), |
56 | "r" (FPSCR_RCHG), | 55 | "r" (FPSCR_RCHG), |
57 | "r" (FPSCR_INIT) | 56 | "r" (FPSCR_INIT) |
58 | : "memory"); | 57 | : "memory"); |
@@ -60,8 +59,7 @@ save_fpu(struct task_struct *tsk) | |||
60 | disable_fpu(); | 59 | disable_fpu(); |
61 | } | 60 | } |
62 | 61 | ||
63 | static void | 62 | void restore_fpu(struct task_struct *tsk) |
64 | restore_fpu(struct task_struct *tsk) | ||
65 | { | 63 | { |
66 | unsigned long dummy; | 64 | unsigned long dummy; |
67 | 65 | ||
@@ -85,45 +83,12 @@ restore_fpu(struct task_struct *tsk) | |||
85 | "lds.l @%0+, fpscr\n\t" | 83 | "lds.l @%0+, fpscr\n\t" |
86 | "lds.l @%0+, fpul\n\t" | 84 | "lds.l @%0+, fpul\n\t" |
87 | : "=r" (dummy) | 85 | : "=r" (dummy) |
88 | : "0" (&tsk->thread.fpu), "r" (FPSCR_RCHG) | 86 | : "0" (tsk->thread.xstate), "r" (FPSCR_RCHG) |
89 | : "memory"); | 87 | : "memory"); |
90 | disable_fpu(); | 88 | disable_fpu(); |
91 | } | 89 | } |
92 | 90 | ||
93 | /* | 91 | /* |
94 | * Load the FPU with signalling NANS. This bit pattern we're using | ||
95 | * has the property that no matter wether considered as single or as | ||
96 | * double precission represents signaling NANS. | ||
97 | */ | ||
98 | |||
99 | static void | ||
100 | fpu_init(void) | ||
101 | { | ||
102 | enable_fpu(); | ||
103 | asm volatile("lds %0, fpul\n\t" | ||
104 | "fsts fpul, fr0\n\t" | ||
105 | "fsts fpul, fr1\n\t" | ||
106 | "fsts fpul, fr2\n\t" | ||
107 | "fsts fpul, fr3\n\t" | ||
108 | "fsts fpul, fr4\n\t" | ||
109 | "fsts fpul, fr5\n\t" | ||
110 | "fsts fpul, fr6\n\t" | ||
111 | "fsts fpul, fr7\n\t" | ||
112 | "fsts fpul, fr8\n\t" | ||
113 | "fsts fpul, fr9\n\t" | ||
114 | "fsts fpul, fr10\n\t" | ||
115 | "fsts fpul, fr11\n\t" | ||
116 | "fsts fpul, fr12\n\t" | ||
117 | "fsts fpul, fr13\n\t" | ||
118 | "fsts fpul, fr14\n\t" | ||
119 | "fsts fpul, fr15\n\t" | ||
120 | "lds %2, fpscr\n\t" | ||
121 | : /* no output */ | ||
122 | : "r" (0), "r" (FPSCR_RCHG), "r" (FPSCR_INIT)); | ||
123 | disable_fpu(); | ||
124 | } | ||
125 | |||
126 | /* | ||
127 | * Emulate arithmetic ops on denormalized number for some FPU insns. | 92 | * Emulate arithmetic ops on denormalized number for some FPU insns. |
128 | */ | 93 | */ |
129 | 94 | ||
@@ -490,9 +455,9 @@ ieee_fpe_handler (struct pt_regs *regs) | |||
490 | if ((finsn & 0xf1ff) == 0xf0ad) { /* fcnvsd */ | 455 | if ((finsn & 0xf1ff) == 0xf0ad) { /* fcnvsd */ |
491 | struct task_struct *tsk = current; | 456 | struct task_struct *tsk = current; |
492 | 457 | ||
493 | if ((tsk->thread.fpu.hard.fpscr & FPSCR_FPU_ERROR)) { | 458 | if ((tsk->thread.xstate->hardfpu.fpscr & FPSCR_FPU_ERROR)) { |
494 | /* FPU error */ | 459 | /* FPU error */ |
495 | denormal_to_double (&tsk->thread.fpu.hard, | 460 | denormal_to_double (&tsk->thread.xstate->hardfpu, |
496 | (finsn >> 8) & 0xf); | 461 | (finsn >> 8) & 0xf); |
497 | } else | 462 | } else |
498 | return 0; | 463 | return 0; |
@@ -507,9 +472,9 @@ ieee_fpe_handler (struct pt_regs *regs) | |||
507 | 472 | ||
508 | n = (finsn >> 8) & 0xf; | 473 | n = (finsn >> 8) & 0xf; |
509 | m = (finsn >> 4) & 0xf; | 474 | m = (finsn >> 4) & 0xf; |
510 | hx = tsk->thread.fpu.hard.fp_regs[n]; | 475 | hx = tsk->thread.xstate->hardfpu.fp_regs[n]; |
511 | hy = tsk->thread.fpu.hard.fp_regs[m]; | 476 | hy = tsk->thread.xstate->hardfpu.fp_regs[m]; |
512 | fpscr = tsk->thread.fpu.hard.fpscr; | 477 | fpscr = tsk->thread.xstate->hardfpu.fpscr; |
513 | prec = fpscr & (1 << 19); | 478 | prec = fpscr & (1 << 19); |
514 | 479 | ||
515 | if ((fpscr & FPSCR_FPU_ERROR) | 480 | if ((fpscr & FPSCR_FPU_ERROR) |
@@ -519,15 +484,15 @@ ieee_fpe_handler (struct pt_regs *regs) | |||
519 | 484 | ||
520 | /* FPU error because of denormal */ | 485 | /* FPU error because of denormal */ |
521 | llx = ((long long) hx << 32) | 486 | llx = ((long long) hx << 32) |
522 | | tsk->thread.fpu.hard.fp_regs[n+1]; | 487 | | tsk->thread.xstate->hardfpu.fp_regs[n+1]; |
523 | lly = ((long long) hy << 32) | 488 | lly = ((long long) hy << 32) |
524 | | tsk->thread.fpu.hard.fp_regs[m+1]; | 489 | | tsk->thread.xstate->hardfpu.fp_regs[m+1]; |
525 | if ((hx & 0x7fffffff) >= 0x00100000) | 490 | if ((hx & 0x7fffffff) >= 0x00100000) |
526 | llx = denormal_muld(lly, llx); | 491 | llx = denormal_muld(lly, llx); |
527 | else | 492 | else |
528 | llx = denormal_muld(llx, lly); | 493 | llx = denormal_muld(llx, lly); |
529 | tsk->thread.fpu.hard.fp_regs[n] = llx >> 32; | 494 | tsk->thread.xstate->hardfpu.fp_regs[n] = llx >> 32; |
530 | tsk->thread.fpu.hard.fp_regs[n+1] = llx & 0xffffffff; | 495 | tsk->thread.xstate->hardfpu.fp_regs[n+1] = llx & 0xffffffff; |
531 | } else if ((fpscr & FPSCR_FPU_ERROR) | 496 | } else if ((fpscr & FPSCR_FPU_ERROR) |
532 | && (!prec && ((hx & 0x7fffffff) < 0x00800000 | 497 | && (!prec && ((hx & 0x7fffffff) < 0x00800000 |
533 | || (hy & 0x7fffffff) < 0x00800000))) { | 498 | || (hy & 0x7fffffff) < 0x00800000))) { |
@@ -536,7 +501,7 @@ ieee_fpe_handler (struct pt_regs *regs) | |||
536 | hx = denormal_mulf(hy, hx); | 501 | hx = denormal_mulf(hy, hx); |
537 | else | 502 | else |
538 | hx = denormal_mulf(hx, hy); | 503 | hx = denormal_mulf(hx, hy); |
539 | tsk->thread.fpu.hard.fp_regs[n] = hx; | 504 | tsk->thread.xstate->hardfpu.fp_regs[n] = hx; |
540 | } else | 505 | } else |
541 | return 0; | 506 | return 0; |
542 | 507 | ||
@@ -550,9 +515,9 @@ ieee_fpe_handler (struct pt_regs *regs) | |||
550 | 515 | ||
551 | n = (finsn >> 8) & 0xf; | 516 | n = (finsn >> 8) & 0xf; |
552 | m = (finsn >> 4) & 0xf; | 517 | m = (finsn >> 4) & 0xf; |
553 | hx = tsk->thread.fpu.hard.fp_regs[n]; | 518 | hx = tsk->thread.xstate->hardfpu.fp_regs[n]; |
554 | hy = tsk->thread.fpu.hard.fp_regs[m]; | 519 | hy = tsk->thread.xstate->hardfpu.fp_regs[m]; |
555 | fpscr = tsk->thread.fpu.hard.fpscr; | 520 | fpscr = tsk->thread.xstate->hardfpu.fpscr; |
556 | prec = fpscr & (1 << 19); | 521 | prec = fpscr & (1 << 19); |
557 | 522 | ||
558 | if ((fpscr & FPSCR_FPU_ERROR) | 523 | if ((fpscr & FPSCR_FPU_ERROR) |
@@ -562,15 +527,15 @@ ieee_fpe_handler (struct pt_regs *regs) | |||
562 | 527 | ||
563 | /* FPU error because of denormal */ | 528 | /* FPU error because of denormal */ |
564 | llx = ((long long) hx << 32) | 529 | llx = ((long long) hx << 32) |
565 | | tsk->thread.fpu.hard.fp_regs[n+1]; | 530 | | tsk->thread.xstate->hardfpu.fp_regs[n+1]; |
566 | lly = ((long long) hy << 32) | 531 | lly = ((long long) hy << 32) |
567 | | tsk->thread.fpu.hard.fp_regs[m+1]; | 532 | | tsk->thread.xstate->hardfpu.fp_regs[m+1]; |
568 | if ((finsn & 0xf00f) == 0xf000) | 533 | if ((finsn & 0xf00f) == 0xf000) |
569 | llx = denormal_addd(llx, lly); | 534 | llx = denormal_addd(llx, lly); |
570 | else | 535 | else |
571 | llx = denormal_addd(llx, lly ^ (1LL << 63)); | 536 | llx = denormal_addd(llx, lly ^ (1LL << 63)); |
572 | tsk->thread.fpu.hard.fp_regs[n] = llx >> 32; | 537 | tsk->thread.xstate->hardfpu.fp_regs[n] = llx >> 32; |
573 | tsk->thread.fpu.hard.fp_regs[n+1] = llx & 0xffffffff; | 538 | tsk->thread.xstate->hardfpu.fp_regs[n+1] = llx & 0xffffffff; |
574 | } else if ((fpscr & FPSCR_FPU_ERROR) | 539 | } else if ((fpscr & FPSCR_FPU_ERROR) |
575 | && (!prec && ((hx & 0x7fffffff) < 0x00800000 | 540 | && (!prec && ((hx & 0x7fffffff) < 0x00800000 |
576 | || (hy & 0x7fffffff) < 0x00800000))) { | 541 | || (hy & 0x7fffffff) < 0x00800000))) { |
@@ -579,7 +544,7 @@ ieee_fpe_handler (struct pt_regs *regs) | |||
579 | hx = denormal_addf(hx, hy); | 544 | hx = denormal_addf(hx, hy); |
580 | else | 545 | else |
581 | hx = denormal_addf(hx, hy ^ 0x80000000); | 546 | hx = denormal_addf(hx, hy ^ 0x80000000); |
582 | tsk->thread.fpu.hard.fp_regs[n] = hx; | 547 | tsk->thread.xstate->hardfpu.fp_regs[n] = hx; |
583 | } else | 548 | } else |
584 | return 0; | 549 | return 0; |
585 | 550 | ||
@@ -597,7 +562,7 @@ BUILD_TRAP_HANDLER(fpu_error) | |||
597 | 562 | ||
598 | __unlazy_fpu(tsk, regs); | 563 | __unlazy_fpu(tsk, regs); |
599 | if (ieee_fpe_handler(regs)) { | 564 | if (ieee_fpe_handler(regs)) { |
600 | tsk->thread.fpu.hard.fpscr &= | 565 | tsk->thread.xstate->hardfpu.fpscr &= |
601 | ~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK); | 566 | ~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK); |
602 | grab_fpu(regs); | 567 | grab_fpu(regs); |
603 | restore_fpu(tsk); | 568 | restore_fpu(tsk); |
@@ -607,33 +572,3 @@ BUILD_TRAP_HANDLER(fpu_error) | |||
607 | 572 | ||
608 | force_sig(SIGFPE, tsk); | 573 | force_sig(SIGFPE, tsk); |
609 | } | 574 | } |
610 | |||
611 | void fpu_state_restore(struct pt_regs *regs) | ||
612 | { | ||
613 | struct task_struct *tsk = current; | ||
614 | |||
615 | grab_fpu(regs); | ||
616 | if (unlikely(!user_mode(regs))) { | ||
617 | printk(KERN_ERR "BUG: FPU is used in kernel mode.\n"); | ||
618 | BUG(); | ||
619 | return; | ||
620 | } | ||
621 | |||
622 | if (likely(used_math())) { | ||
623 | /* Using the FPU again. */ | ||
624 | restore_fpu(tsk); | ||
625 | } else { | ||
626 | /* First time FPU user. */ | ||
627 | fpu_init(); | ||
628 | set_used_math(); | ||
629 | } | ||
630 | task_thread_info(tsk)->status |= TS_USEDFPU; | ||
631 | tsk->fpu_counter++; | ||
632 | } | ||
633 | |||
634 | BUILD_TRAP_HANDLER(fpu_state_restore) | ||
635 | { | ||
636 | TRAP_HANDLER_DECL; | ||
637 | |||
638 | fpu_state_restore(regs); | ||
639 | } | ||