diff options
Diffstat (limited to 'arch/powerpc/math-emu')
-rw-r--r-- | arch/powerpc/math-emu/Makefile | 2 | ||||
-rw-r--r-- | arch/powerpc/math-emu/math_efp.c | 65 |
2 files changed, 61 insertions, 6 deletions
diff --git a/arch/powerpc/math-emu/Makefile b/arch/powerpc/math-emu/Makefile index 0c16ab947f1f..7d1dba0d57f9 100644 --- a/arch/powerpc/math-emu/Makefile +++ b/arch/powerpc/math-emu/Makefile | |||
@@ -15,4 +15,4 @@ obj-$(CONFIG_SPE) += math_efp.o | |||
15 | CFLAGS_fabs.o = -fno-builtin-fabs | 15 | CFLAGS_fabs.o = -fno-builtin-fabs |
16 | CFLAGS_math.o = -fno-builtin-fabs | 16 | CFLAGS_math.o = -fno-builtin-fabs |
17 | 17 | ||
18 | EXTRA_CFLAGS = -I. -Iinclude/math-emu -w | 18 | ccflags-y = -I. -Iinclude/math-emu -w |
diff --git a/arch/powerpc/math-emu/math_efp.c b/arch/powerpc/math-emu/math_efp.c index 41f4ef30e480..62279200d965 100644 --- a/arch/powerpc/math-emu/math_efp.c +++ b/arch/powerpc/math-emu/math_efp.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * arch/powerpc/math-emu/math_efp.c | 2 | * arch/powerpc/math-emu/math_efp.c |
3 | * | 3 | * |
4 | * Copyright (C) 2006-2008 Freescale Semiconductor, Inc. All rights reserved. | 4 | * Copyright (C) 2006-2008, 2010 Freescale Semiconductor, Inc. |
5 | * | 5 | * |
6 | * Author: Ebony Zhu, <ebony.zhu@freescale.com> | 6 | * Author: Ebony Zhu, <ebony.zhu@freescale.com> |
7 | * Yu Liu, <yu.liu@freescale.com> | 7 | * Yu Liu, <yu.liu@freescale.com> |
@@ -104,6 +104,8 @@ | |||
104 | #define FP_EX_MASK (FP_EX_INEXACT | FP_EX_INVALID | FP_EX_DIVZERO | \ | 104 | #define FP_EX_MASK (FP_EX_INEXACT | FP_EX_INVALID | FP_EX_DIVZERO | \ |
105 | FP_EX_UNDERFLOW | FP_EX_OVERFLOW) | 105 | FP_EX_UNDERFLOW | FP_EX_OVERFLOW) |
106 | 106 | ||
107 | static int have_e500_cpu_a005_erratum; | ||
108 | |||
107 | union dw_union { | 109 | union dw_union { |
108 | u64 dp[1]; | 110 | u64 dp[1]; |
109 | u32 wp[2]; | 111 | u32 wp[2]; |
@@ -320,7 +322,8 @@ int do_spe_mathemu(struct pt_regs *regs) | |||
320 | } else { | 322 | } else { |
321 | _FP_ROUND_ZERO(1, SB); | 323 | _FP_ROUND_ZERO(1, SB); |
322 | } | 324 | } |
323 | FP_TO_INT_S(vc.wp[1], SB, 32, ((func & 0x3) != 0)); | 325 | FP_TO_INT_S(vc.wp[1], SB, 32, |
326 | (((func & 0x3) != 0) || SB_s)); | ||
324 | goto update_regs; | 327 | goto update_regs; |
325 | 328 | ||
326 | default: | 329 | default: |
@@ -458,7 +461,8 @@ cmp_s: | |||
458 | } else { | 461 | } else { |
459 | _FP_ROUND_ZERO(2, DB); | 462 | _FP_ROUND_ZERO(2, DB); |
460 | } | 463 | } |
461 | FP_TO_INT_D(vc.wp[1], DB, 32, ((func & 0x3) != 0)); | 464 | FP_TO_INT_D(vc.wp[1], DB, 32, |
465 | (((func & 0x3) != 0) || DB_s)); | ||
462 | goto update_regs; | 466 | goto update_regs; |
463 | 467 | ||
464 | default: | 468 | default: |
@@ -589,8 +593,10 @@ cmp_d: | |||
589 | _FP_ROUND_ZERO(1, SB0); | 593 | _FP_ROUND_ZERO(1, SB0); |
590 | _FP_ROUND_ZERO(1, SB1); | 594 | _FP_ROUND_ZERO(1, SB1); |
591 | } | 595 | } |
592 | FP_TO_INT_S(vc.wp[0], SB0, 32, ((func & 0x3) != 0)); | 596 | FP_TO_INT_S(vc.wp[0], SB0, 32, |
593 | FP_TO_INT_S(vc.wp[1], SB1, 32, ((func & 0x3) != 0)); | 597 | (((func & 0x3) != 0) || SB0_s)); |
598 | FP_TO_INT_S(vc.wp[1], SB1, 32, | ||
599 | (((func & 0x3) != 0) || SB1_s)); | ||
594 | goto update_regs; | 600 | goto update_regs; |
595 | 601 | ||
596 | default: | 602 | default: |
@@ -652,6 +658,15 @@ update_regs: | |||
652 | return 0; | 658 | return 0; |
653 | 659 | ||
654 | illegal: | 660 | illegal: |
661 | if (have_e500_cpu_a005_erratum) { | ||
662 | /* according to e500 cpu a005 erratum, reissue efp inst */ | ||
663 | regs->nip -= 4; | ||
664 | #ifdef DEBUG | ||
665 | printk(KERN_DEBUG "re-issue efp inst: %08lx\n", speinsn); | ||
666 | #endif | ||
667 | return 0; | ||
668 | } | ||
669 | |||
655 | printk(KERN_ERR "\nOoops! IEEE-754 compliance handler encountered un-supported instruction.\ninst code: %08lx\n", speinsn); | 670 | printk(KERN_ERR "\nOoops! IEEE-754 compliance handler encountered un-supported instruction.\ninst code: %08lx\n", speinsn); |
656 | return -ENOSYS; | 671 | return -ENOSYS; |
657 | } | 672 | } |
@@ -718,3 +733,43 @@ int speround_handler(struct pt_regs *regs) | |||
718 | 733 | ||
719 | return 0; | 734 | return 0; |
720 | } | 735 | } |
736 | |||
737 | int __init spe_mathemu_init(void) | ||
738 | { | ||
739 | u32 pvr, maj, min; | ||
740 | |||
741 | pvr = mfspr(SPRN_PVR); | ||
742 | |||
743 | if ((PVR_VER(pvr) == PVR_VER_E500V1) || | ||
744 | (PVR_VER(pvr) == PVR_VER_E500V2)) { | ||
745 | maj = PVR_MAJ(pvr); | ||
746 | min = PVR_MIN(pvr); | ||
747 | |||
748 | /* | ||
749 | * E500 revision below 1.1, 2.3, 3.1, 4.1, 5.1 | ||
750 | * need cpu a005 errata workaround | ||
751 | */ | ||
752 | switch (maj) { | ||
753 | case 1: | ||
754 | if (min < 1) | ||
755 | have_e500_cpu_a005_erratum = 1; | ||
756 | break; | ||
757 | case 2: | ||
758 | if (min < 3) | ||
759 | have_e500_cpu_a005_erratum = 1; | ||
760 | break; | ||
761 | case 3: | ||
762 | case 4: | ||
763 | case 5: | ||
764 | if (min < 1) | ||
765 | have_e500_cpu_a005_erratum = 1; | ||
766 | break; | ||
767 | default: | ||
768 | break; | ||
769 | } | ||
770 | } | ||
771 | |||
772 | return 0; | ||
773 | } | ||
774 | |||
775 | module_init(spe_mathemu_init); | ||