powerpc: Always restore FPU/VEC/VSX if hardware transactional memory in use
[cascardo/linux.git] / arch / powerpc / kernel / process.c
index ce8a26a..3846fab 100644 (file)
@@ -89,7 +89,13 @@ static void check_if_tm_restore_required(struct task_struct *tsk)
                set_thread_flag(TIF_RESTORE_TM);
        }
 }
+
+static inline bool msr_tm_active(unsigned long msr)
+{
+       return MSR_TM_ACTIVE(msr);
+}
 #else
+static inline bool msr_tm_active(unsigned long msr) { return false; }
 static inline void check_if_tm_restore_required(struct task_struct *tsk) { }
 #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
 
@@ -209,7 +215,7 @@ void enable_kernel_fp(void)
 EXPORT_SYMBOL(enable_kernel_fp);
 
 static int restore_fp(struct task_struct *tsk) {
-       if (tsk->thread.load_fp) {
+       if (tsk->thread.load_fp || msr_tm_active(tsk->thread.regs->msr)) {
                load_fp_state(&current->thread.fp_state);
                current->thread.load_fp++;
                return 1;
@@ -279,7 +285,8 @@ EXPORT_SYMBOL_GPL(flush_altivec_to_thread);
 
 static int restore_altivec(struct task_struct *tsk)
 {
-       if (cpu_has_feature(CPU_FTR_ALTIVEC) && tsk->thread.load_vec) {
+       if (cpu_has_feature(CPU_FTR_ALTIVEC) &&
+               (tsk->thread.load_vec || msr_tm_active(tsk->thread.regs->msr))) {
                load_vr_state(&tsk->thread.vr_state);
                tsk->thread.used_vr = 1;
                tsk->thread.load_vec++;
@@ -465,7 +472,8 @@ void restore_math(struct pt_regs *regs)
 {
        unsigned long msr;
 
-       if (!current->thread.load_fp && !loadvec(current->thread))
+       if (!msr_tm_active(regs->msr) &&
+               !current->thread.load_fp && !loadvec(current->thread))
                return;
 
        msr = regs->msr;
@@ -984,6 +992,13 @@ void restore_tm_state(struct pt_regs *regs)
        msr_diff = current->thread.ckpt_regs.msr & ~regs->msr;
        msr_diff &= MSR_FP | MSR_VEC | MSR_VSX;
 
+       /* Ensure that restore_math() will restore */
+       if (msr_diff & MSR_FP)
+               current->thread.load_fp = 1;
+#ifdef CONFIG_ALIVEC
+       if (cpu_has_feature(CPU_FTR_ALTIVEC) && msr_diff & MSR_VEC)
+               current->thread.load_vec = 1;
+#endif
        restore_math(regs);
 
        regs->msr |= msr_diff;