aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCyril Bur <cyrilbur@gmail.com>2016-09-14 04:02:16 -0400
committerMichael Ellerman <mpe@ellerman.id.au>2016-10-04 05:33:17 -0400
commit5d176f751ee3c6eededd984ad409bff201f436a7 (patch)
treec760a51812c2cfd6c27fccf9bd0f4d303e984509
parent172f7aaa75d0eaae167edde25c08aae9059e80fc (diff)
powerpc: tm: Enable transactional memory (TM) lazily for userspace
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 <cyrilbur@gmail.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
-rw-r--r--arch/powerpc/include/asm/processor.h1
-rw-r--r--arch/powerpc/kernel/process.c28
-rw-r--r--arch/powerpc/kernel/traps.c9
3 files changed, 33 insertions, 5 deletions
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index b3e0cfcc84f6..c07c31b0e89e 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -257,6 +257,7 @@ struct thread_struct {
257 int used_spe; /* set if process has used spe */ 257 int used_spe; /* set if process has used spe */
258#endif /* CONFIG_SPE */ 258#endif /* CONFIG_SPE */
259#ifdef CONFIG_PPC_TRANSACTIONAL_MEM 259#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
260 u8 load_tm;
260 u64 tm_tfhar; /* Transaction fail handler addr */ 261 u64 tm_tfhar; /* Transaction fail handler addr */
261 u64 tm_texasr; /* Transaction exception & summary */ 262 u64 tm_texasr; /* Transaction exception & summary */
262 u64 tm_tfiar; /* Transaction fail instr address reg */ 263 u64 tm_tfiar; /* Transaction fail instr address reg */
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index e22033005d15..9e7c10fe205f 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -812,6 +812,12 @@ static inline bool hw_brk_match(struct arch_hw_breakpoint *a,
812} 812}
813 813
814#ifdef CONFIG_PPC_TRANSACTIONAL_MEM 814#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
815
816static inline bool tm_enabled(struct task_struct *tsk)
817{
818 return tsk && tsk->thread.regs && (tsk->thread.regs->msr & MSR_TM);
819}
820
815static void tm_reclaim_thread(struct thread_struct *thr, 821static void tm_reclaim_thread(struct thread_struct *thr,
816 struct thread_info *ti, uint8_t cause) 822 struct thread_info *ti, uint8_t cause)
817{ 823{
@@ -892,6 +898,9 @@ void tm_recheckpoint(struct thread_struct *thread,
892{ 898{
893 unsigned long flags; 899 unsigned long flags;
894 900
901 if (!(thread->regs->msr & MSR_TM))
902 return;
903
895 /* We really can't be interrupted here as the TEXASR registers can't 904 /* We really can't be interrupted here as the TEXASR registers can't
896 * change and later in the trecheckpoint code, we have a userspace R1. 905 * change and later in the trecheckpoint code, we have a userspace R1.
897 * So let's hard disable over this region. 906 * So let's hard disable over this region.
@@ -924,7 +933,7 @@ static inline void tm_recheckpoint_new_task(struct task_struct *new)
924 * unavailable later, we are unable to determine which set of FP regs 933 * unavailable later, we are unable to determine which set of FP regs
925 * need to be restored. 934 * need to be restored.
926 */ 935 */
927 if (!new->thread.regs) 936 if (!tm_enabled(new))
928 return; 937 return;
929 938
930 if (!MSR_TM_ACTIVE(new->thread.regs->msr)){ 939 if (!MSR_TM_ACTIVE(new->thread.regs->msr)){
@@ -955,8 +964,16 @@ static inline void __switch_to_tm(struct task_struct *prev,
955 struct task_struct *new) 964 struct task_struct *new)
956{ 965{
957 if (cpu_has_feature(CPU_FTR_TM)) { 966 if (cpu_has_feature(CPU_FTR_TM)) {
958 tm_enable(); 967 if (tm_enabled(prev) || tm_enabled(new))
959 tm_reclaim_task(prev); 968 tm_enable();
969
970 if (tm_enabled(prev)) {
971 prev->thread.load_tm++;
972 tm_reclaim_task(prev);
973 if (!MSR_TM_ACTIVE(prev->thread.regs->msr) && prev->thread.load_tm == 0)
974 prev->thread.regs->msr &= ~MSR_TM;
975 }
976
960 tm_recheckpoint_new_task(new); 977 tm_recheckpoint_new_task(new);
961 } 978 }
962} 979}
@@ -1393,6 +1410,9 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src)
1393 * transitions the CPU out of TM mode. Hence we need to call 1410 * transitions the CPU out of TM mode. Hence we need to call
1394 * tm_recheckpoint_new_task() (on the same task) to restore the 1411 * tm_recheckpoint_new_task() (on the same task) to restore the
1395 * checkpointed state back and the TM mode. 1412 * checkpointed state back and the TM mode.
1413 *
1414 * Can't pass dst because it isn't ready. Doesn't matter, passing
1415 * dst is only important for __switch_to()
1396 */ 1416 */
1397 __switch_to_tm(src, src); 1417 __switch_to_tm(src, src);
1398 1418
@@ -1636,8 +1656,6 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp)
1636 current->thread.used_spe = 0; 1656 current->thread.used_spe = 0;
1637#endif /* CONFIG_SPE */ 1657#endif /* CONFIG_SPE */
1638#ifdef CONFIG_PPC_TRANSACTIONAL_MEM 1658#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
1639 if (cpu_has_feature(CPU_FTR_TM))
1640 regs->msr |= MSR_TM;
1641 current->thread.tm_tfhar = 0; 1659 current->thread.tm_tfhar = 0;
1642 current->thread.tm_texasr = 0; 1660 current->thread.tm_texasr = 0;
1643 current->thread.tm_tfiar = 0; 1661 current->thread.tm_tfiar = 0;
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 2f5ef5a80353..a1f8f5641e9e 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -1392,6 +1392,15 @@ void vsx_unavailable_exception(struct pt_regs *regs)
1392#ifdef CONFIG_PPC64 1392#ifdef CONFIG_PPC64
1393static void tm_unavailable(struct pt_regs *regs) 1393static void tm_unavailable(struct pt_regs *regs)
1394{ 1394{
1395#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
1396 if (user_mode(regs)) {
1397 current->thread.load_tm++;
1398 regs->msr |= MSR_TM;
1399 tm_enable();
1400 tm_restore_sprs(&current->thread);
1401 return;
1402 }
1403#endif
1395 pr_emerg("Unrecoverable TM Unavailable Exception " 1404 pr_emerg("Unrecoverable TM Unavailable Exception "
1396 "%lx at %lx\n", regs->trap, regs->nip); 1405 "%lx at %lx\n", regs->trap, regs->nip);
1397 die("Unrecoverable TM Unavailable Exception", regs, SIGABRT); 1406 die("Unrecoverable TM Unavailable Exception", regs, SIGABRT);