0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
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;
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
0661
0662
0663
0664
0665
0666
0667
0668
0669
0670
0671
0672
0673
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
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;
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
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
0768
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
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
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
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
0819
0820
0821
0822 case SPFP:
0823 if ((FP_ROUNDMODE) == FP_RND_PINF) {
0824 if (!s_lo) fgpr.wp[1]++;
0825 } else {
0826 if (s_lo) {
0827 if (fp_result)
0828 fgpr.wp[1]++;
0829 else
0830 fgpr.wp[1]--;
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]++;
0840 else
0841 fgpr.wp[1]++;
0842 }
0843 } else {
0844 if (s_hi) {
0845 if (fp_result)
0846 fgpr.dp[0]++;
0847 else
0848 fgpr.wp[1]--;
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]++;
0857 if (hi_inexact && !s_hi)
0858 fgpr.wp[0]++;
0859 } else {
0860 if (lo_inexact && s_lo) {
0861 if (fp_result)
0862 fgpr.wp[1]++;
0863 else
0864 fgpr.wp[1]--;
0865 }
0866 if (hi_inexact && s_hi) {
0867 if (fp_result)
0868 fgpr.wp[0]++;
0869 else
0870 fgpr.wp[0]--;
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
0902
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);