diff options
Diffstat (limited to 'arch/powerpc/math-emu/math_efp.c')
| -rw-r--r-- | arch/powerpc/math-emu/math_efp.c | 65 | 
1 files changed, 60 insertions, 5 deletions
diff --git a/arch/powerpc/math-emu/math_efp.c b/arch/powerpc/math-emu/math_efp.c index 41f4ef30e48..62279200d96 100644 --- a/arch/powerpc/math-emu/math_efp.c +++ b/arch/powerpc/math-emu/math_efp.c @@ -1,7 +1,7 @@  /*   * arch/powerpc/math-emu/math_efp.c   * - * Copyright (C) 2006-2008 Freescale Semiconductor, Inc. All rights reserved. + * Copyright (C) 2006-2008, 2010 Freescale Semiconductor, Inc.   *   * Author: Ebony Zhu,	<ebony.zhu@freescale.com>   *         Yu Liu,	<yu.liu@freescale.com> @@ -104,6 +104,8 @@  #define FP_EX_MASK	(FP_EX_INEXACT | FP_EX_INVALID | FP_EX_DIVZERO | \  			FP_EX_UNDERFLOW | FP_EX_OVERFLOW) +static int have_e500_cpu_a005_erratum; +  union dw_union {  	u64 dp[1];  	u32 wp[2]; @@ -320,7 +322,8 @@ int do_spe_mathemu(struct pt_regs *regs)  			} else {  				_FP_ROUND_ZERO(1, SB);  			} -			FP_TO_INT_S(vc.wp[1], SB, 32, ((func & 0x3) != 0)); +			FP_TO_INT_S(vc.wp[1], SB, 32, +					(((func & 0x3) != 0) || SB_s));  			goto update_regs;  		default: @@ -458,7 +461,8 @@ cmp_s:  			} else {  				_FP_ROUND_ZERO(2, DB);  			} -			FP_TO_INT_D(vc.wp[1], DB, 32, ((func & 0x3) != 0)); +			FP_TO_INT_D(vc.wp[1], DB, 32, +					(((func & 0x3) != 0) || DB_s));  			goto update_regs;  		default: @@ -589,8 +593,10 @@ cmp_d:  				_FP_ROUND_ZERO(1, SB0);  				_FP_ROUND_ZERO(1, SB1);  			} -			FP_TO_INT_S(vc.wp[0], SB0, 32, ((func & 0x3) != 0)); -			FP_TO_INT_S(vc.wp[1], SB1, 32, ((func & 0x3) != 0)); +			FP_TO_INT_S(vc.wp[0], SB0, 32, +					(((func & 0x3) != 0) || SB0_s)); +			FP_TO_INT_S(vc.wp[1], SB1, 32, +					(((func & 0x3) != 0) || SB1_s));  			goto update_regs;  		default: @@ -652,6 +658,15 @@ update_regs:  	return 0;  illegal: +	if (have_e500_cpu_a005_erratum) { +		/* according to e500 cpu a005 erratum, reissue efp inst */ +		regs->nip -= 4; +#ifdef DEBUG +		printk(KERN_DEBUG "re-issue efp inst: %08lx\n", speinsn); +#endif +		return 0; +	} +  	printk(KERN_ERR "\nOoops! IEEE-754 compliance handler encountered un-supported instruction.\ninst code: %08lx\n", speinsn);  	return -ENOSYS;  } @@ -718,3 +733,43 @@ int speround_handler(struct pt_regs *regs)  	return 0;  } + +int __init spe_mathemu_init(void) +{ +	u32 pvr, maj, min; + +	pvr = mfspr(SPRN_PVR); + +	if ((PVR_VER(pvr) == PVR_VER_E500V1) || +	    (PVR_VER(pvr) == PVR_VER_E500V2)) { +		maj = PVR_MAJ(pvr); +		min = PVR_MIN(pvr); + +		/* +		 * E500 revision below 1.1, 2.3, 3.1, 4.1, 5.1 +		 * need cpu a005 errata workaround +		 */ +		switch (maj) { +		case 1: +			if (min < 1) +				have_e500_cpu_a005_erratum = 1; +			break; +		case 2: +			if (min < 3) +				have_e500_cpu_a005_erratum = 1; +			break; +		case 3: +		case 4: +		case 5: +			if (min < 1) +				have_e500_cpu_a005_erratum = 1; +			break; +		default: +			break; +		} +	} + +	return 0; +} + +module_init(spe_mathemu_init);  |