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