On 29/06/2016 08:34, Cyril Bur wrote: > Currently the MSR TM bit is always set if the hardware is TM capable. > This adds extra overhead as it means the TM SPRS (TFHAR, TEXASR and > TFAIR) must be swapped for each process regardless of if they use TM. > > For processes that don't use TM the TM MSR bit can be turned off > allowing the kernel to avoid the expensive swap of the TM registers. > > A TM unavailable exception will occur if a thread does use TM and the > kernel will enable MSR_TM and leave it so for some time afterwards. > > Signed-off-by: Cyril Bur <cyril...@gmail.com> > --- > arch/powerpc/include/asm/processor.h | 1 + > arch/powerpc/kernel/process.c | 30 ++++++++++++++++++++++-------- > arch/powerpc/kernel/traps.c | 8 ++++++++ > 3 files changed, 31 insertions(+), 8 deletions(-) > > diff --git a/arch/powerpc/include/asm/processor.h > b/arch/powerpc/include/asm/processor.h > index 5ff1e4c..9d4363c 100644 > --- a/arch/powerpc/include/asm/processor.h > +++ b/arch/powerpc/include/asm/processor.h > @@ -257,6 +257,7 @@ struct thread_struct { > int used_spe; /* set if process has used spe */ > #endif /* CONFIG_SPE */ > #ifdef CONFIG_PPC_TRANSACTIONAL_MEM > + u8 load_tm; > u64 tm_tfhar; /* Transaction fail handler addr */ > u64 tm_texasr; /* Transaction exception & summary */ > u64 tm_tfiar; /* Transaction fail instr address reg */ > diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c > index 2e903c6..8abecda 100644 > --- a/arch/powerpc/kernel/process.c > +++ b/arch/powerpc/kernel/process.c > @@ -870,6 +870,9 @@ void tm_recheckpoint(struct thread_struct *thread, > { > unsigned long flags; > > + if (!(thread->regs->msr & MSR_TM)) > + return; > + > /* We really can't be interrupted here as the TEXASR registers can't > * change and later in the trecheckpoint code, we have a userspace R1. > * So let's hard disable over this region. > @@ -905,6 +908,9 @@ static inline void tm_recheckpoint_new_task(struct > task_struct *new) > if (!new->thread.regs) > return; > > + if (!(new->thread.regs->msr & MSR_TM)) > + return; > + > if (!MSR_TM_ACTIVE(new->thread.regs->msr)){ > tm_restore_sprs(&new->thread); > return; > @@ -925,11 +931,18 @@ static inline void tm_recheckpoint_new_task(struct > task_struct *new) > new->pid, mfmsr()); > } > > -static inline void __switch_to_tm(struct task_struct *prev) > +static inline void __switch_to_tm(struct task_struct *prev, struct > task_struct *new) > { > if (cpu_has_feature(CPU_FTR_TM)) { > - tm_enable(); > - tm_reclaim_task(prev); > + if (prev->thread.regs && (prev->thread.regs->msr & MSR_TM)) { > + prev->thread.load_tm++; > + tm_enable(); > + tm_reclaim_task(prev); > + if (!MSR_TM_ACTIVE(prev->thread.regs->msr) && > prev->thread.load_tm == 0) > + prev->thread.regs->msr |= ~MSR_TM;
Hi Cyrill, I guess the idea is to clear MSR_TM here, so why "or-ing" here ? I'd rather see : + prev->thread.regs->msr &= ~MSR_TM; Cheers, Laurent. > + } else if (new && new->thread.regs && (new->thread.regs->msr & > MSR_TM)) { > + tm_enable(); > + } > } > } > > @@ -965,7 +978,7 @@ void restore_tm_state(struct pt_regs *regs) > > #else > #define tm_recheckpoint_new_task(new) > -#define __switch_to_tm(prev) > +#define __switch_to_tm(prev, new) > #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */ > > static inline void save_sprs(struct thread_struct *t) > @@ -1095,7 +1108,7 @@ struct task_struct *__switch_to(struct task_struct > *prev, > /* Save FPU, Altivec, VSX and SPE state */ > giveup_all(prev); > > - __switch_to_tm(prev); > + __switch_to_tm(prev, new); > > /* > * We can't take a PMU exception inside _switch() since there is a > @@ -1340,8 +1353,11 @@ int arch_dup_task_struct(struct task_struct *dst, > struct task_struct *src) > * transitions the CPU out of TM mode. Hence we need to call > * tm_recheckpoint_new_task() (on the same task) to restore the > * checkpointed state back and the TM mode. > + * > + * Can't pass dst because it isn't ready. Doesn't matter, passing > + * dst is only important for __switch_to() > */ > - __switch_to_tm(src); > + __switch_to_tm(src, NULL); > tm_recheckpoint_new_task(src); > > *dst = *src; > @@ -1574,8 +1590,6 @@ void start_thread(struct pt_regs *regs, unsigned long > start, unsigned long sp) > current->thread.used_spe = 0; > #endif /* CONFIG_SPE */ > #ifdef CONFIG_PPC_TRANSACTIONAL_MEM > - if (cpu_has_feature(CPU_FTR_TM)) > - regs->msr |= MSR_TM; > current->thread.tm_tfhar = 0; > current->thread.tm_texasr = 0; > current->thread.tm_tfiar = 0; > diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c > index 29260ee..141b953 100644 > --- a/arch/powerpc/kernel/traps.c > +++ b/arch/powerpc/kernel/traps.c > @@ -1366,6 +1366,14 @@ void vsx_unavailable_exception(struct pt_regs *regs) > > static void tm_unavailable(struct pt_regs *regs) > { > + if (user_mode(regs)) { > + current->thread.load_tm++; > + regs->msr |= MSR_TM; > + tm_enable(); > + tm_restore_sprs(¤t->thread); > + return; > + } > + > pr_emerg("Unrecoverable TM Unavailable Exception " > "%lx at %lx\n", regs->trap, regs->nip); > die("Unrecoverable TM Unavailable Exception", regs, SIGABRT); > _______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev