powerpc: Add the ability to save FPU without giving it up
authorCyril Bur <cyrilbur@gmail.com>
Mon, 29 Feb 2016 06:53:49 +0000 (17:53 +1100)
committerMichael Ellerman <mpe@ellerman.id.au>
Wed, 2 Mar 2016 12:34:49 +0000 (23:34 +1100)
This patch adds the ability to be able to save the FPU registers to the
thread struct without giving up (disabling the facility) next time the
process returns to userspace.

This patch optimises the thread copy path (as a result of a fork() or
clone()) so that the parent thread can return to userspace with hot
registers avoiding a possibly pointless reload of FPU register state.

Signed-off-by: Cyril Bur <cyrilbur@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/include/asm/switch_to.h
arch/powerpc/kernel/fpu.S
arch/powerpc/kernel/process.c

index 3690041c126a7850a4dc37ec0684b81e04fa2bd5..6a201e8dc94791dc4c5b6dca6c7bb9f194fcf818 100644 (file)
@@ -28,13 +28,14 @@ extern void giveup_all(struct task_struct *);
 extern void enable_kernel_fp(void);
 extern void flush_fp_to_thread(struct task_struct *);
 extern void giveup_fpu(struct task_struct *);
-extern void __giveup_fpu(struct task_struct *);
+extern void save_fpu(struct task_struct *);
 static inline void disable_kernel_fp(void)
 {
        msr_check_and_clear(MSR_FP);
 }
 #else
 static inline void __giveup_fpu(struct task_struct *t) { }
+static inline void save_fpu(struct task_struct *t) { }
 static inline void flush_fp_to_thread(struct task_struct *t) { }
 #endif
 
index b06352474ad08a535b3ff1428b7e527be22d6caf..15da2b5df85e6775ede9834a6620c8abb7c0be02 100644 (file)
@@ -143,33 +143,20 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX)
        blr
 
 /*
- * __giveup_fpu(tsk)
- * Disable FP for the task given as the argument,
- * and save the floating-point registers in its thread_struct.
+ * save_fpu(tsk)
+ * Save the floating-point registers in its thread_struct.
  * Enables the FPU for use in the kernel on return.
  */
-_GLOBAL(__giveup_fpu)
+_GLOBAL(save_fpu)
        addi    r3,r3,THREAD            /* want THREAD of task */
        PPC_LL  r6,THREAD_FPSAVEAREA(r3)
        PPC_LL  r5,PT_REGS(r3)
        PPC_LCMPI       0,r6,0
        bne     2f
        addi    r6,r3,THREAD_FPSTATE
-2:     PPC_LCMPI       0,r5,0
-       SAVE_32FPVSRS(0, R4, R6)
+2:     SAVE_32FPVSRS(0, R4, R6)
        mffs    fr0
        stfd    fr0,FPSTATE_FPSCR(r6)
-       beq     1f
-       PPC_LL  r4,_MSR-STACK_FRAME_OVERHEAD(r5)
-       li      r3,MSR_FP|MSR_FE0|MSR_FE1
-#ifdef CONFIG_VSX
-BEGIN_FTR_SECTION
-       oris    r3,r3,MSR_VSX@h
-END_FTR_SECTION_IFSET(CPU_FTR_VSX)
-#endif
-       andc    r4,r4,r3                /* disable FP for previous task */
-       PPC_STL r4,_MSR-STACK_FRAME_OVERHEAD(r5)
-1:
        blr
 
 /*
index 29da07fb3b4adb64880a44561d79a3f3e5251bb6..a7e5061187e890100e1d461db707c858d5ae4dea 100644 (file)
@@ -133,6 +133,16 @@ void __msr_check_and_clear(unsigned long bits)
 EXPORT_SYMBOL(__msr_check_and_clear);
 
 #ifdef CONFIG_PPC_FPU
+void __giveup_fpu(struct task_struct *tsk)
+{
+       save_fpu(tsk);
+       tsk->thread.regs->msr &= ~MSR_FP;
+#ifdef CONFIG_VSX
+       if (cpu_has_feature(CPU_FTR_VSX))
+               tsk->thread.regs->msr &= ~MSR_VSX;
+#endif
+}
+
 void giveup_fpu(struct task_struct *tsk)
 {
        check_if_tm_restore_required(tsk);
@@ -459,7 +469,7 @@ void save_all(struct task_struct *tsk)
        msr_check_and_set(msr_all_available);
 
        if (usermsr & MSR_FP)
-               __giveup_fpu(tsk);
+               save_fpu(tsk);
 
        if (usermsr & MSR_VEC)
                __giveup_altivec(tsk);