Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * arch/powerpc/math-emu/math_efp.c
0004  *
0005  * Copyright (C) 2006-2008, 2010 Freescale Semiconductor, Inc.
0006  *
0007  * Author: Ebony Zhu,   <ebony.zhu@freescale.com>
0008  *         Yu Liu,  <yu.liu@freescale.com>
0009  *
0010  * Derived from arch/alpha/math-emu/math.c
0011  *              arch/powerpc/math-emu/math.c
0012  *
0013  * Description:
0014  * This file is the exception handler to make E500 SPE instructions
0015  * fully comply with IEEE-754 floating point standard.
0016  */
0017 
0018 #include <linux/types.h>
0019 #include <linux/prctl.h>
0020 
0021 #include <linux/uaccess.h>
0022 #include <asm/reg.h>
0023 
0024 #define FP_EX_BOOKE_E500_SPE
0025 #include <asm/sfp-machine.h>
0026 
0027 #include <math-emu/soft-fp.h>
0028 #include <math-emu/single.h>
0029 #include <math-emu/double.h>
0030 
0031 #define EFAPU       0x4
0032 
0033 #define VCT     0x4
0034 #define SPFP        0x6
0035 #define DPFP        0x7
0036 
0037 #define EFSADD      0x2c0
0038 #define EFSSUB      0x2c1
0039 #define EFSABS      0x2c4
0040 #define EFSNABS     0x2c5
0041 #define EFSNEG      0x2c6
0042 #define EFSMUL      0x2c8
0043 #define EFSDIV      0x2c9
0044 #define EFSCMPGT    0x2cc
0045 #define EFSCMPLT    0x2cd
0046 #define EFSCMPEQ    0x2ce
0047 #define EFSCFD      0x2cf
0048 #define EFSCFSI     0x2d1
0049 #define EFSCTUI     0x2d4
0050 #define EFSCTSI     0x2d5
0051 #define EFSCTUF     0x2d6
0052 #define EFSCTSF     0x2d7
0053 #define EFSCTUIZ    0x2d8
0054 #define EFSCTSIZ    0x2da
0055 
0056 #define EVFSADD     0x280
0057 #define EVFSSUB     0x281
0058 #define EVFSABS     0x284
0059 #define EVFSNABS    0x285
0060 #define EVFSNEG     0x286
0061 #define EVFSMUL     0x288
0062 #define EVFSDIV     0x289
0063 #define EVFSCMPGT   0x28c
0064 #define EVFSCMPLT   0x28d
0065 #define EVFSCMPEQ   0x28e
0066 #define EVFSCTUI    0x294
0067 #define EVFSCTSI    0x295
0068 #define EVFSCTUF    0x296
0069 #define EVFSCTSF    0x297
0070 #define EVFSCTUIZ   0x298
0071 #define EVFSCTSIZ   0x29a
0072 
0073 #define EFDADD      0x2e0
0074 #define EFDSUB      0x2e1
0075 #define EFDABS      0x2e4
0076 #define EFDNABS     0x2e5
0077 #define EFDNEG      0x2e6
0078 #define EFDMUL      0x2e8
0079 #define EFDDIV      0x2e9
0080 #define EFDCTUIDZ   0x2ea
0081 #define EFDCTSIDZ   0x2eb
0082 #define EFDCMPGT    0x2ec
0083 #define EFDCMPLT    0x2ed
0084 #define EFDCMPEQ    0x2ee
0085 #define EFDCFS      0x2ef
0086 #define EFDCTUI     0x2f4
0087 #define EFDCTSI     0x2f5
0088 #define EFDCTUF     0x2f6
0089 #define EFDCTSF     0x2f7
0090 #define EFDCTUIZ    0x2f8
0091 #define EFDCTSIZ    0x2fa
0092 
0093 #define AB  2
0094 #define XA  3
0095 #define XB  4
0096 #define XCR 5
0097 #define NOTYPE  0
0098 
0099 #define SIGN_BIT_S  (1UL << 31)
0100 #define SIGN_BIT_D  (1ULL << 63)
0101 #define FP_EX_MASK  (FP_EX_INEXACT | FP_EX_INVALID | FP_EX_DIVZERO | \
0102             FP_EX_UNDERFLOW | FP_EX_OVERFLOW)
0103 
0104 static int have_e500_cpu_a005_erratum;
0105 
0106 union dw_union {
0107     u64 dp[1];
0108     u32 wp[2];
0109 };
0110 
0111 static unsigned long insn_type(unsigned long speinsn)
0112 {
0113     unsigned long ret = NOTYPE;
0114 
0115     switch (speinsn & 0x7ff) {
0116     case EFSABS:    ret = XA;   break;
0117     case EFSADD:    ret = AB;   break;
0118     case EFSCFD:    ret = XB;   break;
0119     case EFSCMPEQ:  ret = XCR;  break;
0120     case EFSCMPGT:  ret = XCR;  break;
0121     case EFSCMPLT:  ret = XCR;  break;
0122     case EFSCTSF:   ret = XB;   break;
0123     case EFSCTSI:   ret = XB;   break;
0124     case EFSCTSIZ:  ret = XB;   break;
0125     case EFSCTUF:   ret = XB;   break;
0126     case EFSCTUI:   ret = XB;   break;
0127     case EFSCTUIZ:  ret = XB;   break;
0128     case EFSDIV:    ret = AB;   break;
0129     case EFSMUL:    ret = AB;   break;
0130     case EFSNABS:   ret = XA;   break;
0131     case EFSNEG:    ret = XA;   break;
0132     case EFSSUB:    ret = AB;   break;
0133     case EFSCFSI:   ret = XB;   break;
0134 
0135     case EVFSABS:   ret = XA;   break;
0136     case EVFSADD:   ret = AB;   break;
0137     case EVFSCMPEQ: ret = XCR;  break;
0138     case EVFSCMPGT: ret = XCR;  break;
0139     case EVFSCMPLT: ret = XCR;  break;
0140     case EVFSCTSF:  ret = XB;   break;
0141     case EVFSCTSI:  ret = XB;   break;
0142     case EVFSCTSIZ: ret = XB;   break;
0143     case EVFSCTUF:  ret = XB;   break;
0144     case EVFSCTUI:  ret = XB;   break;
0145     case EVFSCTUIZ: ret = XB;   break;
0146     case EVFSDIV:   ret = AB;   break;
0147     case EVFSMUL:   ret = AB;   break;
0148     case EVFSNABS:  ret = XA;   break;
0149     case EVFSNEG:   ret = XA;   break;
0150     case EVFSSUB:   ret = AB;   break;
0151 
0152     case EFDABS:    ret = XA;   break;
0153     case EFDADD:    ret = AB;   break;
0154     case EFDCFS:    ret = XB;   break;
0155     case EFDCMPEQ:  ret = XCR;  break;
0156     case EFDCMPGT:  ret = XCR;  break;
0157     case EFDCMPLT:  ret = XCR;  break;
0158     case EFDCTSF:   ret = XB;   break;
0159     case EFDCTSI:   ret = XB;   break;
0160     case EFDCTSIDZ: ret = XB;   break;
0161     case EFDCTSIZ:  ret = XB;   break;
0162     case EFDCTUF:   ret = XB;   break;
0163     case EFDCTUI:   ret = XB;   break;
0164     case EFDCTUIDZ: ret = XB;   break;
0165     case EFDCTUIZ:  ret = XB;   break;
0166     case EFDDIV:    ret = AB;   break;
0167     case EFDMUL:    ret = AB;   break;
0168     case EFDNABS:   ret = XA;   break;
0169     case EFDNEG:    ret = XA;   break;
0170     case EFDSUB:    ret = AB;   break;
0171     }
0172 
0173     return ret;
0174 }
0175 
0176 int do_spe_mathemu(struct pt_regs *regs)
0177 {
0178     FP_DECL_EX;
0179     int IR, cmp;
0180 
0181     unsigned long type, func, fc, fa, fb, src, speinsn;
0182     union dw_union vc, va, vb;
0183 
0184     if (get_user(speinsn, (unsigned int __user *) regs->nip))
0185         return -EFAULT;
0186     if ((speinsn >> 26) != EFAPU)
0187         return -EINVAL;         /* not an spe instruction */
0188 
0189     type = insn_type(speinsn);
0190     if (type == NOTYPE)
0191         goto illegal;
0192 
0193     func = speinsn & 0x7ff;
0194     fc = (speinsn >> 21) & 0x1f;
0195     fa = (speinsn >> 16) & 0x1f;
0196     fb = (speinsn >> 11) & 0x1f;
0197     src = (speinsn >> 5) & 0x7;
0198 
0199     vc.wp[0] = current->thread.evr[fc];
0200     vc.wp[1] = regs->gpr[fc];
0201     va.wp[0] = current->thread.evr[fa];
0202     va.wp[1] = regs->gpr[fa];
0203     vb.wp[0] = current->thread.evr[fb];
0204     vb.wp[1] = regs->gpr[fb];
0205 
0206     __FPU_FPSCR = mfspr(SPRN_SPEFSCR);
0207 
0208     pr_debug("speinsn:%08lx spefscr:%08lx\n", speinsn, __FPU_FPSCR);
0209     pr_debug("vc: %08x  %08x\n", vc.wp[0], vc.wp[1]);
0210     pr_debug("va: %08x  %08x\n", va.wp[0], va.wp[1]);
0211     pr_debug("vb: %08x  %08x\n", vb.wp[0], vb.wp[1]);
0212 
0213     switch (src) {
0214     case SPFP: {
0215         FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
0216 
0217         switch (type) {
0218         case AB:
0219         case XCR:
0220             FP_UNPACK_SP(SA, va.wp + 1);
0221         case XB:
0222             FP_UNPACK_SP(SB, vb.wp + 1);
0223             break;
0224         case XA:
0225             FP_UNPACK_SP(SA, va.wp + 1);
0226             break;
0227         }
0228 
0229         pr_debug("SA: %ld %08lx %ld (%ld)\n", SA_s, SA_f, SA_e, SA_c);
0230         pr_debug("SB: %ld %08lx %ld (%ld)\n", SB_s, SB_f, SB_e, SB_c);
0231 
0232         switch (func) {
0233         case EFSABS:
0234             vc.wp[1] = va.wp[1] & ~SIGN_BIT_S;
0235             goto update_regs;
0236 
0237         case EFSNABS:
0238             vc.wp[1] = va.wp[1] | SIGN_BIT_S;
0239             goto update_regs;
0240 
0241         case EFSNEG:
0242             vc.wp[1] = va.wp[1] ^ SIGN_BIT_S;
0243             goto update_regs;
0244 
0245         case EFSADD:
0246             FP_ADD_S(SR, SA, SB);
0247             goto pack_s;
0248 
0249         case EFSSUB:
0250             FP_SUB_S(SR, SA, SB);
0251             goto pack_s;
0252 
0253         case EFSMUL:
0254             FP_MUL_S(SR, SA, SB);
0255             goto pack_s;
0256 
0257         case EFSDIV:
0258             FP_DIV_S(SR, SA, SB);
0259             goto pack_s;
0260 
0261         case EFSCMPEQ:
0262             cmp = 0;
0263             goto cmp_s;
0264 
0265         case EFSCMPGT:
0266             cmp = 1;
0267             goto cmp_s;
0268 
0269         case EFSCMPLT:
0270             cmp = -1;
0271             goto cmp_s;
0272 
0273         case EFSCTSF:
0274         case EFSCTUF:
0275             if (SB_c == FP_CLS_NAN) {
0276                 vc.wp[1] = 0;
0277                 FP_SET_EXCEPTION(FP_EX_INVALID);
0278             } else {
0279                 SB_e += (func == EFSCTSF ? 31 : 32);
0280                 FP_TO_INT_ROUND_S(vc.wp[1], SB, 32,
0281                         (func == EFSCTSF));
0282             }
0283             goto update_regs;
0284 
0285         case EFSCFD: {
0286             FP_DECL_D(DB);
0287             FP_CLEAR_EXCEPTIONS;
0288             FP_UNPACK_DP(DB, vb.dp);
0289 
0290             pr_debug("DB: %ld %08lx %08lx %ld (%ld)\n",
0291                     DB_s, DB_f1, DB_f0, DB_e, DB_c);
0292 
0293             FP_CONV(S, D, 1, 2, SR, DB);
0294             goto pack_s;
0295         }
0296 
0297         case EFSCTSI:
0298         case EFSCTUI:
0299             if (SB_c == FP_CLS_NAN) {
0300                 vc.wp[1] = 0;
0301                 FP_SET_EXCEPTION(FP_EX_INVALID);
0302             } else {
0303                 FP_TO_INT_ROUND_S(vc.wp[1], SB, 32,
0304                         ((func & 0x3) != 0));
0305             }
0306             goto update_regs;
0307 
0308         case EFSCTSIZ:
0309         case EFSCTUIZ:
0310             if (SB_c == FP_CLS_NAN) {
0311                 vc.wp[1] = 0;
0312                 FP_SET_EXCEPTION(FP_EX_INVALID);
0313             } else {
0314                 FP_TO_INT_S(vc.wp[1], SB, 32,
0315                         ((func & 0x3) != 0));
0316             }
0317             goto update_regs;
0318 
0319         default:
0320             goto illegal;
0321         }
0322         break;
0323 
0324 pack_s:
0325         pr_debug("SR: %ld %08lx %ld (%ld)\n", SR_s, SR_f, SR_e, SR_c);
0326 
0327         FP_PACK_SP(vc.wp + 1, SR);
0328         goto update_regs;
0329 
0330 cmp_s:
0331         FP_CMP_S(IR, SA, SB, 3);
0332         if (IR == 3 && (FP_ISSIGNAN_S(SA) || FP_ISSIGNAN_S(SB)))
0333             FP_SET_EXCEPTION(FP_EX_INVALID);
0334         if (IR == cmp) {
0335             IR = 0x4;
0336         } else {
0337             IR = 0;
0338         }
0339         goto update_ccr;
0340     }
0341 
0342     case DPFP: {
0343         FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
0344 
0345         switch (type) {
0346         case AB:
0347         case XCR:
0348             FP_UNPACK_DP(DA, va.dp);
0349         case XB:
0350             FP_UNPACK_DP(DB, vb.dp);
0351             break;
0352         case XA:
0353             FP_UNPACK_DP(DA, va.dp);
0354             break;
0355         }
0356 
0357         pr_debug("DA: %ld %08lx %08lx %ld (%ld)\n",
0358                 DA_s, DA_f1, DA_f0, DA_e, DA_c);
0359         pr_debug("DB: %ld %08lx %08lx %ld (%ld)\n",
0360                 DB_s, DB_f1, DB_f0, DB_e, DB_c);
0361 
0362         switch (func) {
0363         case EFDABS:
0364             vc.dp[0] = va.dp[0] & ~SIGN_BIT_D;
0365             goto update_regs;
0366 
0367         case EFDNABS:
0368             vc.dp[0] = va.dp[0] | SIGN_BIT_D;
0369             goto update_regs;
0370 
0371         case EFDNEG:
0372             vc.dp[0] = va.dp[0] ^ SIGN_BIT_D;
0373             goto update_regs;
0374 
0375         case EFDADD:
0376             FP_ADD_D(DR, DA, DB);
0377             goto pack_d;
0378 
0379         case EFDSUB:
0380             FP_SUB_D(DR, DA, DB);
0381             goto pack_d;
0382 
0383         case EFDMUL:
0384             FP_MUL_D(DR, DA, DB);
0385             goto pack_d;
0386 
0387         case EFDDIV:
0388             FP_DIV_D(DR, DA, DB);
0389             goto pack_d;
0390 
0391         case EFDCMPEQ:
0392             cmp = 0;
0393             goto cmp_d;
0394 
0395         case EFDCMPGT:
0396             cmp = 1;
0397             goto cmp_d;
0398 
0399         case EFDCMPLT:
0400             cmp = -1;
0401             goto cmp_d;
0402 
0403         case EFDCTSF:
0404         case EFDCTUF:
0405             if (DB_c == FP_CLS_NAN) {
0406                 vc.wp[1] = 0;
0407                 FP_SET_EXCEPTION(FP_EX_INVALID);
0408             } else {
0409                 DB_e += (func == EFDCTSF ? 31 : 32);
0410                 FP_TO_INT_ROUND_D(vc.wp[1], DB, 32,
0411                         (func == EFDCTSF));
0412             }
0413             goto update_regs;
0414 
0415         case EFDCFS: {
0416             FP_DECL_S(SB);
0417             FP_CLEAR_EXCEPTIONS;
0418             FP_UNPACK_SP(SB, vb.wp + 1);
0419 
0420             pr_debug("SB: %ld %08lx %ld (%ld)\n",
0421                     SB_s, SB_f, SB_e, SB_c);
0422 
0423             FP_CONV(D, S, 2, 1, DR, SB);
0424             goto pack_d;
0425         }
0426 
0427         case EFDCTUIDZ:
0428         case EFDCTSIDZ:
0429             if (DB_c == FP_CLS_NAN) {
0430                 vc.dp[0] = 0;
0431                 FP_SET_EXCEPTION(FP_EX_INVALID);
0432             } else {
0433                 FP_TO_INT_D(vc.dp[0], DB, 64,
0434                         ((func & 0x1) == 0));
0435             }
0436             goto update_regs;
0437 
0438         case EFDCTUI:
0439         case EFDCTSI:
0440             if (DB_c == FP_CLS_NAN) {
0441                 vc.wp[1] = 0;
0442                 FP_SET_EXCEPTION(FP_EX_INVALID);
0443             } else {
0444                 FP_TO_INT_ROUND_D(vc.wp[1], DB, 32,
0445                         ((func & 0x3) != 0));
0446             }
0447             goto update_regs;
0448 
0449         case EFDCTUIZ:
0450         case EFDCTSIZ:
0451             if (DB_c == FP_CLS_NAN) {
0452                 vc.wp[1] = 0;
0453                 FP_SET_EXCEPTION(FP_EX_INVALID);
0454             } else {
0455                 FP_TO_INT_D(vc.wp[1], DB, 32,
0456                         ((func & 0x3) != 0));
0457             }
0458             goto update_regs;
0459 
0460         default:
0461             goto illegal;
0462         }
0463         break;
0464 
0465 pack_d:
0466         pr_debug("DR: %ld %08lx %08lx %ld (%ld)\n",
0467                 DR_s, DR_f1, DR_f0, DR_e, DR_c);
0468 
0469         FP_PACK_DP(vc.dp, DR);
0470         goto update_regs;
0471 
0472 cmp_d:
0473         FP_CMP_D(IR, DA, DB, 3);
0474         if (IR == 3 && (FP_ISSIGNAN_D(DA) || FP_ISSIGNAN_D(DB)))
0475             FP_SET_EXCEPTION(FP_EX_INVALID);
0476         if (IR == cmp) {
0477             IR = 0x4;
0478         } else {
0479             IR = 0;
0480         }
0481         goto update_ccr;
0482 
0483     }
0484 
0485     case VCT: {
0486         FP_DECL_S(SA0); FP_DECL_S(SB0); FP_DECL_S(SR0);
0487         FP_DECL_S(SA1); FP_DECL_S(SB1); FP_DECL_S(SR1);
0488         int IR0, IR1;
0489 
0490         switch (type) {
0491         case AB:
0492         case XCR:
0493             FP_UNPACK_SP(SA0, va.wp);
0494             FP_UNPACK_SP(SA1, va.wp + 1);
0495         case XB:
0496             FP_UNPACK_SP(SB0, vb.wp);
0497             FP_UNPACK_SP(SB1, vb.wp + 1);
0498             break;
0499         case XA:
0500             FP_UNPACK_SP(SA0, va.wp);
0501             FP_UNPACK_SP(SA1, va.wp + 1);
0502             break;
0503         }
0504 
0505         pr_debug("SA0: %ld %08lx %ld (%ld)\n",
0506                 SA0_s, SA0_f, SA0_e, SA0_c);
0507         pr_debug("SA1: %ld %08lx %ld (%ld)\n",
0508                 SA1_s, SA1_f, SA1_e, SA1_c);
0509         pr_debug("SB0: %ld %08lx %ld (%ld)\n",
0510                 SB0_s, SB0_f, SB0_e, SB0_c);
0511         pr_debug("SB1: %ld %08lx %ld (%ld)\n",
0512                 SB1_s, SB1_f, SB1_e, SB1_c);
0513 
0514         switch (func) {
0515         case EVFSABS:
0516             vc.wp[0] = va.wp[0] & ~SIGN_BIT_S;
0517             vc.wp[1] = va.wp[1] & ~SIGN_BIT_S;
0518             goto update_regs;
0519 
0520         case EVFSNABS:
0521             vc.wp[0] = va.wp[0] | SIGN_BIT_S;
0522             vc.wp[1] = va.wp[1] | SIGN_BIT_S;
0523             goto update_regs;
0524 
0525         case EVFSNEG:
0526             vc.wp[0] = va.wp[0] ^ SIGN_BIT_S;
0527             vc.wp[1] = va.wp[1] ^ SIGN_BIT_S;
0528             goto update_regs;
0529 
0530         case EVFSADD:
0531             FP_ADD_S(SR0, SA0, SB0);
0532             FP_ADD_S(SR1, SA1, SB1);
0533             goto pack_vs;
0534 
0535         case EVFSSUB:
0536             FP_SUB_S(SR0, SA0, SB0);
0537             FP_SUB_S(SR1, SA1, SB1);
0538             goto pack_vs;
0539 
0540         case EVFSMUL:
0541             FP_MUL_S(SR0, SA0, SB0);
0542             FP_MUL_S(SR1, SA1, SB1);
0543             goto pack_vs;
0544 
0545         case EVFSDIV:
0546             FP_DIV_S(SR0, SA0, SB0);
0547             FP_DIV_S(SR1, SA1, SB1);
0548             goto pack_vs;
0549 
0550         case EVFSCMPEQ:
0551             cmp = 0;
0552             goto cmp_vs;
0553 
0554         case EVFSCMPGT:
0555             cmp = 1;
0556             goto cmp_vs;
0557 
0558         case EVFSCMPLT:
0559             cmp = -1;
0560             goto cmp_vs;
0561 
0562         case EVFSCTUF:
0563         case EVFSCTSF:
0564             if (SB0_c == FP_CLS_NAN) {
0565                 vc.wp[0] = 0;
0566                 FP_SET_EXCEPTION(FP_EX_INVALID);
0567             } else {
0568                 SB0_e += (func == EVFSCTSF ? 31 : 32);
0569                 FP_TO_INT_ROUND_S(vc.wp[0], SB0, 32,
0570                         (func == EVFSCTSF));
0571             }
0572             if (SB1_c == FP_CLS_NAN) {
0573                 vc.wp[1] = 0;
0574                 FP_SET_EXCEPTION(FP_EX_INVALID);
0575             } else {
0576                 SB1_e += (func == EVFSCTSF ? 31 : 32);
0577                 FP_TO_INT_ROUND_S(vc.wp[1], SB1, 32,
0578                         (func == EVFSCTSF));
0579             }
0580             goto update_regs;
0581 
0582         case EVFSCTUI:
0583         case EVFSCTSI:
0584             if (SB0_c == FP_CLS_NAN) {
0585                 vc.wp[0] = 0;
0586                 FP_SET_EXCEPTION(FP_EX_INVALID);
0587             } else {
0588                 FP_TO_INT_ROUND_S(vc.wp[0], SB0, 32,
0589                         ((func & 0x3) != 0));
0590             }
0591             if (SB1_c == FP_CLS_NAN) {
0592                 vc.wp[1] = 0;
0593                 FP_SET_EXCEPTION(FP_EX_INVALID);
0594             } else {
0595                 FP_TO_INT_ROUND_S(vc.wp[1], SB1, 32,
0596                         ((func & 0x3) != 0));
0597             }
0598             goto update_regs;
0599 
0600         case EVFSCTUIZ:
0601         case EVFSCTSIZ:
0602             if (SB0_c == FP_CLS_NAN) {
0603                 vc.wp[0] = 0;
0604                 FP_SET_EXCEPTION(FP_EX_INVALID);
0605             } else {
0606                 FP_TO_INT_S(vc.wp[0], SB0, 32,
0607                         ((func & 0x3) != 0));
0608             }
0609             if (SB1_c == FP_CLS_NAN) {
0610                 vc.wp[1] = 0;
0611                 FP_SET_EXCEPTION(FP_EX_INVALID);
0612             } else {
0613                 FP_TO_INT_S(vc.wp[1], SB1, 32,
0614                         ((func & 0x3) != 0));
0615             }
0616             goto update_regs;
0617 
0618         default:
0619             goto illegal;
0620         }
0621         break;
0622 
0623 pack_vs:
0624         pr_debug("SR0: %ld %08lx %ld (%ld)\n",
0625                 SR0_s, SR0_f, SR0_e, SR0_c);
0626         pr_debug("SR1: %ld %08lx %ld (%ld)\n",
0627                 SR1_s, SR1_f, SR1_e, SR1_c);
0628 
0629         FP_PACK_SP(vc.wp, SR0);
0630         FP_PACK_SP(vc.wp + 1, SR1);
0631         goto update_regs;
0632 
0633 cmp_vs:
0634         {
0635             int ch, cl;
0636 
0637             FP_CMP_S(IR0, SA0, SB0, 3);
0638             FP_CMP_S(IR1, SA1, SB1, 3);
0639             if (IR0 == 3 && (FP_ISSIGNAN_S(SA0) || FP_ISSIGNAN_S(SB0)))
0640                 FP_SET_EXCEPTION(FP_EX_INVALID);
0641             if (IR1 == 3 && (FP_ISSIGNAN_S(SA1) || FP_ISSIGNAN_S(SB1)))
0642                 FP_SET_EXCEPTION(FP_EX_INVALID);
0643             ch = (IR0 == cmp) ? 1 : 0;
0644             cl = (IR1 == cmp) ? 1 : 0;
0645             IR = (ch << 3) | (cl << 2) | ((ch | cl) << 1) |
0646                 ((ch & cl) << 0);
0647             goto update_ccr;
0648         }
0649     }
0650     default:
0651         return -EINVAL;
0652     }
0653 
0654 update_ccr:
0655     regs->ccr &= ~(15 << ((7 - ((speinsn >> 23) & 0x7)) << 2));
0656     regs->ccr |= (IR << ((7 - ((speinsn >> 23) & 0x7)) << 2));
0657 
0658 update_regs:
0659     /*
0660      * If the "invalid" exception sticky bit was set by the
0661      * processor for non-finite input, but was not set before the
0662      * instruction being emulated, clear it.  Likewise for the
0663      * "underflow" bit, which may have been set by the processor
0664      * for exact underflow, not just inexact underflow when the
0665      * flag should be set for IEEE 754 semantics.  Other sticky
0666      * exceptions will only be set by the processor when they are
0667      * correct according to IEEE 754 semantics, and we must not
0668      * clear sticky bits that were already set before the emulated
0669      * instruction as they represent the user-visible sticky
0670      * exception status.  "inexact" traps to kernel are not
0671      * required for IEEE semantics and are not enabled by default,
0672      * so the "inexact" sticky bit may have been set by a previous
0673      * instruction without the kernel being aware of it.
0674      */
0675     __FPU_FPSCR
0676       &= ~(FP_EX_INVALID | FP_EX_UNDERFLOW) | current->thread.spefscr_last;
0677     __FPU_FPSCR |= (FP_CUR_EXCEPTIONS & FP_EX_MASK);
0678     mtspr(SPRN_SPEFSCR, __FPU_FPSCR);
0679     current->thread.spefscr_last = __FPU_FPSCR;
0680 
0681     current->thread.evr[fc] = vc.wp[0];
0682     regs->gpr[fc] = vc.wp[1];
0683 
0684     pr_debug("ccr = %08lx\n", regs->ccr);
0685     pr_debug("cur exceptions = %08x spefscr = %08lx\n",
0686             FP_CUR_EXCEPTIONS, __FPU_FPSCR);
0687     pr_debug("vc: %08x  %08x\n", vc.wp[0], vc.wp[1]);
0688     pr_debug("va: %08x  %08x\n", va.wp[0], va.wp[1]);
0689     pr_debug("vb: %08x  %08x\n", vb.wp[0], vb.wp[1]);
0690 
0691     if (current->thread.fpexc_mode & PR_FP_EXC_SW_ENABLE) {
0692         if ((FP_CUR_EXCEPTIONS & FP_EX_DIVZERO)
0693             && (current->thread.fpexc_mode & PR_FP_EXC_DIV))
0694             return 1;
0695         if ((FP_CUR_EXCEPTIONS & FP_EX_OVERFLOW)
0696             && (current->thread.fpexc_mode & PR_FP_EXC_OVF))
0697             return 1;
0698         if ((FP_CUR_EXCEPTIONS & FP_EX_UNDERFLOW)
0699             && (current->thread.fpexc_mode & PR_FP_EXC_UND))
0700             return 1;
0701         if ((FP_CUR_EXCEPTIONS & FP_EX_INEXACT)
0702             && (current->thread.fpexc_mode & PR_FP_EXC_RES))
0703             return 1;
0704         if ((FP_CUR_EXCEPTIONS & FP_EX_INVALID)
0705             && (current->thread.fpexc_mode & PR_FP_EXC_INV))
0706             return 1;
0707     }
0708     return 0;
0709 
0710 illegal:
0711     if (have_e500_cpu_a005_erratum) {
0712         /* according to e500 cpu a005 erratum, reissue efp inst */
0713         regs_add_return_ip(regs, -4);
0714         pr_debug("re-issue efp inst: %08lx\n", speinsn);
0715         return 0;
0716     }
0717 
0718     printk(KERN_ERR "\nOoops! IEEE-754 compliance handler encountered un-supported instruction.\ninst code: %08lx\n", speinsn);
0719     return -ENOSYS;
0720 }
0721 
0722 int speround_handler(struct pt_regs *regs)
0723 {
0724     union dw_union fgpr;
0725     int s_lo, s_hi;
0726     int lo_inexact, hi_inexact;
0727     int fp_result;
0728     unsigned long speinsn, type, fb, fc, fptype, func;
0729 
0730     if (get_user(speinsn, (unsigned int __user *) regs->nip))
0731         return -EFAULT;
0732     if ((speinsn >> 26) != 4)
0733         return -EINVAL;         /* not an spe instruction */
0734 
0735     func = speinsn & 0x7ff;
0736     type = insn_type(func);
0737     if (type == XCR) return -ENOSYS;
0738 
0739     __FPU_FPSCR = mfspr(SPRN_SPEFSCR);
0740     pr_debug("speinsn:%08lx spefscr:%08lx\n", speinsn, __FPU_FPSCR);
0741 
0742     fptype = (speinsn >> 5) & 0x7;
0743 
0744     /* No need to round if the result is exact */
0745     lo_inexact = __FPU_FPSCR & (SPEFSCR_FG | SPEFSCR_FX);
0746     hi_inexact = __FPU_FPSCR & (SPEFSCR_FGH | SPEFSCR_FXH);
0747     if (!(lo_inexact || (hi_inexact && fptype == VCT)))
0748         return 0;
0749 
0750     fc = (speinsn >> 21) & 0x1f;
0751     s_lo = regs->gpr[fc] & SIGN_BIT_S;
0752     s_hi = current->thread.evr[fc] & SIGN_BIT_S;
0753     fgpr.wp[0] = current->thread.evr[fc];
0754     fgpr.wp[1] = regs->gpr[fc];
0755 
0756     fb = (speinsn >> 11) & 0x1f;
0757     switch (func) {
0758     case EFSCTUIZ:
0759     case EFSCTSIZ:
0760     case EVFSCTUIZ:
0761     case EVFSCTSIZ:
0762     case EFDCTUIDZ:
0763     case EFDCTSIDZ:
0764     case EFDCTUIZ:
0765     case EFDCTSIZ:
0766         /*
0767          * These instructions always round to zero,
0768          * independent of the rounding mode.
0769          */
0770         return 0;
0771 
0772     case EFSCTUI:
0773     case EFSCTUF:
0774     case EVFSCTUI:
0775     case EVFSCTUF:
0776     case EFDCTUI:
0777     case EFDCTUF:
0778         fp_result = 0;
0779         s_lo = 0;
0780         s_hi = 0;
0781         break;
0782 
0783     case EFSCTSI:
0784     case EFSCTSF:
0785         fp_result = 0;
0786         /* Recover the sign of a zero result if possible.  */
0787         if (fgpr.wp[1] == 0)
0788             s_lo = regs->gpr[fb] & SIGN_BIT_S;
0789         break;
0790 
0791     case EVFSCTSI:
0792     case EVFSCTSF:
0793         fp_result = 0;
0794         /* Recover the sign of a zero result if possible.  */
0795         if (fgpr.wp[1] == 0)
0796             s_lo = regs->gpr[fb] & SIGN_BIT_S;
0797         if (fgpr.wp[0] == 0)
0798             s_hi = current->thread.evr[fb] & SIGN_BIT_S;
0799         break;
0800 
0801     case EFDCTSI:
0802     case EFDCTSF:
0803         fp_result = 0;
0804         s_hi = s_lo;
0805         /* Recover the sign of a zero result if possible.  */
0806         if (fgpr.wp[1] == 0)
0807             s_hi = current->thread.evr[fb] & SIGN_BIT_S;
0808         break;
0809 
0810     default:
0811         fp_result = 1;
0812         break;
0813     }
0814 
0815     pr_debug("round fgpr: %08x  %08x\n", fgpr.wp[0], fgpr.wp[1]);
0816 
0817     switch (fptype) {
0818     /* Since SPE instructions on E500 core can handle round to nearest
0819      * and round toward zero with IEEE-754 complied, we just need
0820      * to handle round toward +Inf and round toward -Inf by software.
0821      */
0822     case SPFP:
0823         if ((FP_ROUNDMODE) == FP_RND_PINF) {
0824             if (!s_lo) fgpr.wp[1]++; /* Z > 0, choose Z1 */
0825         } else { /* round to -Inf */
0826             if (s_lo) {
0827                 if (fp_result)
0828                     fgpr.wp[1]++; /* Z < 0, choose Z2 */
0829                 else
0830                     fgpr.wp[1]--; /* Z < 0, choose Z2 */
0831             }
0832         }
0833         break;
0834 
0835     case DPFP:
0836         if (FP_ROUNDMODE == FP_RND_PINF) {
0837             if (!s_hi) {
0838                 if (fp_result)
0839                     fgpr.dp[0]++; /* Z > 0, choose Z1 */
0840                 else
0841                     fgpr.wp[1]++; /* Z > 0, choose Z1 */
0842             }
0843         } else { /* round to -Inf */
0844             if (s_hi) {
0845                 if (fp_result)
0846                     fgpr.dp[0]++; /* Z < 0, choose Z2 */
0847                 else
0848                     fgpr.wp[1]--; /* Z < 0, choose Z2 */
0849             }
0850         }
0851         break;
0852 
0853     case VCT:
0854         if (FP_ROUNDMODE == FP_RND_PINF) {
0855             if (lo_inexact && !s_lo)
0856                 fgpr.wp[1]++; /* Z_low > 0, choose Z1 */
0857             if (hi_inexact && !s_hi)
0858                 fgpr.wp[0]++; /* Z_high word > 0, choose Z1 */
0859         } else { /* round to -Inf */
0860             if (lo_inexact && s_lo) {
0861                 if (fp_result)
0862                     fgpr.wp[1]++; /* Z_low < 0, choose Z2 */
0863                 else
0864                     fgpr.wp[1]--; /* Z_low < 0, choose Z2 */
0865             }
0866             if (hi_inexact && s_hi) {
0867                 if (fp_result)
0868                     fgpr.wp[0]++; /* Z_high < 0, choose Z2 */
0869                 else
0870                     fgpr.wp[0]--; /* Z_high < 0, choose Z2 */
0871             }
0872         }
0873         break;
0874 
0875     default:
0876         return -EINVAL;
0877     }
0878 
0879     current->thread.evr[fc] = fgpr.wp[0];
0880     regs->gpr[fc] = fgpr.wp[1];
0881 
0882     pr_debug("  to fgpr: %08x  %08x\n", fgpr.wp[0], fgpr.wp[1]);
0883 
0884     if (current->thread.fpexc_mode & PR_FP_EXC_SW_ENABLE)
0885         return (current->thread.fpexc_mode & PR_FP_EXC_RES) ? 1 : 0;
0886     return 0;
0887 }
0888 
0889 int __init spe_mathemu_init(void)
0890 {
0891     u32 pvr, maj, min;
0892 
0893     pvr = mfspr(SPRN_PVR);
0894 
0895     if ((PVR_VER(pvr) == PVR_VER_E500V1) ||
0896         (PVR_VER(pvr) == PVR_VER_E500V2)) {
0897         maj = PVR_MAJ(pvr);
0898         min = PVR_MIN(pvr);
0899 
0900         /*
0901          * E500 revision below 1.1, 2.3, 3.1, 4.1, 5.1
0902          * need cpu a005 errata workaround
0903          */
0904         switch (maj) {
0905         case 1:
0906             if (min < 1)
0907                 have_e500_cpu_a005_erratum = 1;
0908             break;
0909         case 2:
0910             if (min < 3)
0911                 have_e500_cpu_a005_erratum = 1;
0912             break;
0913         case 3:
0914         case 4:
0915         case 5:
0916             if (min < 1)
0917                 have_e500_cpu_a005_erratum = 1;
0918             break;
0919         default:
0920             break;
0921         }
0922     }
0923 
0924     return 0;
0925 }
0926 
0927 module_init(spe_mathemu_init);