math_efp.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * arch/powerpc/math-emu/math_efp.c
  4. *
  5. * Copyright (C) 2006-2008, 2010 Freescale Semiconductor, Inc.
  6. *
  7. * Author: Ebony Zhu, <ebony.zhu@freescale.com>
  8. * Yu Liu, <yu.liu@freescale.com>
  9. *
  10. * Derived from arch/alpha/math-emu/math.c
  11. * arch/powerpc/math-emu/math.c
  12. *
  13. * Description:
  14. * This file is the exception handler to make E500 SPE instructions
  15. * fully comply with IEEE-754 floating point standard.
  16. */
  17. #include <linux/types.h>
  18. #include <linux/prctl.h>
  19. #include <linux/uaccess.h>
  20. #include <asm/reg.h>
  21. #define FP_EX_BOOKE_E500_SPE
  22. #include <asm/sfp-machine.h>
  23. #include <math-emu/soft-fp.h>
  24. #include <math-emu/single.h>
  25. #include <math-emu/double.h>
  26. #define EFAPU 0x4
  27. #define VCT 0x4
  28. #define SPFP 0x6
  29. #define DPFP 0x7
  30. #define EFSADD 0x2c0
  31. #define EFSSUB 0x2c1
  32. #define EFSABS 0x2c4
  33. #define EFSNABS 0x2c5
  34. #define EFSNEG 0x2c6
  35. #define EFSMUL 0x2c8
  36. #define EFSDIV 0x2c9
  37. #define EFSCMPGT 0x2cc
  38. #define EFSCMPLT 0x2cd
  39. #define EFSCMPEQ 0x2ce
  40. #define EFSCFD 0x2cf
  41. #define EFSCFSI 0x2d1
  42. #define EFSCTUI 0x2d4
  43. #define EFSCTSI 0x2d5
  44. #define EFSCTUF 0x2d6
  45. #define EFSCTSF 0x2d7
  46. #define EFSCTUIZ 0x2d8
  47. #define EFSCTSIZ 0x2da
  48. #define EVFSADD 0x280
  49. #define EVFSSUB 0x281
  50. #define EVFSABS 0x284
  51. #define EVFSNABS 0x285
  52. #define EVFSNEG 0x286
  53. #define EVFSMUL 0x288
  54. #define EVFSDIV 0x289
  55. #define EVFSCMPGT 0x28c
  56. #define EVFSCMPLT 0x28d
  57. #define EVFSCMPEQ 0x28e
  58. #define EVFSCTUI 0x294
  59. #define EVFSCTSI 0x295
  60. #define EVFSCTUF 0x296
  61. #define EVFSCTSF 0x297
  62. #define EVFSCTUIZ 0x298
  63. #define EVFSCTSIZ 0x29a
  64. #define EFDADD 0x2e0
  65. #define EFDSUB 0x2e1
  66. #define EFDABS 0x2e4
  67. #define EFDNABS 0x2e5
  68. #define EFDNEG 0x2e6
  69. #define EFDMUL 0x2e8
  70. #define EFDDIV 0x2e9
  71. #define EFDCTUIDZ 0x2ea
  72. #define EFDCTSIDZ 0x2eb
  73. #define EFDCMPGT 0x2ec
  74. #define EFDCMPLT 0x2ed
  75. #define EFDCMPEQ 0x2ee
  76. #define EFDCFS 0x2ef
  77. #define EFDCTUI 0x2f4
  78. #define EFDCTSI 0x2f5
  79. #define EFDCTUF 0x2f6
  80. #define EFDCTSF 0x2f7
  81. #define EFDCTUIZ 0x2f8
  82. #define EFDCTSIZ 0x2fa
  83. #define AB 2
  84. #define XA 3
  85. #define XB 4
  86. #define XCR 5
  87. #define NOTYPE 0
  88. #define SIGN_BIT_S (1UL << 31)
  89. #define SIGN_BIT_D (1ULL << 63)
  90. #define FP_EX_MASK (FP_EX_INEXACT | FP_EX_INVALID | FP_EX_DIVZERO | \
  91. FP_EX_UNDERFLOW | FP_EX_OVERFLOW)
  92. static int have_e500_cpu_a005_erratum;
  93. union dw_union {
  94. u64 dp[1];
  95. u32 wp[2];
  96. };
  97. static unsigned long insn_type(unsigned long speinsn)
  98. {
  99. unsigned long ret = NOTYPE;
  100. switch (speinsn & 0x7ff) {
  101. case EFSABS: ret = XA; break;
  102. case EFSADD: ret = AB; break;
  103. case EFSCFD: ret = XB; break;
  104. case EFSCMPEQ: ret = XCR; break;
  105. case EFSCMPGT: ret = XCR; break;
  106. case EFSCMPLT: ret = XCR; break;
  107. case EFSCTSF: ret = XB; break;
  108. case EFSCTSI: ret = XB; break;
  109. case EFSCTSIZ: ret = XB; break;
  110. case EFSCTUF: ret = XB; break;
  111. case EFSCTUI: ret = XB; break;
  112. case EFSCTUIZ: ret = XB; break;
  113. case EFSDIV: ret = AB; break;
  114. case EFSMUL: ret = AB; break;
  115. case EFSNABS: ret = XA; break;
  116. case EFSNEG: ret = XA; break;
  117. case EFSSUB: ret = AB; break;
  118. case EFSCFSI: ret = XB; break;
  119. case EVFSABS: ret = XA; break;
  120. case EVFSADD: ret = AB; break;
  121. case EVFSCMPEQ: ret = XCR; break;
  122. case EVFSCMPGT: ret = XCR; break;
  123. case EVFSCMPLT: ret = XCR; break;
  124. case EVFSCTSF: ret = XB; break;
  125. case EVFSCTSI: ret = XB; break;
  126. case EVFSCTSIZ: ret = XB; break;
  127. case EVFSCTUF: ret = XB; break;
  128. case EVFSCTUI: ret = XB; break;
  129. case EVFSCTUIZ: ret = XB; break;
  130. case EVFSDIV: ret = AB; break;
  131. case EVFSMUL: ret = AB; break;
  132. case EVFSNABS: ret = XA; break;
  133. case EVFSNEG: ret = XA; break;
  134. case EVFSSUB: ret = AB; break;
  135. case EFDABS: ret = XA; break;
  136. case EFDADD: ret = AB; break;
  137. case EFDCFS: ret = XB; break;
  138. case EFDCMPEQ: ret = XCR; break;
  139. case EFDCMPGT: ret = XCR; break;
  140. case EFDCMPLT: ret = XCR; break;
  141. case EFDCTSF: ret = XB; break;
  142. case EFDCTSI: ret = XB; break;
  143. case EFDCTSIDZ: ret = XB; break;
  144. case EFDCTSIZ: ret = XB; break;
  145. case EFDCTUF: ret = XB; break;
  146. case EFDCTUI: ret = XB; break;
  147. case EFDCTUIDZ: ret = XB; break;
  148. case EFDCTUIZ: ret = XB; break;
  149. case EFDDIV: ret = AB; break;
  150. case EFDMUL: ret = AB; break;
  151. case EFDNABS: ret = XA; break;
  152. case EFDNEG: ret = XA; break;
  153. case EFDSUB: ret = AB; break;
  154. }
  155. return ret;
  156. }
  157. int do_spe_mathemu(struct pt_regs *regs)
  158. {
  159. FP_DECL_EX;
  160. int IR, cmp;
  161. unsigned long type, func, fc, fa, fb, src, speinsn;
  162. union dw_union vc, va, vb;
  163. if (get_user(speinsn, (unsigned int __user *) regs->nip))
  164. return -EFAULT;
  165. if ((speinsn >> 26) != EFAPU)
  166. return -EINVAL; /* not an spe instruction */
  167. type = insn_type(speinsn);
  168. if (type == NOTYPE)
  169. goto illegal;
  170. func = speinsn & 0x7ff;
  171. fc = (speinsn >> 21) & 0x1f;
  172. fa = (speinsn >> 16) & 0x1f;
  173. fb = (speinsn >> 11) & 0x1f;
  174. src = (speinsn >> 5) & 0x7;
  175. vc.wp[0] = current->thread.evr[fc];
  176. vc.wp[1] = regs->gpr[fc];
  177. va.wp[0] = current->thread.evr[fa];
  178. va.wp[1] = regs->gpr[fa];
  179. vb.wp[0] = current->thread.evr[fb];
  180. vb.wp[1] = regs->gpr[fb];
  181. __FPU_FPSCR = mfspr(SPRN_SPEFSCR);
  182. pr_debug("speinsn:%08lx spefscr:%08lx\n", speinsn, __FPU_FPSCR);
  183. pr_debug("vc: %08x %08x\n", vc.wp[0], vc.wp[1]);
  184. pr_debug("va: %08x %08x\n", va.wp[0], va.wp[1]);
  185. pr_debug("vb: %08x %08x\n", vb.wp[0], vb.wp[1]);
  186. switch (src) {
  187. case SPFP: {
  188. FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
  189. switch (type) {
  190. case AB:
  191. case XCR:
  192. FP_UNPACK_SP(SA, va.wp + 1);
  193. case XB:
  194. FP_UNPACK_SP(SB, vb.wp + 1);
  195. break;
  196. case XA:
  197. FP_UNPACK_SP(SA, va.wp + 1);
  198. break;
  199. }
  200. pr_debug("SA: %ld %08lx %ld (%ld)\n", SA_s, SA_f, SA_e, SA_c);
  201. pr_debug("SB: %ld %08lx %ld (%ld)\n", SB_s, SB_f, SB_e, SB_c);
  202. switch (func) {
  203. case EFSABS:
  204. vc.wp[1] = va.wp[1] & ~SIGN_BIT_S;
  205. goto update_regs;
  206. case EFSNABS:
  207. vc.wp[1] = va.wp[1] | SIGN_BIT_S;
  208. goto update_regs;
  209. case EFSNEG:
  210. vc.wp[1] = va.wp[1] ^ SIGN_BIT_S;
  211. goto update_regs;
  212. case EFSADD:
  213. FP_ADD_S(SR, SA, SB);
  214. goto pack_s;
  215. case EFSSUB:
  216. FP_SUB_S(SR, SA, SB);
  217. goto pack_s;
  218. case EFSMUL:
  219. FP_MUL_S(SR, SA, SB);
  220. goto pack_s;
  221. case EFSDIV:
  222. FP_DIV_S(SR, SA, SB);
  223. goto pack_s;
  224. case EFSCMPEQ:
  225. cmp = 0;
  226. goto cmp_s;
  227. case EFSCMPGT:
  228. cmp = 1;
  229. goto cmp_s;
  230. case EFSCMPLT:
  231. cmp = -1;
  232. goto cmp_s;
  233. case EFSCTSF:
  234. case EFSCTUF:
  235. if (SB_c == FP_CLS_NAN) {
  236. vc.wp[1] = 0;
  237. FP_SET_EXCEPTION(FP_EX_INVALID);
  238. } else {
  239. SB_e += (func == EFSCTSF ? 31 : 32);
  240. FP_TO_INT_ROUND_S(vc.wp[1], SB, 32,
  241. (func == EFSCTSF));
  242. }
  243. goto update_regs;
  244. case EFSCFD: {
  245. FP_DECL_D(DB);
  246. FP_CLEAR_EXCEPTIONS;
  247. FP_UNPACK_DP(DB, vb.dp);
  248. pr_debug("DB: %ld %08lx %08lx %ld (%ld)\n",
  249. DB_s, DB_f1, DB_f0, DB_e, DB_c);
  250. FP_CONV(S, D, 1, 2, SR, DB);
  251. goto pack_s;
  252. }
  253. case EFSCTSI:
  254. case EFSCTUI:
  255. if (SB_c == FP_CLS_NAN) {
  256. vc.wp[1] = 0;
  257. FP_SET_EXCEPTION(FP_EX_INVALID);
  258. } else {
  259. FP_TO_INT_ROUND_S(vc.wp[1], SB, 32,
  260. ((func & 0x3) != 0));
  261. }
  262. goto update_regs;
  263. case EFSCTSIZ:
  264. case EFSCTUIZ:
  265. if (SB_c == FP_CLS_NAN) {
  266. vc.wp[1] = 0;
  267. FP_SET_EXCEPTION(FP_EX_INVALID);
  268. } else {
  269. FP_TO_INT_S(vc.wp[1], SB, 32,
  270. ((func & 0x3) != 0));
  271. }
  272. goto update_regs;
  273. default:
  274. goto illegal;
  275. }
  276. break;
  277. pack_s:
  278. pr_debug("SR: %ld %08lx %ld (%ld)\n", SR_s, SR_f, SR_e, SR_c);
  279. FP_PACK_SP(vc.wp + 1, SR);
  280. goto update_regs;
  281. cmp_s:
  282. FP_CMP_S(IR, SA, SB, 3);
  283. if (IR == 3 && (FP_ISSIGNAN_S(SA) || FP_ISSIGNAN_S(SB)))
  284. FP_SET_EXCEPTION(FP_EX_INVALID);
  285. if (IR == cmp) {
  286. IR = 0x4;
  287. } else {
  288. IR = 0;
  289. }
  290. goto update_ccr;
  291. }
  292. case DPFP: {
  293. FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
  294. switch (type) {
  295. case AB:
  296. case XCR:
  297. FP_UNPACK_DP(DA, va.dp);
  298. case XB:
  299. FP_UNPACK_DP(DB, vb.dp);
  300. break;
  301. case XA:
  302. FP_UNPACK_DP(DA, va.dp);
  303. break;
  304. }
  305. pr_debug("DA: %ld %08lx %08lx %ld (%ld)\n",
  306. DA_s, DA_f1, DA_f0, DA_e, DA_c);
  307. pr_debug("DB: %ld %08lx %08lx %ld (%ld)\n",
  308. DB_s, DB_f1, DB_f0, DB_e, DB_c);
  309. switch (func) {
  310. case EFDABS:
  311. vc.dp[0] = va.dp[0] & ~SIGN_BIT_D;
  312. goto update_regs;
  313. case EFDNABS:
  314. vc.dp[0] = va.dp[0] | SIGN_BIT_D;
  315. goto update_regs;
  316. case EFDNEG:
  317. vc.dp[0] = va.dp[0] ^ SIGN_BIT_D;
  318. goto update_regs;
  319. case EFDADD:
  320. FP_ADD_D(DR, DA, DB);
  321. goto pack_d;
  322. case EFDSUB:
  323. FP_SUB_D(DR, DA, DB);
  324. goto pack_d;
  325. case EFDMUL:
  326. FP_MUL_D(DR, DA, DB);
  327. goto pack_d;
  328. case EFDDIV:
  329. FP_DIV_D(DR, DA, DB);
  330. goto pack_d;
  331. case EFDCMPEQ:
  332. cmp = 0;
  333. goto cmp_d;
  334. case EFDCMPGT:
  335. cmp = 1;
  336. goto cmp_d;
  337. case EFDCMPLT:
  338. cmp = -1;
  339. goto cmp_d;
  340. case EFDCTSF:
  341. case EFDCTUF:
  342. if (DB_c == FP_CLS_NAN) {
  343. vc.wp[1] = 0;
  344. FP_SET_EXCEPTION(FP_EX_INVALID);
  345. } else {
  346. DB_e += (func == EFDCTSF ? 31 : 32);
  347. FP_TO_INT_ROUND_D(vc.wp[1], DB, 32,
  348. (func == EFDCTSF));
  349. }
  350. goto update_regs;
  351. case EFDCFS: {
  352. FP_DECL_S(SB);
  353. FP_CLEAR_EXCEPTIONS;
  354. FP_UNPACK_SP(SB, vb.wp + 1);
  355. pr_debug("SB: %ld %08lx %ld (%ld)\n",
  356. SB_s, SB_f, SB_e, SB_c);
  357. FP_CONV(D, S, 2, 1, DR, SB);
  358. goto pack_d;
  359. }
  360. case EFDCTUIDZ:
  361. case EFDCTSIDZ:
  362. if (DB_c == FP_CLS_NAN) {
  363. vc.dp[0] = 0;
  364. FP_SET_EXCEPTION(FP_EX_INVALID);
  365. } else {
  366. FP_TO_INT_D(vc.dp[0], DB, 64,
  367. ((func & 0x1) == 0));
  368. }
  369. goto update_regs;
  370. case EFDCTUI:
  371. case EFDCTSI:
  372. if (DB_c == FP_CLS_NAN) {
  373. vc.wp[1] = 0;
  374. FP_SET_EXCEPTION(FP_EX_INVALID);
  375. } else {
  376. FP_TO_INT_ROUND_D(vc.wp[1], DB, 32,
  377. ((func & 0x3) != 0));
  378. }
  379. goto update_regs;
  380. case EFDCTUIZ:
  381. case EFDCTSIZ:
  382. if (DB_c == FP_CLS_NAN) {
  383. vc.wp[1] = 0;
  384. FP_SET_EXCEPTION(FP_EX_INVALID);
  385. } else {
  386. FP_TO_INT_D(vc.wp[1], DB, 32,
  387. ((func & 0x3) != 0));
  388. }
  389. goto update_regs;
  390. default:
  391. goto illegal;
  392. }
  393. break;
  394. pack_d:
  395. pr_debug("DR: %ld %08lx %08lx %ld (%ld)\n",
  396. DR_s, DR_f1, DR_f0, DR_e, DR_c);
  397. FP_PACK_DP(vc.dp, DR);
  398. goto update_regs;
  399. cmp_d:
  400. FP_CMP_D(IR, DA, DB, 3);
  401. if (IR == 3 && (FP_ISSIGNAN_D(DA) || FP_ISSIGNAN_D(DB)))
  402. FP_SET_EXCEPTION(FP_EX_INVALID);
  403. if (IR == cmp) {
  404. IR = 0x4;
  405. } else {
  406. IR = 0;
  407. }
  408. goto update_ccr;
  409. }
  410. case VCT: {
  411. FP_DECL_S(SA0); FP_DECL_S(SB0); FP_DECL_S(SR0);
  412. FP_DECL_S(SA1); FP_DECL_S(SB1); FP_DECL_S(SR1);
  413. int IR0, IR1;
  414. switch (type) {
  415. case AB:
  416. case XCR:
  417. FP_UNPACK_SP(SA0, va.wp);
  418. FP_UNPACK_SP(SA1, va.wp + 1);
  419. case XB:
  420. FP_UNPACK_SP(SB0, vb.wp);
  421. FP_UNPACK_SP(SB1, vb.wp + 1);
  422. break;
  423. case XA:
  424. FP_UNPACK_SP(SA0, va.wp);
  425. FP_UNPACK_SP(SA1, va.wp + 1);
  426. break;
  427. }
  428. pr_debug("SA0: %ld %08lx %ld (%ld)\n",
  429. SA0_s, SA0_f, SA0_e, SA0_c);
  430. pr_debug("SA1: %ld %08lx %ld (%ld)\n",
  431. SA1_s, SA1_f, SA1_e, SA1_c);
  432. pr_debug("SB0: %ld %08lx %ld (%ld)\n",
  433. SB0_s, SB0_f, SB0_e, SB0_c);
  434. pr_debug("SB1: %ld %08lx %ld (%ld)\n",
  435. SB1_s, SB1_f, SB1_e, SB1_c);
  436. switch (func) {
  437. case EVFSABS:
  438. vc.wp[0] = va.wp[0] & ~SIGN_BIT_S;
  439. vc.wp[1] = va.wp[1] & ~SIGN_BIT_S;
  440. goto update_regs;
  441. case EVFSNABS:
  442. vc.wp[0] = va.wp[0] | SIGN_BIT_S;
  443. vc.wp[1] = va.wp[1] | SIGN_BIT_S;
  444. goto update_regs;
  445. case EVFSNEG:
  446. vc.wp[0] = va.wp[0] ^ SIGN_BIT_S;
  447. vc.wp[1] = va.wp[1] ^ SIGN_BIT_S;
  448. goto update_regs;
  449. case EVFSADD:
  450. FP_ADD_S(SR0, SA0, SB0);
  451. FP_ADD_S(SR1, SA1, SB1);
  452. goto pack_vs;
  453. case EVFSSUB:
  454. FP_SUB_S(SR0, SA0, SB0);
  455. FP_SUB_S(SR1, SA1, SB1);
  456. goto pack_vs;
  457. case EVFSMUL:
  458. FP_MUL_S(SR0, SA0, SB0);
  459. FP_MUL_S(SR1, SA1, SB1);
  460. goto pack_vs;
  461. case EVFSDIV:
  462. FP_DIV_S(SR0, SA0, SB0);
  463. FP_DIV_S(SR1, SA1, SB1);
  464. goto pack_vs;
  465. case EVFSCMPEQ:
  466. cmp = 0;
  467. goto cmp_vs;
  468. case EVFSCMPGT:
  469. cmp = 1;
  470. goto cmp_vs;
  471. case EVFSCMPLT:
  472. cmp = -1;
  473. goto cmp_vs;
  474. case EVFSCTUF:
  475. case EVFSCTSF:
  476. if (SB0_c == FP_CLS_NAN) {
  477. vc.wp[0] = 0;
  478. FP_SET_EXCEPTION(FP_EX_INVALID);
  479. } else {
  480. SB0_e += (func == EVFSCTSF ? 31 : 32);
  481. FP_TO_INT_ROUND_S(vc.wp[0], SB0, 32,
  482. (func == EVFSCTSF));
  483. }
  484. if (SB1_c == FP_CLS_NAN) {
  485. vc.wp[1] = 0;
  486. FP_SET_EXCEPTION(FP_EX_INVALID);
  487. } else {
  488. SB1_e += (func == EVFSCTSF ? 31 : 32);
  489. FP_TO_INT_ROUND_S(vc.wp[1], SB1, 32,
  490. (func == EVFSCTSF));
  491. }
  492. goto update_regs;
  493. case EVFSCTUI:
  494. case EVFSCTSI:
  495. if (SB0_c == FP_CLS_NAN) {
  496. vc.wp[0] = 0;
  497. FP_SET_EXCEPTION(FP_EX_INVALID);
  498. } else {
  499. FP_TO_INT_ROUND_S(vc.wp[0], SB0, 32,
  500. ((func & 0x3) != 0));
  501. }
  502. if (SB1_c == FP_CLS_NAN) {
  503. vc.wp[1] = 0;
  504. FP_SET_EXCEPTION(FP_EX_INVALID);
  505. } else {
  506. FP_TO_INT_ROUND_S(vc.wp[1], SB1, 32,
  507. ((func & 0x3) != 0));
  508. }
  509. goto update_regs;
  510. case EVFSCTUIZ:
  511. case EVFSCTSIZ:
  512. if (SB0_c == FP_CLS_NAN) {
  513. vc.wp[0] = 0;
  514. FP_SET_EXCEPTION(FP_EX_INVALID);
  515. } else {
  516. FP_TO_INT_S(vc.wp[0], SB0, 32,
  517. ((func & 0x3) != 0));
  518. }
  519. if (SB1_c == FP_CLS_NAN) {
  520. vc.wp[1] = 0;
  521. FP_SET_EXCEPTION(FP_EX_INVALID);
  522. } else {
  523. FP_TO_INT_S(vc.wp[1], SB1, 32,
  524. ((func & 0x3) != 0));
  525. }
  526. goto update_regs;
  527. default:
  528. goto illegal;
  529. }
  530. break;
  531. pack_vs:
  532. pr_debug("SR0: %ld %08lx %ld (%ld)\n",
  533. SR0_s, SR0_f, SR0_e, SR0_c);
  534. pr_debug("SR1: %ld %08lx %ld (%ld)\n",
  535. SR1_s, SR1_f, SR1_e, SR1_c);
  536. FP_PACK_SP(vc.wp, SR0);
  537. FP_PACK_SP(vc.wp + 1, SR1);
  538. goto update_regs;
  539. cmp_vs:
  540. {
  541. int ch, cl;
  542. FP_CMP_S(IR0, SA0, SB0, 3);
  543. FP_CMP_S(IR1, SA1, SB1, 3);
  544. if (IR0 == 3 && (FP_ISSIGNAN_S(SA0) || FP_ISSIGNAN_S(SB0)))
  545. FP_SET_EXCEPTION(FP_EX_INVALID);
  546. if (IR1 == 3 && (FP_ISSIGNAN_S(SA1) || FP_ISSIGNAN_S(SB1)))
  547. FP_SET_EXCEPTION(FP_EX_INVALID);
  548. ch = (IR0 == cmp) ? 1 : 0;
  549. cl = (IR1 == cmp) ? 1 : 0;
  550. IR = (ch << 3) | (cl << 2) | ((ch | cl) << 1) |
  551. ((ch & cl) << 0);
  552. goto update_ccr;
  553. }
  554. }
  555. default:
  556. return -EINVAL;
  557. }
  558. update_ccr:
  559. regs->ccr &= ~(15 << ((7 - ((speinsn >> 23) & 0x7)) << 2));
  560. regs->ccr |= (IR << ((7 - ((speinsn >> 23) & 0x7)) << 2));
  561. update_regs:
  562. /*
  563. * If the "invalid" exception sticky bit was set by the
  564. * processor for non-finite input, but was not set before the
  565. * instruction being emulated, clear it. Likewise for the
  566. * "underflow" bit, which may have been set by the processor
  567. * for exact underflow, not just inexact underflow when the
  568. * flag should be set for IEEE 754 semantics. Other sticky
  569. * exceptions will only be set by the processor when they are
  570. * correct according to IEEE 754 semantics, and we must not
  571. * clear sticky bits that were already set before the emulated
  572. * instruction as they represent the user-visible sticky
  573. * exception status. "inexact" traps to kernel are not
  574. * required for IEEE semantics and are not enabled by default,
  575. * so the "inexact" sticky bit may have been set by a previous
  576. * instruction without the kernel being aware of it.
  577. */
  578. __FPU_FPSCR
  579. &= ~(FP_EX_INVALID | FP_EX_UNDERFLOW) | current->thread.spefscr_last;
  580. __FPU_FPSCR |= (FP_CUR_EXCEPTIONS & FP_EX_MASK);
  581. mtspr(SPRN_SPEFSCR, __FPU_FPSCR);
  582. current->thread.spefscr_last = __FPU_FPSCR;
  583. current->thread.evr[fc] = vc.wp[0];
  584. regs->gpr[fc] = vc.wp[1];
  585. pr_debug("ccr = %08lx\n", regs->ccr);
  586. pr_debug("cur exceptions = %08x spefscr = %08lx\n",
  587. FP_CUR_EXCEPTIONS, __FPU_FPSCR);
  588. pr_debug("vc: %08x %08x\n", vc.wp[0], vc.wp[1]);
  589. pr_debug("va: %08x %08x\n", va.wp[0], va.wp[1]);
  590. pr_debug("vb: %08x %08x\n", vb.wp[0], vb.wp[1]);
  591. if (current->thread.fpexc_mode & PR_FP_EXC_SW_ENABLE) {
  592. if ((FP_CUR_EXCEPTIONS & FP_EX_DIVZERO)
  593. && (current->thread.fpexc_mode & PR_FP_EXC_DIV))
  594. return 1;
  595. if ((FP_CUR_EXCEPTIONS & FP_EX_OVERFLOW)
  596. && (current->thread.fpexc_mode & PR_FP_EXC_OVF))
  597. return 1;
  598. if ((FP_CUR_EXCEPTIONS & FP_EX_UNDERFLOW)
  599. && (current->thread.fpexc_mode & PR_FP_EXC_UND))
  600. return 1;
  601. if ((FP_CUR_EXCEPTIONS & FP_EX_INEXACT)
  602. && (current->thread.fpexc_mode & PR_FP_EXC_RES))
  603. return 1;
  604. if ((FP_CUR_EXCEPTIONS & FP_EX_INVALID)
  605. && (current->thread.fpexc_mode & PR_FP_EXC_INV))
  606. return 1;
  607. }
  608. return 0;
  609. illegal:
  610. if (have_e500_cpu_a005_erratum) {
  611. /* according to e500 cpu a005 erratum, reissue efp inst */
  612. regs->nip -= 4;
  613. pr_debug("re-issue efp inst: %08lx\n", speinsn);
  614. return 0;
  615. }
  616. printk(KERN_ERR "\nOoops! IEEE-754 compliance handler encountered un-supported instruction.\ninst code: %08lx\n", speinsn);
  617. return -ENOSYS;
  618. }
  619. int speround_handler(struct pt_regs *regs)
  620. {
  621. union dw_union fgpr;
  622. int s_lo, s_hi;
  623. int lo_inexact, hi_inexact;
  624. int fp_result;
  625. unsigned long speinsn, type, fb, fc, fptype, func;
  626. if (get_user(speinsn, (unsigned int __user *) regs->nip))
  627. return -EFAULT;
  628. if ((speinsn >> 26) != 4)
  629. return -EINVAL; /* not an spe instruction */
  630. func = speinsn & 0x7ff;
  631. type = insn_type(func);
  632. if (type == XCR) return -ENOSYS;
  633. __FPU_FPSCR = mfspr(SPRN_SPEFSCR);
  634. pr_debug("speinsn:%08lx spefscr:%08lx\n", speinsn, __FPU_FPSCR);
  635. fptype = (speinsn >> 5) & 0x7;
  636. /* No need to round if the result is exact */
  637. lo_inexact = __FPU_FPSCR & (SPEFSCR_FG | SPEFSCR_FX);
  638. hi_inexact = __FPU_FPSCR & (SPEFSCR_FGH | SPEFSCR_FXH);
  639. if (!(lo_inexact || (hi_inexact && fptype == VCT)))
  640. return 0;
  641. fc = (speinsn >> 21) & 0x1f;
  642. s_lo = regs->gpr[fc] & SIGN_BIT_S;
  643. s_hi = current->thread.evr[fc] & SIGN_BIT_S;
  644. fgpr.wp[0] = current->thread.evr[fc];
  645. fgpr.wp[1] = regs->gpr[fc];
  646. fb = (speinsn >> 11) & 0x1f;
  647. switch (func) {
  648. case EFSCTUIZ:
  649. case EFSCTSIZ:
  650. case EVFSCTUIZ:
  651. case EVFSCTSIZ:
  652. case EFDCTUIDZ:
  653. case EFDCTSIDZ:
  654. case EFDCTUIZ:
  655. case EFDCTSIZ:
  656. /*
  657. * These instructions always round to zero,
  658. * independent of the rounding mode.
  659. */
  660. return 0;
  661. case EFSCTUI:
  662. case EFSCTUF:
  663. case EVFSCTUI:
  664. case EVFSCTUF:
  665. case EFDCTUI:
  666. case EFDCTUF:
  667. fp_result = 0;
  668. s_lo = 0;
  669. s_hi = 0;
  670. break;
  671. case EFSCTSI:
  672. case EFSCTSF:
  673. fp_result = 0;
  674. /* Recover the sign of a zero result if possible. */
  675. if (fgpr.wp[1] == 0)
  676. s_lo = regs->gpr[fb] & SIGN_BIT_S;
  677. break;
  678. case EVFSCTSI:
  679. case EVFSCTSF:
  680. fp_result = 0;
  681. /* Recover the sign of a zero result if possible. */
  682. if (fgpr.wp[1] == 0)
  683. s_lo = regs->gpr[fb] & SIGN_BIT_S;
  684. if (fgpr.wp[0] == 0)
  685. s_hi = current->thread.evr[fb] & SIGN_BIT_S;
  686. break;
  687. case EFDCTSI:
  688. case EFDCTSF:
  689. fp_result = 0;
  690. s_hi = s_lo;
  691. /* Recover the sign of a zero result if possible. */
  692. if (fgpr.wp[1] == 0)
  693. s_hi = current->thread.evr[fb] & SIGN_BIT_S;
  694. break;
  695. default:
  696. fp_result = 1;
  697. break;
  698. }
  699. pr_debug("round fgpr: %08x %08x\n", fgpr.wp[0], fgpr.wp[1]);
  700. switch (fptype) {
  701. /* Since SPE instructions on E500 core can handle round to nearest
  702. * and round toward zero with IEEE-754 complied, we just need
  703. * to handle round toward +Inf and round toward -Inf by software.
  704. */
  705. case SPFP:
  706. if ((FP_ROUNDMODE) == FP_RND_PINF) {
  707. if (!s_lo) fgpr.wp[1]++; /* Z > 0, choose Z1 */
  708. } else { /* round to -Inf */
  709. if (s_lo) {
  710. if (fp_result)
  711. fgpr.wp[1]++; /* Z < 0, choose Z2 */
  712. else
  713. fgpr.wp[1]--; /* Z < 0, choose Z2 */
  714. }
  715. }
  716. break;
  717. case DPFP:
  718. if (FP_ROUNDMODE == FP_RND_PINF) {
  719. if (!s_hi) {
  720. if (fp_result)
  721. fgpr.dp[0]++; /* Z > 0, choose Z1 */
  722. else
  723. fgpr.wp[1]++; /* Z > 0, choose Z1 */
  724. }
  725. } else { /* round to -Inf */
  726. if (s_hi) {
  727. if (fp_result)
  728. fgpr.dp[0]++; /* Z < 0, choose Z2 */
  729. else
  730. fgpr.wp[1]--; /* Z < 0, choose Z2 */
  731. }
  732. }
  733. break;
  734. case VCT:
  735. if (FP_ROUNDMODE == FP_RND_PINF) {
  736. if (lo_inexact && !s_lo)
  737. fgpr.wp[1]++; /* Z_low > 0, choose Z1 */
  738. if (hi_inexact && !s_hi)
  739. fgpr.wp[0]++; /* Z_high word > 0, choose Z1 */
  740. } else { /* round to -Inf */
  741. if (lo_inexact && s_lo) {
  742. if (fp_result)
  743. fgpr.wp[1]++; /* Z_low < 0, choose Z2 */
  744. else
  745. fgpr.wp[1]--; /* Z_low < 0, choose Z2 */
  746. }
  747. if (hi_inexact && s_hi) {
  748. if (fp_result)
  749. fgpr.wp[0]++; /* Z_high < 0, choose Z2 */
  750. else
  751. fgpr.wp[0]--; /* Z_high < 0, choose Z2 */
  752. }
  753. }
  754. break;
  755. default:
  756. return -EINVAL;
  757. }
  758. current->thread.evr[fc] = fgpr.wp[0];
  759. regs->gpr[fc] = fgpr.wp[1];
  760. pr_debug(" to fgpr: %08x %08x\n", fgpr.wp[0], fgpr.wp[1]);
  761. if (current->thread.fpexc_mode & PR_FP_EXC_SW_ENABLE)
  762. return (current->thread.fpexc_mode & PR_FP_EXC_RES) ? 1 : 0;
  763. return 0;
  764. }
  765. int __init spe_mathemu_init(void)
  766. {
  767. u32 pvr, maj, min;
  768. pvr = mfspr(SPRN_PVR);
  769. if ((PVR_VER(pvr) == PVR_VER_E500V1) ||
  770. (PVR_VER(pvr) == PVR_VER_E500V2)) {
  771. maj = PVR_MAJ(pvr);
  772. min = PVR_MIN(pvr);
  773. /*
  774. * E500 revision below 1.1, 2.3, 3.1, 4.1, 5.1
  775. * need cpu a005 errata workaround
  776. */
  777. switch (maj) {
  778. case 1:
  779. if (min < 1)
  780. have_e500_cpu_a005_erratum = 1;
  781. break;
  782. case 2:
  783. if (min < 3)
  784. have_e500_cpu_a005_erratum = 1;
  785. break;
  786. case 3:
  787. case 4:
  788. case 5:
  789. if (min < 1)
  790. have_e500_cpu_a005_erratum = 1;
  791. break;
  792. default:
  793. break;
  794. }
  795. }
  796. return 0;
  797. }
  798. module_init(spe_mathemu_init);