[RFC PATCH 12/14] powerpc/tm: Restore transactional SPRs
Breno Leitao
leitao at debian.org
Tue Nov 6 23:40:26 AEDT 2018
In the previous TM code, trecheckpoint was being executed in the middle of
an exception, thus, SPRs were being restored to default kernel SPRs (as
DSCR) value after trecheckpoint was done.
With this current patchset, trecheckpoint is executed just before getting
to userspace, at ret_from_except_lite, for example. Thus, SPRs need to be
restored to transactional value.
In order to so, a function, called restore_sprs_after_recheckpoint(), was
created to restore the SPRs after recheckpoint. This function should be
called after trecheckpoint to restore transactional SPRs, otherwise the
SPRs will be clobbered (with checkpointed values) after recheckpoint. I
understand it is preferred to have it done as a C function instead of
embedding it in the ASM code.
This patch also changes tm_reclaim() that now always return with
transactional SPRs value (instead of checkpointed value), as NVGPRs.
Previously tm_reclaim() was returning with transactional NVGPRS and
checkpointed SPRS, intermixing them. With the current patch, tm_reclaim()
just fill out thread->ck and thread->tm values, and return with
transactional values in a uniform way (for SPRS and NVGPRS). In this case,
a later save_spr() at switch_to() will not overwrite thread->sprs with
checkpointed values, but with transactional values.
Facility registers, as VEC and FP, continue to be clobbered after
tm_reclaim(), tho.
These are the SPRs that are checkpointed by the hardware: CR fields other
than CR0, LR, CTR, FPSCR, AMR, PPR, VRSAVE, VSCR, DSCR, and TAR.
This patch only cares about PPR, TAR and DSCR, because others SPRS either
volatiles, restored as part of facilities or not being handled currently as
AMR/CRs.
Signed-off-by: Breno Leitao <leitao at debian.org>
---
arch/powerpc/kernel/asm-offsets.c | 4 ++++
arch/powerpc/kernel/process.c | 19 +++++++++++++++++++
arch/powerpc/kernel/tm.S | 19 ++++++++++++-------
3 files changed, 35 insertions(+), 7 deletions(-)
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 9ffc72ded73a..93def2e23e68 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -109,6 +109,9 @@ int main(void)
OFFSET(THREAD_FPSAVEAREA, thread_struct, fp_save_area);
OFFSET(FPSTATE_FPSCR, thread_fp_state, fpscr);
OFFSET(THREAD_LOAD_FP, thread_struct, load_fp);
+ OFFSET(THREAD_DSCR, thread_struct, dscr);
+ OFFSET(THREAD_TAR, thread_struct, tar);
+
#ifdef CONFIG_ALTIVEC
OFFSET(THREAD_VRSTATE, thread_struct, vr_state.vr);
OFFSET(THREAD_VRSAVEAREA, thread_struct, vr_save_area);
@@ -311,6 +314,7 @@ int main(void)
STACK_PT_REGS_OFFSET(ORIG_GPR3, orig_gpr3);
STACK_PT_REGS_OFFSET(RESULT, result);
STACK_PT_REGS_OFFSET(_TRAP, trap);
+ STACK_PT_REGS_OFFSET(_PPR, ppr);
#ifndef CONFIG_PPC64
/*
* The PowerPC 400-class & Book-E processors have neither the DAR
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 8a9c298928f9..3937408ff339 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -79,6 +79,9 @@
#endif
extern unsigned long _get_SP(void);
+static inline void save_sprs(struct thread_struct *t);
+static inline void restore_sprs_after_recheckpoint(struct thread_struct
+ *thread);
#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
/*
@@ -883,6 +886,8 @@ static void tm_reclaim_thread(struct thread_struct *thr, uint8_t cause)
thr->regs->msr);
giveup_all(container_of(thr, struct task_struct, thread));
+ /* Save SPRS before reclaim */
+ save_sprs(thr);
tm_reclaim(thr, cause);
/* Tag it so restore_tm_state will pay attention to this task */
@@ -939,6 +944,7 @@ void tm_recheckpoint(struct thread_struct *thread)
__tm_recheckpoint(thread);
+ restore_sprs_after_recheckpoint(thread);
local_irq_restore(flags);
}
@@ -1166,6 +1172,19 @@ static inline void restore_sprs(struct thread_struct *old_thread,
thread_pkey_regs_restore(new_thread, old_thread);
}
+static inline void restore_sprs_after_recheckpoint(struct thread_struct *thread)
+{
+#ifdef CONFIG_PPC_BOOK3S_64
+ if (cpu_has_feature(CPU_FTR_DSCR))
+ mtspr(SPRN_DSCR, thread->dscr);
+
+ if (cpu_has_feature(CPU_FTR_ARCH_207S)) {
+ mtspr(SPRN_TAR, thread->tar);
+ mtspr(SPRN_FSCR, thread->fscr);
+ }
+#endif
+}
+
#ifdef CONFIG_PPC_BOOK3S_64
#define CP_SIZE 128
static const u8 dummy_copy_buffer[CP_SIZE] __attribute__((aligned(CP_SIZE)));
diff --git a/arch/powerpc/kernel/tm.S b/arch/powerpc/kernel/tm.S
index 9fabdce255cd..e3090502061e 100644
--- a/arch/powerpc/kernel/tm.S
+++ b/arch/powerpc/kernel/tm.S
@@ -326,9 +326,18 @@ _GLOBAL(tm_reclaim)
mtlr r0
ld r2, STK_GOT(r1)
- /* Load CPU's default DSCR */
- ld r0, PACA_DSCR_DEFAULT(r13)
- mtspr SPRN_DSCR, r0
+ /*
+ * Load transactional SPRs, as all other registers have the
+ * transacional value, which will be seen by save_sprs and so
+ * forth. Checkpointed SPRs are in the thread->tm_tar/dscr.
+ */
+ ld r0, THREAD_DSCR(r12)
+ mtspr SPRN_DSCR, r0
+ ld r0, THREAD_TAR(r12)
+ mtspr SPRN_TAR, r0
+ ld r0, _PPR(r7)
+ mtspr SPRN_PPR, r0
+
blr
@@ -518,10 +527,6 @@ restore_gprs:
mtlr r0
ld r2, STK_GOT(r1)
- /* Load CPU's default DSCR */
- ld r0, PACA_DSCR_DEFAULT(r13)
- mtspr SPRN_DSCR, r0
-
blr
/* ****************************************************************** */
--
2.19.0
More information about the Linuxppc-dev
mailing list