[PATCH V2 6/8] powerpc: Add the ability to save FPU without giving it up

Denis Kirjanov kda at linux-powerpc.org
Fri Jan 15 18:42:59 AEDT 2016


On 1/15/16, Denis Kirjanov <kda at linux-powerpc.org> wrote:
> On 1/15/16, Cyril Bur <cyrilbur at gmail.com> wrote:
>> 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.
>
> Ok, but if the patch optimizes the copy path then show the performance
> numbers.
>
> Thanks!

Oh, I've missed your cover letter.

>>
>> Signed-off-by: Cyril Bur <cyrilbur at gmail.com>
>> ---
>>  arch/powerpc/include/asm/switch_to.h |  2 +-
>>  arch/powerpc/kernel/fpu.S            | 21 ++++------------
>>  arch/powerpc/kernel/process.c        | 46
>> +++++++++++++++++++++++++++++++++++-
>>  3 files changed, 50 insertions(+), 19 deletions(-)
>>
>> diff --git a/arch/powerpc/include/asm/switch_to.h
>> b/arch/powerpc/include/asm/switch_to.h
>> index 5b268b6..c4d50e9 100644
>> --- a/arch/powerpc/include/asm/switch_to.h
>> +++ b/arch/powerpc/include/asm/switch_to.h
>> @@ -28,7 +28,7 @@ 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);
>> diff --git a/arch/powerpc/kernel/fpu.S b/arch/powerpc/kernel/fpu.S
>> index b063524..15da2b5 100644
>> --- a/arch/powerpc/kernel/fpu.S
>> +++ b/arch/powerpc/kernel/fpu.S
>> @@ -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 at 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
>>
>>  /*
>> diff --git a/arch/powerpc/kernel/process.c
>> b/arch/powerpc/kernel/process.c
>> index ec53468..8a96e4f 100644
>> --- a/arch/powerpc/kernel/process.c
>> +++ b/arch/powerpc/kernel/process.c
>> @@ -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);
>> @@ -421,12 +431,46 @@ void restore_math(struct pt_regs *regs)
>>  	regs->msr = msr;
>>  }
>>
>> +void save_all(struct task_struct *tsk)
>> +{
>> +	unsigned long usermsr;
>> +
>> +	if (!tsk->thread.regs)
>> +		return;
>> +
>> +	usermsr = tsk->thread.regs->msr;
>> +
>> +	if ((usermsr & msr_all_available) == 0)
>> +		return;
>> +
>> +	msr_check_and_set(msr_all_available);
>> +
>> +#ifdef CONFIG_PPC_FPU
>> +	if (usermsr & MSR_FP)
>> +		save_fpu(tsk);
>> +#endif
>> +#ifdef CONFIG_ALTIVEC
>> +	if (usermsr & MSR_VEC)
>> +		__giveup_altivec(tsk);
>> +#endif
>> +#ifdef CONFIG_VSX
>> +	if (usermsr & MSR_VSX)
>> +		__giveup_vsx(tsk);
>> +#endif
>> +#ifdef CONFIG_SPE
>> +	if (usermsr & MSR_SPE)
>> +		__giveup_spe(tsk);
>> +#endif
>> +
>> +	msr_check_and_clear(msr_all_available);
>> +}
>> +
>>  void flush_all_to_thread(struct task_struct *tsk)
>>  {
>>  	if (tsk->thread.regs) {
>>  		preempt_disable();
>>  		BUG_ON(tsk != current);
>> -		giveup_all(tsk);
>> +		save_all(tsk);
>>
>>  #ifdef CONFIG_SPE
>>  		if (tsk->thread.regs->msr & MSR_SPE)
>> --
>> 2.7.0
>>
>> _______________________________________________
>> Linuxppc-dev mailing list
>> Linuxppc-dev at lists.ozlabs.org
>> https://lists.ozlabs.org/listinfo/linuxppc-dev
>


More information about the Linuxppc-dev mailing list