diff options
author | Michael Neuling <mikey@neuling.org> | 2012-09-09 20:35:26 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2012-09-17 02:31:47 -0400 |
commit | b92a66a65cb4480774066d9a3080c77eb34b7232 (patch) | |
tree | ba40ef5be8bdb9b76e36ec1da29db90189d2a821 /arch/powerpc/kernel | |
parent | eda485f06d17f98bd58559fb5dd331951ffd1608 (diff) |
powerpc: Add denormalisation exception handling for POWER6/7
On POWER6 and POWER7 if the input operand to an instruction is a
denormalised single precision binary floating point value we can take
a denormalisation exception where it's expected that the hypervisor
(HV=1) will fix up the inputs before the instruction is run.
This adds code to handle this denormalisation exception for POWER6 and
POWER7.
It also add a CONFIG_PPC_DENORMALISATION option and sets it in
pseries/ppc64_defconfig.
This is useful on bare metal systems only. Based on patch from Milton
Miller.
Signed-off-by: Michael Neuling <mikey@neuling.org>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r-- | arch/powerpc/kernel/exceptions-64s.S | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S index 39aa97d3ff88..5eb00569199f 100644 --- a/arch/powerpc/kernel/exceptions-64s.S +++ b/arch/powerpc/kernel/exceptions-64s.S | |||
@@ -275,6 +275,31 @@ vsx_unavailable_pSeries_1: | |||
275 | STD_EXCEPTION_PSERIES(0x1300, 0x1300, instruction_breakpoint) | 275 | STD_EXCEPTION_PSERIES(0x1300, 0x1300, instruction_breakpoint) |
276 | KVM_HANDLER_PR_SKIP(PACA_EXGEN, EXC_STD, 0x1300) | 276 | KVM_HANDLER_PR_SKIP(PACA_EXGEN, EXC_STD, 0x1300) |
277 | 277 | ||
278 | . = 0x1500 | ||
279 | .global denorm_Hypervisor | ||
280 | denorm_exception_hv: | ||
281 | HMT_MEDIUM | ||
282 | mtspr SPRN_SPRG_HSCRATCH0,r13 | ||
283 | mfspr r13,SPRN_SPRG_HPACA | ||
284 | std r9,PACA_EXGEN+EX_R9(r13) | ||
285 | std r10,PACA_EXGEN+EX_R10(r13) | ||
286 | std r11,PACA_EXGEN+EX_R11(r13) | ||
287 | std r12,PACA_EXGEN+EX_R12(r13) | ||
288 | mfspr r9,SPRN_SPRG_HSCRATCH0 | ||
289 | std r9,PACA_EXGEN+EX_R13(r13) | ||
290 | mfcr r9 | ||
291 | |||
292 | #ifdef CONFIG_PPC_DENORMALISATION | ||
293 | mfspr r10,SPRN_HSRR1 | ||
294 | mfspr r11,SPRN_HSRR0 /* save HSRR0 */ | ||
295 | andis. r10,r10,(HSRR1_DENORM)@h /* denorm? */ | ||
296 | addi r11,r11,-4 /* HSRR0 is next instruction */ | ||
297 | bne+ denorm_assist | ||
298 | #endif | ||
299 | |||
300 | EXCEPTION_PROLOG_PSERIES_1(denorm_common, EXC_HV) | ||
301 | KVM_HANDLER_SKIP(PACA_EXGEN, EXC_STD, 0x1500) | ||
302 | |||
278 | #ifdef CONFIG_CBE_RAS | 303 | #ifdef CONFIG_CBE_RAS |
279 | STD_EXCEPTION_HV(0x1600, 0x1602, cbe_maintenance) | 304 | STD_EXCEPTION_HV(0x1600, 0x1602, cbe_maintenance) |
280 | KVM_HANDLER_SKIP(PACA_EXGEN, EXC_HV, 0x1602) | 305 | KVM_HANDLER_SKIP(PACA_EXGEN, EXC_HV, 0x1602) |
@@ -336,6 +361,103 @@ do_stab_bolted_pSeries: | |||
336 | KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0x900) | 361 | KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0x900) |
337 | KVM_HANDLER(PACA_EXGEN, EXC_HV, 0x982) | 362 | KVM_HANDLER(PACA_EXGEN, EXC_HV, 0x982) |
338 | 363 | ||
364 | #ifdef CONFIG_PPC_DENORMALISATION | ||
365 | denorm_assist: | ||
366 | BEGIN_FTR_SECTION | ||
367 | /* | ||
368 | * To denormalise we need to move a copy of the register to itself. | ||
369 | * For POWER6 do that here for all FP regs. | ||
370 | */ | ||
371 | mfmsr r10 | ||
372 | ori r10,r10,(MSR_FP|MSR_FE0|MSR_FE1) | ||
373 | xori r10,r10,(MSR_FE0|MSR_FE1) | ||
374 | mtmsrd r10 | ||
375 | sync | ||
376 | fmr 0,0 | ||
377 | fmr 1,1 | ||
378 | fmr 2,2 | ||
379 | fmr 3,3 | ||
380 | fmr 4,4 | ||
381 | fmr 5,5 | ||
382 | fmr 6,6 | ||
383 | fmr 7,7 | ||
384 | fmr 8,8 | ||
385 | fmr 9,9 | ||
386 | fmr 10,10 | ||
387 | fmr 11,11 | ||
388 | fmr 12,12 | ||
389 | fmr 13,13 | ||
390 | fmr 14,14 | ||
391 | fmr 15,15 | ||
392 | fmr 16,16 | ||
393 | fmr 17,17 | ||
394 | fmr 18,18 | ||
395 | fmr 19,19 | ||
396 | fmr 20,20 | ||
397 | fmr 21,21 | ||
398 | fmr 22,22 | ||
399 | fmr 23,23 | ||
400 | fmr 24,24 | ||
401 | fmr 25,25 | ||
402 | fmr 26,26 | ||
403 | fmr 27,27 | ||
404 | fmr 28,28 | ||
405 | fmr 29,29 | ||
406 | fmr 30,30 | ||
407 | fmr 31,31 | ||
408 | FTR_SECTION_ELSE | ||
409 | /* | ||
410 | * To denormalise we need to move a copy of the register to itself. | ||
411 | * For POWER7 do that here for the first 32 VSX registers only. | ||
412 | */ | ||
413 | mfmsr r10 | ||
414 | oris r10,r10,MSR_VSX@h | ||
415 | mtmsrd r10 | ||
416 | sync | ||
417 | XVCPSGNDP(0,0,0) | ||
418 | XVCPSGNDP(1,1,1) | ||
419 | XVCPSGNDP(2,2,2) | ||
420 | XVCPSGNDP(3,3,3) | ||
421 | XVCPSGNDP(4,4,4) | ||
422 | XVCPSGNDP(5,5,5) | ||
423 | XVCPSGNDP(6,6,6) | ||
424 | XVCPSGNDP(7,7,7) | ||
425 | XVCPSGNDP(8,8,8) | ||
426 | XVCPSGNDP(9,9,9) | ||
427 | XVCPSGNDP(10,10,10) | ||
428 | XVCPSGNDP(11,11,11) | ||
429 | XVCPSGNDP(12,12,12) | ||
430 | XVCPSGNDP(13,13,13) | ||
431 | XVCPSGNDP(14,14,14) | ||
432 | XVCPSGNDP(15,15,15) | ||
433 | XVCPSGNDP(16,16,16) | ||
434 | XVCPSGNDP(17,17,17) | ||
435 | XVCPSGNDP(18,18,18) | ||
436 | XVCPSGNDP(19,19,19) | ||
437 | XVCPSGNDP(20,20,20) | ||
438 | XVCPSGNDP(21,21,21) | ||
439 | XVCPSGNDP(22,22,22) | ||
440 | XVCPSGNDP(23,23,23) | ||
441 | XVCPSGNDP(24,24,24) | ||
442 | XVCPSGNDP(25,25,25) | ||
443 | XVCPSGNDP(26,26,26) | ||
444 | XVCPSGNDP(27,27,27) | ||
445 | XVCPSGNDP(28,28,28) | ||
446 | XVCPSGNDP(29,29,29) | ||
447 | XVCPSGNDP(30,30,30) | ||
448 | XVCPSGNDP(31,31,31) | ||
449 | ALT_FTR_SECTION_END_IFCLR(CPU_FTR_ARCH_206) | ||
450 | mtspr SPRN_HSRR0,r11 | ||
451 | mtcrf 0x80,r9 | ||
452 | ld r9,PACA_EXGEN+EX_R9(r13) | ||
453 | ld r10,PACA_EXGEN+EX_R10(r13) | ||
454 | ld r11,PACA_EXGEN+EX_R11(r13) | ||
455 | ld r12,PACA_EXGEN+EX_R12(r13) | ||
456 | ld r13,PACA_EXGEN+EX_R13(r13) | ||
457 | HRFID | ||
458 | b . | ||
459 | #endif | ||
460 | |||
339 | .align 7 | 461 | .align 7 |
340 | /* moved from 0xe00 */ | 462 | /* moved from 0xe00 */ |
341 | STD_EXCEPTION_HV(., 0xe02, h_data_storage) | 463 | STD_EXCEPTION_HV(., 0xe02, h_data_storage) |
@@ -495,6 +617,7 @@ machine_check_common: | |||
495 | STD_EXCEPTION_COMMON(0xe60, hmi_exception, .unknown_exception) | 617 | STD_EXCEPTION_COMMON(0xe60, hmi_exception, .unknown_exception) |
496 | STD_EXCEPTION_COMMON_ASYNC(0xf00, performance_monitor, .performance_monitor_exception) | 618 | STD_EXCEPTION_COMMON_ASYNC(0xf00, performance_monitor, .performance_monitor_exception) |
497 | STD_EXCEPTION_COMMON(0x1300, instruction_breakpoint, .instruction_breakpoint_exception) | 619 | STD_EXCEPTION_COMMON(0x1300, instruction_breakpoint, .instruction_breakpoint_exception) |
620 | STD_EXCEPTION_COMMON(0x1502, denorm, .unknown_exception) | ||
498 | #ifdef CONFIG_ALTIVEC | 621 | #ifdef CONFIG_ALTIVEC |
499 | STD_EXCEPTION_COMMON(0x1700, altivec_assist, .altivec_assist_exception) | 622 | STD_EXCEPTION_COMMON(0x1700, altivec_assist, .altivec_assist_exception) |
500 | #else | 623 | #else |