diff options
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/include/asm/processor.h | 6 | ||||
-rw-r--r-- | arch/powerpc/kernel/process.c | 30 | ||||
-rw-r--r-- | arch/powerpc/math-emu/math_efp.c | 20 |
3 files changed, 52 insertions, 4 deletions
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h index fc14a38c7ccf..91441d9cbaae 100644 --- a/arch/powerpc/include/asm/processor.h +++ b/arch/powerpc/include/asm/processor.h | |||
@@ -256,6 +256,8 @@ struct thread_struct { | |||
256 | unsigned long evr[32]; /* upper 32-bits of SPE regs */ | 256 | unsigned long evr[32]; /* upper 32-bits of SPE regs */ |
257 | u64 acc; /* Accumulator */ | 257 | u64 acc; /* Accumulator */ |
258 | unsigned long spefscr; /* SPE & eFP status */ | 258 | unsigned long spefscr; /* SPE & eFP status */ |
259 | unsigned long spefscr_last; /* SPEFSCR value on last prctl | ||
260 | call or trap return */ | ||
259 | int used_spe; /* set if process has used spe */ | 261 | int used_spe; /* set if process has used spe */ |
260 | #endif /* CONFIG_SPE */ | 262 | #endif /* CONFIG_SPE */ |
261 | #ifdef CONFIG_PPC_TRANSACTIONAL_MEM | 263 | #ifdef CONFIG_PPC_TRANSACTIONAL_MEM |
@@ -317,7 +319,9 @@ struct thread_struct { | |||
317 | (_ALIGN_UP(sizeof(init_thread_info), 16) + (unsigned long) &init_stack) | 319 | (_ALIGN_UP(sizeof(init_thread_info), 16) + (unsigned long) &init_stack) |
318 | 320 | ||
319 | #ifdef CONFIG_SPE | 321 | #ifdef CONFIG_SPE |
320 | #define SPEFSCR_INIT .spefscr = SPEFSCR_FINVE | SPEFSCR_FDBZE | SPEFSCR_FUNFE | SPEFSCR_FOVFE, | 322 | #define SPEFSCR_INIT \ |
323 | .spefscr = SPEFSCR_FINVE | SPEFSCR_FDBZE | SPEFSCR_FUNFE | SPEFSCR_FOVFE, \ | ||
324 | .spefscr_last = SPEFSCR_FINVE | SPEFSCR_FDBZE | SPEFSCR_FUNFE | SPEFSCR_FOVFE, | ||
321 | #else | 325 | #else |
322 | #define SPEFSCR_INIT | 326 | #define SPEFSCR_INIT |
323 | #endif | 327 | #endif |
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 3386d8ab7eb0..b08c0d03530f 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c | |||
@@ -1175,6 +1175,19 @@ int set_fpexc_mode(struct task_struct *tsk, unsigned int val) | |||
1175 | if (val & PR_FP_EXC_SW_ENABLE) { | 1175 | if (val & PR_FP_EXC_SW_ENABLE) { |
1176 | #ifdef CONFIG_SPE | 1176 | #ifdef CONFIG_SPE |
1177 | if (cpu_has_feature(CPU_FTR_SPE)) { | 1177 | if (cpu_has_feature(CPU_FTR_SPE)) { |
1178 | /* | ||
1179 | * When the sticky exception bits are set | ||
1180 | * directly by userspace, it must call prctl | ||
1181 | * with PR_GET_FPEXC (with PR_FP_EXC_SW_ENABLE | ||
1182 | * in the existing prctl settings) or | ||
1183 | * PR_SET_FPEXC (with PR_FP_EXC_SW_ENABLE in | ||
1184 | * the bits being set). <fenv.h> functions | ||
1185 | * saving and restoring the whole | ||
1186 | * floating-point environment need to do so | ||
1187 | * anyway to restore the prctl settings from | ||
1188 | * the saved environment. | ||
1189 | */ | ||
1190 | tsk->thread.spefscr_last = mfspr(SPRN_SPEFSCR); | ||
1178 | tsk->thread.fpexc_mode = val & | 1191 | tsk->thread.fpexc_mode = val & |
1179 | (PR_FP_EXC_SW_ENABLE | PR_FP_ALL_EXCEPT); | 1192 | (PR_FP_EXC_SW_ENABLE | PR_FP_ALL_EXCEPT); |
1180 | return 0; | 1193 | return 0; |
@@ -1206,9 +1219,22 @@ int get_fpexc_mode(struct task_struct *tsk, unsigned long adr) | |||
1206 | 1219 | ||
1207 | if (tsk->thread.fpexc_mode & PR_FP_EXC_SW_ENABLE) | 1220 | if (tsk->thread.fpexc_mode & PR_FP_EXC_SW_ENABLE) |
1208 | #ifdef CONFIG_SPE | 1221 | #ifdef CONFIG_SPE |
1209 | if (cpu_has_feature(CPU_FTR_SPE)) | 1222 | if (cpu_has_feature(CPU_FTR_SPE)) { |
1223 | /* | ||
1224 | * When the sticky exception bits are set | ||
1225 | * directly by userspace, it must call prctl | ||
1226 | * with PR_GET_FPEXC (with PR_FP_EXC_SW_ENABLE | ||
1227 | * in the existing prctl settings) or | ||
1228 | * PR_SET_FPEXC (with PR_FP_EXC_SW_ENABLE in | ||
1229 | * the bits being set). <fenv.h> functions | ||
1230 | * saving and restoring the whole | ||
1231 | * floating-point environment need to do so | ||
1232 | * anyway to restore the prctl settings from | ||
1233 | * the saved environment. | ||
1234 | */ | ||
1235 | tsk->thread.spefscr_last = mfspr(SPRN_SPEFSCR); | ||
1210 | val = tsk->thread.fpexc_mode; | 1236 | val = tsk->thread.fpexc_mode; |
1211 | else | 1237 | } else |
1212 | return -EINVAL; | 1238 | return -EINVAL; |
1213 | #else | 1239 | #else |
1214 | return -EINVAL; | 1240 | return -EINVAL; |
diff --git a/arch/powerpc/math-emu/math_efp.c b/arch/powerpc/math-emu/math_efp.c index a73f0884d358..59835c625dc6 100644 --- a/arch/powerpc/math-emu/math_efp.c +++ b/arch/powerpc/math-emu/math_efp.c | |||
@@ -630,9 +630,27 @@ update_ccr: | |||
630 | regs->ccr |= (IR << ((7 - ((speinsn >> 23) & 0x7)) << 2)); | 630 | regs->ccr |= (IR << ((7 - ((speinsn >> 23) & 0x7)) << 2)); |
631 | 631 | ||
632 | update_regs: | 632 | update_regs: |
633 | __FPU_FPSCR &= ~FP_EX_MASK; | 633 | /* |
634 | * If the "invalid" exception sticky bit was set by the | ||
635 | * processor for non-finite input, but was not set before the | ||
636 | * instruction being emulated, clear it. Likewise for the | ||
637 | * "underflow" bit, which may have been set by the processor | ||
638 | * for exact underflow, not just inexact underflow when the | ||
639 | * flag should be set for IEEE 754 semantics. Other sticky | ||
640 | * exceptions will only be set by the processor when they are | ||
641 | * correct according to IEEE 754 semantics, and we must not | ||
642 | * clear sticky bits that were already set before the emulated | ||
643 | * instruction as they represent the user-visible sticky | ||
644 | * exception status. "inexact" traps to kernel are not | ||
645 | * required for IEEE semantics and are not enabled by default, | ||
646 | * so the "inexact" sticky bit may have been set by a previous | ||
647 | * instruction without the kernel being aware of it. | ||
648 | */ | ||
649 | __FPU_FPSCR | ||
650 | &= ~(FP_EX_INVALID | FP_EX_UNDERFLOW) | current->thread.spefscr_last; | ||
634 | __FPU_FPSCR |= (FP_CUR_EXCEPTIONS & FP_EX_MASK); | 651 | __FPU_FPSCR |= (FP_CUR_EXCEPTIONS & FP_EX_MASK); |
635 | mtspr(SPRN_SPEFSCR, __FPU_FPSCR); | 652 | mtspr(SPRN_SPEFSCR, __FPU_FPSCR); |
653 | current->thread.spefscr_last = __FPU_FPSCR; | ||
636 | 654 | ||
637 | current->thread.evr[fc] = vc.wp[0]; | 655 | current->thread.evr[fc] = vc.wp[0]; |
638 | regs->gpr[fc] = vc.wp[1]; | 656 | regs->gpr[fc] = vc.wp[1]; |