Path: blob/master/arch/powerpc/math-emu/math_efp.c
10817 views
/*1* arch/powerpc/math-emu/math_efp.c2*3* Copyright (C) 2006-2008, 2010 Freescale Semiconductor, Inc.4*5* Author: Ebony Zhu, <[email protected]>6* Yu Liu, <[email protected]>7*8* Derived from arch/alpha/math-emu/math.c9* arch/powerpc/math-emu/math.c10*11* Description:12* This file is the exception handler to make E500 SPE instructions13* fully comply with IEEE-754 floating point standard.14*15* This program is free software; you can redistribute it and/or16* modify it under the terms of the GNU General Public License17* as published by the Free Software Foundation; either version18* 2 of the License, or (at your option) any later version.19*/2021#include <linux/types.h>2223#include <asm/uaccess.h>24#include <asm/reg.h>2526#define FP_EX_BOOKE_E500_SPE27#include <asm/sfp-machine.h>2829#include <math-emu/soft-fp.h>30#include <math-emu/single.h>31#include <math-emu/double.h>3233#define EFAPU 0x43435#define VCT 0x436#define SPFP 0x637#define DPFP 0x73839#define EFSADD 0x2c040#define EFSSUB 0x2c141#define EFSABS 0x2c442#define EFSNABS 0x2c543#define EFSNEG 0x2c644#define EFSMUL 0x2c845#define EFSDIV 0x2c946#define EFSCMPGT 0x2cc47#define EFSCMPLT 0x2cd48#define EFSCMPEQ 0x2ce49#define EFSCFD 0x2cf50#define EFSCFSI 0x2d151#define EFSCTUI 0x2d452#define EFSCTSI 0x2d553#define EFSCTUF 0x2d654#define EFSCTSF 0x2d755#define EFSCTUIZ 0x2d856#define EFSCTSIZ 0x2da5758#define EVFSADD 0x28059#define EVFSSUB 0x28160#define EVFSABS 0x28461#define EVFSNABS 0x28562#define EVFSNEG 0x28663#define EVFSMUL 0x28864#define EVFSDIV 0x28965#define EVFSCMPGT 0x28c66#define EVFSCMPLT 0x28d67#define EVFSCMPEQ 0x28e68#define EVFSCTUI 0x29469#define EVFSCTSI 0x29570#define EVFSCTUF 0x29671#define EVFSCTSF 0x29772#define EVFSCTUIZ 0x29873#define EVFSCTSIZ 0x29a7475#define EFDADD 0x2e076#define EFDSUB 0x2e177#define EFDABS 0x2e478#define EFDNABS 0x2e579#define EFDNEG 0x2e680#define EFDMUL 0x2e881#define EFDDIV 0x2e982#define EFDCTUIDZ 0x2ea83#define EFDCTSIDZ 0x2eb84#define EFDCMPGT 0x2ec85#define EFDCMPLT 0x2ed86#define EFDCMPEQ 0x2ee87#define EFDCFS 0x2ef88#define EFDCTUI 0x2f489#define EFDCTSI 0x2f590#define EFDCTUF 0x2f691#define EFDCTSF 0x2f792#define EFDCTUIZ 0x2f893#define EFDCTSIZ 0x2fa9495#define AB 296#define XA 397#define XB 498#define XCR 599#define NOTYPE 0100101#define SIGN_BIT_S (1UL << 31)102#define SIGN_BIT_D (1ULL << 63)103#define FP_EX_MASK (FP_EX_INEXACT | FP_EX_INVALID | FP_EX_DIVZERO | \104FP_EX_UNDERFLOW | FP_EX_OVERFLOW)105106static int have_e500_cpu_a005_erratum;107108union dw_union {109u64 dp[1];110u32 wp[2];111};112113static unsigned long insn_type(unsigned long speinsn)114{115unsigned long ret = NOTYPE;116117switch (speinsn & 0x7ff) {118case EFSABS: ret = XA; break;119case EFSADD: ret = AB; break;120case EFSCFD: ret = XB; break;121case EFSCMPEQ: ret = XCR; break;122case EFSCMPGT: ret = XCR; break;123case EFSCMPLT: ret = XCR; break;124case EFSCTSF: ret = XB; break;125case EFSCTSI: ret = XB; break;126case EFSCTSIZ: ret = XB; break;127case EFSCTUF: ret = XB; break;128case EFSCTUI: ret = XB; break;129case EFSCTUIZ: ret = XB; break;130case EFSDIV: ret = AB; break;131case EFSMUL: ret = AB; break;132case EFSNABS: ret = XA; break;133case EFSNEG: ret = XA; break;134case EFSSUB: ret = AB; break;135case EFSCFSI: ret = XB; break;136137case EVFSABS: ret = XA; break;138case EVFSADD: ret = AB; break;139case EVFSCMPEQ: ret = XCR; break;140case EVFSCMPGT: ret = XCR; break;141case EVFSCMPLT: ret = XCR; break;142case EVFSCTSF: ret = XB; break;143case EVFSCTSI: ret = XB; break;144case EVFSCTSIZ: ret = XB; break;145case EVFSCTUF: ret = XB; break;146case EVFSCTUI: ret = XB; break;147case EVFSCTUIZ: ret = XB; break;148case EVFSDIV: ret = AB; break;149case EVFSMUL: ret = AB; break;150case EVFSNABS: ret = XA; break;151case EVFSNEG: ret = XA; break;152case EVFSSUB: ret = AB; break;153154case EFDABS: ret = XA; break;155case EFDADD: ret = AB; break;156case EFDCFS: ret = XB; break;157case EFDCMPEQ: ret = XCR; break;158case EFDCMPGT: ret = XCR; break;159case EFDCMPLT: ret = XCR; break;160case EFDCTSF: ret = XB; break;161case EFDCTSI: ret = XB; break;162case EFDCTSIDZ: ret = XB; break;163case EFDCTSIZ: ret = XB; break;164case EFDCTUF: ret = XB; break;165case EFDCTUI: ret = XB; break;166case EFDCTUIDZ: ret = XB; break;167case EFDCTUIZ: ret = XB; break;168case EFDDIV: ret = AB; break;169case EFDMUL: ret = AB; break;170case EFDNABS: ret = XA; break;171case EFDNEG: ret = XA; break;172case EFDSUB: ret = AB; break;173174default:175printk(KERN_ERR "\nOoops! SPE instruction no type found.");176printk(KERN_ERR "\ninst code: %08lx\n", speinsn);177}178179return ret;180}181182int do_spe_mathemu(struct pt_regs *regs)183{184FP_DECL_EX;185int IR, cmp;186187unsigned long type, func, fc, fa, fb, src, speinsn;188union dw_union vc, va, vb;189190if (get_user(speinsn, (unsigned int __user *) regs->nip))191return -EFAULT;192if ((speinsn >> 26) != EFAPU)193return -EINVAL; /* not an spe instruction */194195type = insn_type(speinsn);196if (type == NOTYPE)197return -ENOSYS;198199func = speinsn & 0x7ff;200fc = (speinsn >> 21) & 0x1f;201fa = (speinsn >> 16) & 0x1f;202fb = (speinsn >> 11) & 0x1f;203src = (speinsn >> 5) & 0x7;204205vc.wp[0] = current->thread.evr[fc];206vc.wp[1] = regs->gpr[fc];207va.wp[0] = current->thread.evr[fa];208va.wp[1] = regs->gpr[fa];209vb.wp[0] = current->thread.evr[fb];210vb.wp[1] = regs->gpr[fb];211212__FPU_FPSCR = mfspr(SPRN_SPEFSCR);213214#ifdef DEBUG215printk("speinsn:%08lx spefscr:%08lx\n", speinsn, __FPU_FPSCR);216printk("vc: %08x %08x\n", vc.wp[0], vc.wp[1]);217printk("va: %08x %08x\n", va.wp[0], va.wp[1]);218printk("vb: %08x %08x\n", vb.wp[0], vb.wp[1]);219#endif220221switch (src) {222case SPFP: {223FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);224225switch (type) {226case AB:227case XCR:228FP_UNPACK_SP(SA, va.wp + 1);229case XB:230FP_UNPACK_SP(SB, vb.wp + 1);231break;232case XA:233FP_UNPACK_SP(SA, va.wp + 1);234break;235}236237#ifdef DEBUG238printk("SA: %ld %08lx %ld (%ld)\n", SA_s, SA_f, SA_e, SA_c);239printk("SB: %ld %08lx %ld (%ld)\n", SB_s, SB_f, SB_e, SB_c);240#endif241242switch (func) {243case EFSABS:244vc.wp[1] = va.wp[1] & ~SIGN_BIT_S;245goto update_regs;246247case EFSNABS:248vc.wp[1] = va.wp[1] | SIGN_BIT_S;249goto update_regs;250251case EFSNEG:252vc.wp[1] = va.wp[1] ^ SIGN_BIT_S;253goto update_regs;254255case EFSADD:256FP_ADD_S(SR, SA, SB);257goto pack_s;258259case EFSSUB:260FP_SUB_S(SR, SA, SB);261goto pack_s;262263case EFSMUL:264FP_MUL_S(SR, SA, SB);265goto pack_s;266267case EFSDIV:268FP_DIV_S(SR, SA, SB);269goto pack_s;270271case EFSCMPEQ:272cmp = 0;273goto cmp_s;274275case EFSCMPGT:276cmp = 1;277goto cmp_s;278279case EFSCMPLT:280cmp = -1;281goto cmp_s;282283case EFSCTSF:284case EFSCTUF:285if (!((vb.wp[1] >> 23) == 0xff && ((vb.wp[1] & 0x7fffff) > 0))) {286/* NaN */287if (((vb.wp[1] >> 23) & 0xff) == 0) {288/* denorm */289vc.wp[1] = 0x0;290} else if ((vb.wp[1] >> 31) == 0) {291/* positive normal */292vc.wp[1] = (func == EFSCTSF) ?2930x7fffffff : 0xffffffff;294} else { /* negative normal */295vc.wp[1] = (func == EFSCTSF) ?2960x80000000 : 0x0;297}298} else { /* rB is NaN */299vc.wp[1] = 0x0;300}301goto update_regs;302303case EFSCFD: {304FP_DECL_D(DB);305FP_CLEAR_EXCEPTIONS;306FP_UNPACK_DP(DB, vb.dp);307#ifdef DEBUG308printk("DB: %ld %08lx %08lx %ld (%ld)\n",309DB_s, DB_f1, DB_f0, DB_e, DB_c);310#endif311FP_CONV(S, D, 1, 2, SR, DB);312goto pack_s;313}314315case EFSCTSI:316case EFSCTSIZ:317case EFSCTUI:318case EFSCTUIZ:319if (func & 0x4) {320_FP_ROUND(1, SB);321} else {322_FP_ROUND_ZERO(1, SB);323}324FP_TO_INT_S(vc.wp[1], SB, 32,325(((func & 0x3) != 0) || SB_s));326goto update_regs;327328default:329goto illegal;330}331break;332333pack_s:334#ifdef DEBUG335printk("SR: %ld %08lx %ld (%ld)\n", SR_s, SR_f, SR_e, SR_c);336#endif337FP_PACK_SP(vc.wp + 1, SR);338goto update_regs;339340cmp_s:341FP_CMP_S(IR, SA, SB, 3);342if (IR == 3 && (FP_ISSIGNAN_S(SA) || FP_ISSIGNAN_S(SB)))343FP_SET_EXCEPTION(FP_EX_INVALID);344if (IR == cmp) {345IR = 0x4;346} else {347IR = 0;348}349goto update_ccr;350}351352case DPFP: {353FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);354355switch (type) {356case AB:357case XCR:358FP_UNPACK_DP(DA, va.dp);359case XB:360FP_UNPACK_DP(DB, vb.dp);361break;362case XA:363FP_UNPACK_DP(DA, va.dp);364break;365}366367#ifdef DEBUG368printk("DA: %ld %08lx %08lx %ld (%ld)\n",369DA_s, DA_f1, DA_f0, DA_e, DA_c);370printk("DB: %ld %08lx %08lx %ld (%ld)\n",371DB_s, DB_f1, DB_f0, DB_e, DB_c);372#endif373374switch (func) {375case EFDABS:376vc.dp[0] = va.dp[0] & ~SIGN_BIT_D;377goto update_regs;378379case EFDNABS:380vc.dp[0] = va.dp[0] | SIGN_BIT_D;381goto update_regs;382383case EFDNEG:384vc.dp[0] = va.dp[0] ^ SIGN_BIT_D;385goto update_regs;386387case EFDADD:388FP_ADD_D(DR, DA, DB);389goto pack_d;390391case EFDSUB:392FP_SUB_D(DR, DA, DB);393goto pack_d;394395case EFDMUL:396FP_MUL_D(DR, DA, DB);397goto pack_d;398399case EFDDIV:400FP_DIV_D(DR, DA, DB);401goto pack_d;402403case EFDCMPEQ:404cmp = 0;405goto cmp_d;406407case EFDCMPGT:408cmp = 1;409goto cmp_d;410411case EFDCMPLT:412cmp = -1;413goto cmp_d;414415case EFDCTSF:416case EFDCTUF:417if (!((vb.wp[0] >> 20) == 0x7ff &&418((vb.wp[0] & 0xfffff) > 0 || (vb.wp[1] > 0)))) {419/* not a NaN */420if (((vb.wp[0] >> 20) & 0x7ff) == 0) {421/* denorm */422vc.wp[1] = 0x0;423} else if ((vb.wp[0] >> 31) == 0) {424/* positive normal */425vc.wp[1] = (func == EFDCTSF) ?4260x7fffffff : 0xffffffff;427} else { /* negative normal */428vc.wp[1] = (func == EFDCTSF) ?4290x80000000 : 0x0;430}431} else { /* NaN */432vc.wp[1] = 0x0;433}434goto update_regs;435436case EFDCFS: {437FP_DECL_S(SB);438FP_CLEAR_EXCEPTIONS;439FP_UNPACK_SP(SB, vb.wp + 1);440#ifdef DEBUG441printk("SB: %ld %08lx %ld (%ld)\n",442SB_s, SB_f, SB_e, SB_c);443#endif444FP_CONV(D, S, 2, 1, DR, SB);445goto pack_d;446}447448case EFDCTUIDZ:449case EFDCTSIDZ:450_FP_ROUND_ZERO(2, DB);451FP_TO_INT_D(vc.dp[0], DB, 64, ((func & 0x1) == 0));452goto update_regs;453454case EFDCTUI:455case EFDCTSI:456case EFDCTUIZ:457case EFDCTSIZ:458if (func & 0x4) {459_FP_ROUND(2, DB);460} else {461_FP_ROUND_ZERO(2, DB);462}463FP_TO_INT_D(vc.wp[1], DB, 32,464(((func & 0x3) != 0) || DB_s));465goto update_regs;466467default:468goto illegal;469}470break;471472pack_d:473#ifdef DEBUG474printk("DR: %ld %08lx %08lx %ld (%ld)\n",475DR_s, DR_f1, DR_f0, DR_e, DR_c);476#endif477FP_PACK_DP(vc.dp, DR);478goto update_regs;479480cmp_d:481FP_CMP_D(IR, DA, DB, 3);482if (IR == 3 && (FP_ISSIGNAN_D(DA) || FP_ISSIGNAN_D(DB)))483FP_SET_EXCEPTION(FP_EX_INVALID);484if (IR == cmp) {485IR = 0x4;486} else {487IR = 0;488}489goto update_ccr;490491}492493case VCT: {494FP_DECL_S(SA0); FP_DECL_S(SB0); FP_DECL_S(SR0);495FP_DECL_S(SA1); FP_DECL_S(SB1); FP_DECL_S(SR1);496int IR0, IR1;497498switch (type) {499case AB:500case XCR:501FP_UNPACK_SP(SA0, va.wp);502FP_UNPACK_SP(SA1, va.wp + 1);503case XB:504FP_UNPACK_SP(SB0, vb.wp);505FP_UNPACK_SP(SB1, vb.wp + 1);506break;507case XA:508FP_UNPACK_SP(SA0, va.wp);509FP_UNPACK_SP(SA1, va.wp + 1);510break;511}512513#ifdef DEBUG514printk("SA0: %ld %08lx %ld (%ld)\n", SA0_s, SA0_f, SA0_e, SA0_c);515printk("SA1: %ld %08lx %ld (%ld)\n", SA1_s, SA1_f, SA1_e, SA1_c);516printk("SB0: %ld %08lx %ld (%ld)\n", SB0_s, SB0_f, SB0_e, SB0_c);517printk("SB1: %ld %08lx %ld (%ld)\n", SB1_s, SB1_f, SB1_e, SB1_c);518#endif519520switch (func) {521case EVFSABS:522vc.wp[0] = va.wp[0] & ~SIGN_BIT_S;523vc.wp[1] = va.wp[1] & ~SIGN_BIT_S;524goto update_regs;525526case EVFSNABS:527vc.wp[0] = va.wp[0] | SIGN_BIT_S;528vc.wp[1] = va.wp[1] | SIGN_BIT_S;529goto update_regs;530531case EVFSNEG:532vc.wp[0] = va.wp[0] ^ SIGN_BIT_S;533vc.wp[1] = va.wp[1] ^ SIGN_BIT_S;534goto update_regs;535536case EVFSADD:537FP_ADD_S(SR0, SA0, SB0);538FP_ADD_S(SR1, SA1, SB1);539goto pack_vs;540541case EVFSSUB:542FP_SUB_S(SR0, SA0, SB0);543FP_SUB_S(SR1, SA1, SB1);544goto pack_vs;545546case EVFSMUL:547FP_MUL_S(SR0, SA0, SB0);548FP_MUL_S(SR1, SA1, SB1);549goto pack_vs;550551case EVFSDIV:552FP_DIV_S(SR0, SA0, SB0);553FP_DIV_S(SR1, SA1, SB1);554goto pack_vs;555556case EVFSCMPEQ:557cmp = 0;558goto cmp_vs;559560case EVFSCMPGT:561cmp = 1;562goto cmp_vs;563564case EVFSCMPLT:565cmp = -1;566goto cmp_vs;567568case EVFSCTSF:569__asm__ __volatile__ ("mtspr 512, %4\n"570"efsctsf %0, %2\n"571"efsctsf %1, %3\n"572: "=r" (vc.wp[0]), "=r" (vc.wp[1])573: "r" (vb.wp[0]), "r" (vb.wp[1]), "r" (0));574goto update_regs;575576case EVFSCTUF:577__asm__ __volatile__ ("mtspr 512, %4\n"578"efsctuf %0, %2\n"579"efsctuf %1, %3\n"580: "=r" (vc.wp[0]), "=r" (vc.wp[1])581: "r" (vb.wp[0]), "r" (vb.wp[1]), "r" (0));582goto update_regs;583584case EVFSCTUI:585case EVFSCTSI:586case EVFSCTUIZ:587case EVFSCTSIZ:588if (func & 0x4) {589_FP_ROUND(1, SB0);590_FP_ROUND(1, SB1);591} else {592_FP_ROUND_ZERO(1, SB0);593_FP_ROUND_ZERO(1, SB1);594}595FP_TO_INT_S(vc.wp[0], SB0, 32,596(((func & 0x3) != 0) || SB0_s));597FP_TO_INT_S(vc.wp[1], SB1, 32,598(((func & 0x3) != 0) || SB1_s));599goto update_regs;600601default:602goto illegal;603}604break;605606pack_vs:607#ifdef DEBUG608printk("SR0: %ld %08lx %ld (%ld)\n", SR0_s, SR0_f, SR0_e, SR0_c);609printk("SR1: %ld %08lx %ld (%ld)\n", SR1_s, SR1_f, SR1_e, SR1_c);610#endif611FP_PACK_SP(vc.wp, SR0);612FP_PACK_SP(vc.wp + 1, SR1);613goto update_regs;614615cmp_vs:616{617int ch, cl;618619FP_CMP_S(IR0, SA0, SB0, 3);620FP_CMP_S(IR1, SA1, SB1, 3);621if (IR0 == 3 && (FP_ISSIGNAN_S(SA0) || FP_ISSIGNAN_S(SB0)))622FP_SET_EXCEPTION(FP_EX_INVALID);623if (IR1 == 3 && (FP_ISSIGNAN_S(SA1) || FP_ISSIGNAN_S(SB1)))624FP_SET_EXCEPTION(FP_EX_INVALID);625ch = (IR0 == cmp) ? 1 : 0;626cl = (IR1 == cmp) ? 1 : 0;627IR = (ch << 3) | (cl << 2) | ((ch | cl) << 1) |628((ch & cl) << 0);629goto update_ccr;630}631}632default:633return -EINVAL;634}635636update_ccr:637regs->ccr &= ~(15 << ((7 - ((speinsn >> 23) & 0x7)) << 2));638regs->ccr |= (IR << ((7 - ((speinsn >> 23) & 0x7)) << 2));639640update_regs:641__FPU_FPSCR &= ~FP_EX_MASK;642__FPU_FPSCR |= (FP_CUR_EXCEPTIONS & FP_EX_MASK);643mtspr(SPRN_SPEFSCR, __FPU_FPSCR);644645current->thread.evr[fc] = vc.wp[0];646regs->gpr[fc] = vc.wp[1];647648#ifdef DEBUG649printk("ccr = %08lx\n", regs->ccr);650printk("cur exceptions = %08x spefscr = %08lx\n",651FP_CUR_EXCEPTIONS, __FPU_FPSCR);652printk("vc: %08x %08x\n", vc.wp[0], vc.wp[1]);653printk("va: %08x %08x\n", va.wp[0], va.wp[1]);654printk("vb: %08x %08x\n", vb.wp[0], vb.wp[1]);655#endif656657return 0;658659illegal:660if (have_e500_cpu_a005_erratum) {661/* according to e500 cpu a005 erratum, reissue efp inst */662regs->nip -= 4;663#ifdef DEBUG664printk(KERN_DEBUG "re-issue efp inst: %08lx\n", speinsn);665#endif666return 0;667}668669printk(KERN_ERR "\nOoops! IEEE-754 compliance handler encountered un-supported instruction.\ninst code: %08lx\n", speinsn);670return -ENOSYS;671}672673int speround_handler(struct pt_regs *regs)674{675union dw_union fgpr;676int s_lo, s_hi;677unsigned long speinsn, type, fc;678679if (get_user(speinsn, (unsigned int __user *) regs->nip))680return -EFAULT;681if ((speinsn >> 26) != 4)682return -EINVAL; /* not an spe instruction */683684type = insn_type(speinsn & 0x7ff);685if (type == XCR) return -ENOSYS;686687fc = (speinsn >> 21) & 0x1f;688s_lo = regs->gpr[fc] & SIGN_BIT_S;689s_hi = current->thread.evr[fc] & SIGN_BIT_S;690fgpr.wp[0] = current->thread.evr[fc];691fgpr.wp[1] = regs->gpr[fc];692693__FPU_FPSCR = mfspr(SPRN_SPEFSCR);694695switch ((speinsn >> 5) & 0x7) {696/* Since SPE instructions on E500 core can handle round to nearest697* and round toward zero with IEEE-754 complied, we just need698* to handle round toward +Inf and round toward -Inf by software.699*/700case SPFP:701if ((FP_ROUNDMODE) == FP_RND_PINF) {702if (!s_lo) fgpr.wp[1]++; /* Z > 0, choose Z1 */703} else { /* round to -Inf */704if (s_lo) fgpr.wp[1]++; /* Z < 0, choose Z2 */705}706break;707708case DPFP:709if (FP_ROUNDMODE == FP_RND_PINF) {710if (!s_hi) fgpr.dp[0]++; /* Z > 0, choose Z1 */711} else { /* round to -Inf */712if (s_hi) fgpr.dp[0]++; /* Z < 0, choose Z2 */713}714break;715716case VCT:717if (FP_ROUNDMODE == FP_RND_PINF) {718if (!s_lo) fgpr.wp[1]++; /* Z_low > 0, choose Z1 */719if (!s_hi) fgpr.wp[0]++; /* Z_high word > 0, choose Z1 */720} else { /* round to -Inf */721if (s_lo) fgpr.wp[1]++; /* Z_low < 0, choose Z2 */722if (s_hi) fgpr.wp[0]++; /* Z_high < 0, choose Z2 */723}724break;725726default:727return -EINVAL;728}729730current->thread.evr[fc] = fgpr.wp[0];731regs->gpr[fc] = fgpr.wp[1];732733return 0;734}735736int __init spe_mathemu_init(void)737{738u32 pvr, maj, min;739740pvr = mfspr(SPRN_PVR);741742if ((PVR_VER(pvr) == PVR_VER_E500V1) ||743(PVR_VER(pvr) == PVR_VER_E500V2)) {744maj = PVR_MAJ(pvr);745min = PVR_MIN(pvr);746747/*748* E500 revision below 1.1, 2.3, 3.1, 4.1, 5.1749* need cpu a005 errata workaround750*/751switch (maj) {752case 1:753if (min < 1)754have_e500_cpu_a005_erratum = 1;755break;756case 2:757if (min < 3)758have_e500_cpu_a005_erratum = 1;759break;760case 3:761case 4:762case 5:763if (min < 1)764have_e500_cpu_a005_erratum = 1;765break;766default:767break;768}769}770771return 0;772}773774module_init(spe_mathemu_init);775776777