* [PATCH 14/16] powerpc: Add config option for transactional memory
From: Michael Neuling @ 2012-11-27 2:48 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: Michael Neuling, linuxppc-dev, Matt Evans
In-Reply-To: <1353984488-1283-1-git-send-email-mikey@neuling.org>
Kconfig option for transactional memory on powerpc.
Signed-off-by: Matt Evans <matt@ozlabs.org>
Signed-off-by: Michael Neuling <mikey@neuling.org>
---
arch/powerpc/Kconfig | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index a902a5c..ece67ca 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -308,6 +308,14 @@ config MATH_EMULATION
unit, which will allow programs that use floating-point
instructions to run.
+config TRANSACTIONAL_MEM
+ bool "Transactional Memory support"
+ depends on PPC64
+ depends on SMP
+ default n
+ ---help---
+ Support user-mode Transactional Memory.
+
config 8XX_MINIMAL_FPEMU
bool "Minimal math emulation for 8xx"
depends on 8xx && !MATH_EMULATION
--
1.7.9.5
^ permalink raw reply related
* [PATCH 13/16] powerpc: Add transactional memory to POWER8 cpu features
From: Michael Neuling @ 2012-11-27 2:48 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: Michael Neuling, linuxppc-dev, Matt Evans
In-Reply-To: <1353984488-1283-1-git-send-email-mikey@neuling.org>
Signed-off-by: Matt Evans <matt@ozlabs.org>
Signed-off-by: Michael Neuling <mikey@neuling.org>
---
arch/powerpc/include/asm/cputable.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h
index f2163da..74458e69 100644
--- a/arch/powerpc/include/asm/cputable.h
+++ b/arch/powerpc/include/asm/cputable.h
@@ -417,7 +417,7 @@ extern const char *powerpc_base_platform;
CPU_FTR_DSCR | CPU_FTR_SAO | \
CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \
CPU_FTR_ICSWX | CPU_FTR_CFAR | CPU_FTR_HVMODE | CPU_FTR_VMX_COPY | \
- CPU_FTR_DBELL)
+ CPU_FTR_DBELL | CPU_FTR_TM_COMP)
#define CPU_FTRS_CELL (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
--
1.7.9.5
^ permalink raw reply related
* [PATCH 12/16] powerpc: Hook in new transactional memory code
From: Michael Neuling @ 2012-11-27 2:48 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: Michael Neuling, linuxppc-dev, Matt Evans
In-Reply-To: <1353984488-1283-1-git-send-email-mikey@neuling.org>
This hooks the new transactional memory code into context switching, FP/VMX/VMX
unavailable and exception return.
Signed-off-by: Matt Evans <matt@ozlabs.org>
Signed-off-by: Michael Neuling <mikey@neuling.org>
---
arch/powerpc/kernel/entry_64.S | 22 ++++++++++++++++
arch/powerpc/kernel/exceptions-64s.S | 48 ++++++++++++++++++++++++++++++++--
arch/powerpc/kernel/fpu.S | 1 -
arch/powerpc/kernel/process.c | 15 +++++++++--
arch/powerpc/kernel/traps.c | 32 +++++++++++++++++++++++
arch/powerpc/kernel/vector.S | 1 -
6 files changed, 113 insertions(+), 6 deletions(-)
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index 5ae8e51..b3590c3 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -602,7 +602,29 @@ _GLOBAL(ret_from_except_lite)
beq 1f
bl .restore_interrupts
bl .schedule
+#ifdef CONFIG_TRANSACTIONAL_MEM
+BEGIN_FTR_SECTION
+ /* If TIF_RESTOREALL was set by switch_to, we MUST clear it before
+ * any return to userspace -- no one else is going to. TRAP.0 has been
+ * cleared to flag full regs to ret_from_except.
+ * Try to avoid the slow atomic clear if the flag isn't set.
+ * (This is OK as no one else will be clearing this flag.)
+ */
+ clrrdi r9,r1,THREAD_SHIFT /* current_thread_info() */
+ li r4,_TIF_RESTOREALL
+ addi r9, r9, TI_FLAGS
+ ld r3, 0(r9) /* Test TIF_RESTOREALL first! */
+ and. r0, r3, r4
+ beq .ret_from_except
+3: ldarx r10, 0, r9 /* If set, clear. */
+ andc r10, r10, r4
+ stdcx. r10, 0, r9
+ bne 3b
+ b .ret_from_except /* Not _lite; we may have full regs! */
+END_FTR_SECTION_IFSET(CPU_FTR_TM)
+#else
b .ret_from_except_lite
+#endif
1: bl .save_nvgprs
bl .restore_interrupts
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index d97cea4..220b896 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -1144,9 +1144,24 @@ fp_unavailable_common:
addi r3,r1,STACK_FRAME_OVERHEAD
bl .kernel_fp_unavailable_exception
BUG_OPCODE
-1: bl .load_up_fpu
+1:
+#ifdef CONFIG_TRANSACTIONAL_MEM
+BEGIN_FTR_SECTION
+ srdi r0, r12, MSR_TS_LG
+ andi. r0, r0, 3
+ bne- 2f
+END_FTR_SECTION_IFSET(CPU_FTR_TM)
+#endif
+ bl .load_up_fpu
+ std r12,_MSR(r1)
b fast_exception_return
-
+#ifdef CONFIG_TRANSACTIONAL_MEM
+2: /* User process was in a transaction */
+ bl .save_nvgprs
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl .fp_unavailable_tm
+ b .ret_from_except
+#endif
.align 7
.globl altivec_unavailable_common
altivec_unavailable_common:
@@ -1154,8 +1169,23 @@ altivec_unavailable_common:
#ifdef CONFIG_ALTIVEC
BEGIN_FTR_SECTION
beq 1f
+#ifdef CONFIG_TRANSACTIONAL_MEM
+ BEGIN_FTR_SECTION_NESTED(69)
+ srdi r0, r12, MSR_TS_LG
+ andi. r0, r0, 3
+ bne- 2f
+ END_FTR_SECTION_NESTED(CPU_FTR_TM, CPU_FTR_TM, 69)
+#endif
bl .load_up_altivec
+ std r12,_MSR(r1)
b fast_exception_return
+#ifdef CONFIG_TRANSACTIONAL_MEM
+2: /* User process was in a transaction */
+ bl .save_nvgprs
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl .altivec_unavailable_tm
+ b .ret_from_except
+#endif
1:
END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
#endif
@@ -1172,7 +1202,21 @@ vsx_unavailable_common:
#ifdef CONFIG_VSX
BEGIN_FTR_SECTION
beq 1f
+#ifdef CONFIG_TRANSACTIONAL_MEM
+ BEGIN_FTR_SECTION_NESTED(69)
+ srdi r0, r12, MSR_TS_LG
+ andi. r0, r0, 3
+ bne- 2f
+ END_FTR_SECTION_NESTED(CPU_FTR_TM, CPU_FTR_TM, 69)
+#endif
b .load_up_vsx
+#ifdef CONFIG_TRANSACTIONAL_MEM
+2: /* User process was in a transaction */
+ bl .save_nvgprs
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl .vsx_unavailable_tm
+ b .ret_from_except
+#endif
1:
END_FTR_SECTION_IFSET(CPU_FTR_VSX)
#endif
diff --git a/arch/powerpc/kernel/fpu.S b/arch/powerpc/kernel/fpu.S
index 6ab0e87..08b6a12f 100644
--- a/arch/powerpc/kernel/fpu.S
+++ b/arch/powerpc/kernel/fpu.S
@@ -170,7 +170,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX)
lwz r4,THREAD_FPEXC_MODE(r5)
ori r12,r12,MSR_FP
or r12,r12,r4
- std r12,_MSR(r1)
#endif
lfd fr0,THREAD_FPSCR(r5)
MTFSF_L(fr0)
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 1bf2c6c7..a0bfd97 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -455,7 +455,7 @@ out_and_saveregs:
tm_save_sprs(thr);
}
-static inline void __maybe_unused tm_recheckpoint_new_task(struct task_struct *new)
+static inline void tm_recheckpoint_new_task(struct task_struct *new)
{
unsigned long msr;
@@ -530,6 +530,8 @@ struct task_struct *__switch_to(struct task_struct *prev,
struct ppc64_tlb_batch *batch;
#endif
+ __switch_to_tm(prev);
+
#ifdef CONFIG_SMP
/* avoid complexity of lazy save/restore of fpu
* by just saving it every time we switch out if
@@ -645,6 +647,9 @@ struct task_struct *__switch_to(struct task_struct *prev,
* of sync. Hard disable here.
*/
hard_irq_disable();
+
+ tm_recheckpoint_new_task(new);
+
last = _switch(old_thread, new_thread);
#ifdef CONFIG_PPC_BOOK3S_64
@@ -1019,7 +1024,6 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp)
regs->msr = MSR_USER32;
}
#endif
-
discard_lazy_cpu_state();
#ifdef CONFIG_VSX
current->thread.used_vsr = 0;
@@ -1039,6 +1043,13 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp)
current->thread.spefscr = 0;
current->thread.used_spe = 0;
#endif /* CONFIG_SPE */
+#ifdef CONFIG_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;
+#endif /* CONFIG_TRANSACTIONAL_MEM */
}
#define PR_FP_ALL_EXCEPT (PR_FP_EXC_DIV | PR_FP_EXC_OVF | PR_FP_EXC_UND \
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 7b9f160..cb04fc7 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -1032,6 +1032,38 @@ void __kprobes program_check_exception(struct pt_regs *regs)
_exception(SIGTRAP, regs, TRAP_BRKPT, regs->nip);
return;
}
+#ifdef CONFIG_TRANSACTIONAL_MEM
+ if (reason & REASON_TM) {
+ /* This is a TM "Bad Thing Exception" program check.
+ * This occurs when:
+ * - An rfid/hrfid/mtmsrd attempts to cause an illegal
+ * transition in TM states.
+ * - A trechkpt is attempted when transactional.
+ * - A treclaim is attempted when non transactional.
+ * - A tend is illegally attempted.
+ * - writing a TM SPR when transactional.
+ */
+ if (!user_mode(regs) &&
+ report_bug(regs->nip, regs) == BUG_TRAP_TYPE_WARN) {
+ regs->nip += 4;
+ return;
+ }
+ /* If usermode caused this, it's done something illegal and
+ * gets a SIGILL slap on the wrist. We call it an illegal
+ * operand to distinguish from the instruction just being bad
+ * (e.g. executing a 'tend' on a CPU without TM!); it's an
+ * illegal /placement/ of a valid instruction.
+ */
+ if (user_mode(regs)) {
+ _exception(SIGILL, regs, ILL_ILLOPN, regs->nip);
+ return;
+ } else {
+ printk(KERN_EMERG "Unexpected TM Bad Thing exception "
+ "at %lx (msr 0x%x)\n", regs->nip, reason);
+ die("Unrecoverable exception", regs, SIGABRT);
+ }
+ }
+#endif
/* We restore the interrupt state now */
if (!arch_irq_disabled_regs(regs))
diff --git a/arch/powerpc/kernel/vector.S b/arch/powerpc/kernel/vector.S
index 330fc8c..9b47306 100644
--- a/arch/powerpc/kernel/vector.S
+++ b/arch/powerpc/kernel/vector.S
@@ -123,7 +123,6 @@ _GLOBAL(load_up_altivec)
ld r4,PACACURRENT(r13)
addi r5,r4,THREAD /* Get THREAD */
oris r12,r12,MSR_VEC@h
- std r12,_MSR(r1)
#endif
li r4,1
li r10,THREAD_VSCR
--
1.7.9.5
^ permalink raw reply related
* [PATCH 11/16] powerpc: Assembler routines for FP/VSX/VMX unavailable during a transaction
From: Michael Neuling @ 2012-11-27 2:48 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: Michael Neuling, linuxppc-dev, Matt Evans
In-Reply-To: <1353984488-1283-1-git-send-email-mikey@neuling.org>
We do lazy FP but not lazy TM (ie. userspace starts with MSR TM=1 FP=0). Hence
if userspace does an FP instruction during a transaction, we'll take an
fp unavailable exception.
This adds functions needed to handle this case. We have to inject the current
FP state into the checkpoint so that the hardware can decide what to do with
the transaction. We can't inject only the FP so we have to do a full treclaim
and recheckpoint to inject just the FP state. This will cause the transaction
to be marked as aborted by the hardware.
This just add the routines needed to do this for FP, VMX and VSX. It doesn't
hook them into the rest of the code yet.
Signed-off-by: Matt Evans <matt@ozlabs.org>
Signed-off-by: Michael Neuling <mikey@neuling.org>
---
arch/powerpc/kernel/traps.c | 95 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 95 insertions(+)
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 4acd98d..7b9f160 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -58,6 +58,7 @@
#include <asm/rio.h>
#include <asm/fadump.h>
#include <asm/switch_to.h>
+#include <asm/tm.h>
#include <asm/debug.h>
#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
@@ -1192,6 +1193,100 @@ void tm_unavailable_exception(struct pt_regs *regs)
die("Unexpected TM unavailable exception", regs, SIGABRT);
}
+#ifdef CONFIG_TRANSACTIONAL_MEM
+
+extern void do_load_up_fpu(struct pt_regs *regs);
+
+void fp_unavailable_tm(struct pt_regs *regs)
+{
+ /* Note: This does not handle any kind of FP laziness. */
+
+ /* We restore the interrupt state now */
+ if (!arch_irq_disabled_regs(regs))
+ local_irq_enable();
+
+ TM_DEBUG("FP Unavailable trap whilst transactional at 0x%lx, MSR=%lx\n",
+ regs->nip, regs->msr);
+ tm_enable();
+
+ /* We can only have got here if the task started using FP after
+ * beginning the transaction. So, the transactional regs are just a
+ * copy of the checkpointed ones. But, we still need to recheckpoint
+ * as we're enabling FP for the process; it will return, abort the
+ * transaction, and probably retry but now with FP enabled. So the
+ * checkpointed FP registers need to be loaded.
+ */
+ tm_reclaim(¤t->thread, current->thread.regs->msr,
+ TM_CAUSE_FAC_UNAV);
+ /* Reclaim didn't save out any FPRs to transact_fprs. */
+
+ /* Enable FP for the task: */
+ regs->msr |= (MSR_FP | current->thread.fpexc_mode);
+
+ /* This loads and recheckpoints the FP registers from
+ * thread.fpr[]. They will remain in registers after the
+ * checkpoint so we don't need to reload them after.
+ */
+ tm_recheckpoint(¤t->thread, regs->msr);
+}
+
+#ifdef CONFIG_ALTIVEC
+extern void do_load_up_altivec(struct pt_regs *regs);
+
+void altivec_unavailable_tm(struct pt_regs *regs)
+{
+ /* See the comments in fp_unavailable_tm(). This function operates
+ * the same way.
+ */
+
+ /* We restore the interrupt state now */
+ if (!arch_irq_disabled_regs(regs))
+ local_irq_enable();
+
+ TM_DEBUG("Vector Unavailable trap whilst transactional at 0x%lx,"
+ "MSR=%lx\n",
+ regs->nip, regs->msr);
+ tm_enable();
+ tm_reclaim(¤t->thread, current->thread.regs->msr,
+ TM_CAUSE_FAC_UNAV);
+ regs->msr |= MSR_VEC;
+ tm_recheckpoint(¤t->thread, regs->msr);
+ current->thread.used_vr = 1;
+}
+#endif
+
+#ifdef CONFIG_VSX
+void vsx_unavailable_tm(struct pt_regs *regs)
+{
+ /* See the comments in fp_unavailable_tm(). This works similarly,
+ * though we're loading both FP and VEC registers in here.
+ *
+ * If FP isn't in use, load FP regs. If VEC isn't in use, load VEC
+ * regs. Either way, set MSR_VSX.
+ */
+
+ /* We restore the interrupt state now */
+ if (!arch_irq_disabled_regs(regs))
+ local_irq_enable();
+
+ TM_DEBUG("VSX Unavailable trap whilst transactional at 0x%lx,"
+ "MSR=%lx\n",
+ regs->nip, regs->msr);
+
+ tm_enable();
+ /* This reclaims FP and/or VR regs if they're already enabled */
+ tm_reclaim(¤t->thread, current->thread.regs->msr,
+ TM_CAUSE_FAC_UNAV);
+
+ regs->msr |= MSR_VEC | MSR_FP | current->thread.fpexc_mode |
+ MSR_VSX;
+ /* This loads & recheckpoints FP and VRs. */
+ tm_recheckpoint(¤t->thread, regs->msr);
+ current->thread.used_vsr = 1;
+}
+#endif
+#endif /* CONFIG_TRANSACTIONAL_MEM */
+
void performance_monitor_exception(struct pt_regs *regs)
{
__get_cpu_var(irq_stat).pmu_irqs++;
--
1.7.9.5
^ permalink raw reply related
* [PATCH 10/16] powerpc: Add transactional memory unavaliable execption handler
From: Michael Neuling @ 2012-11-27 2:48 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: Michael Neuling, linuxppc-dev, Matt Evans
In-Reply-To: <1353984488-1283-1-git-send-email-mikey@neuling.org>
These should never happen since we always turn on MSR TM when in userspace. We
don't do lazy TM.
Hence if we hit this, we barf and kill the task as something's gone horribly
wrong.
Signed-off-by: Matt Evans <matt@ozlabs.org>
Signed-off-by: Michael Neuling <mikey@neuling.org>
---
arch/powerpc/kernel/exceptions-64s.S | 19 +++++++++++++++++++
arch/powerpc/kernel/traps.c | 21 +++++++++++++++++++++
2 files changed, 40 insertions(+)
diff --git a/arch/powerpc/kernel/exceptions-64s.S b/arch/powerpc/kernel/exceptions-64s.S
index 32fc04f..d97cea4 100644
--- a/arch/powerpc/kernel/exceptions-64s.S
+++ b/arch/powerpc/kernel/exceptions-64s.S
@@ -313,6 +313,9 @@ vsx_unavailable_pSeries_1:
. = 0xf40
b vsx_unavailable_pSeries
+ . = 0xf60
+ b tm_unavailable_pSeries
+
#ifdef CONFIG_CBE_RAS
STD_EXCEPTION_HV(0x1200, 0x1202, cbe_system_error)
KVM_HANDLER_SKIP(PACA_EXGEN, EXC_HV, 0x1202)
@@ -526,6 +529,8 @@ ALT_FTR_SECTION_END_IFCLR(CPU_FTR_ARCH_206)
KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xf20)
STD_EXCEPTION_PSERIES(., 0xf40, vsx_unavailable)
KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xf40)
+ STD_EXCEPTION_PSERIES(., 0xf60, tm_unavailable)
+ KVM_HANDLER_PR(PACA_EXGEN, EXC_STD, 0xf60)
/*
* An interrupt came in while soft-disabled. We set paca->irq_happened, then:
@@ -815,6 +820,10 @@ vsx_unavailable_relon_pSeries_1:
. = 0x4f40
b vsx_unavailable_relon_pSeries
+tm_unavailable_relon_pSeries_1:
+ . = 0x4f60
+ b tm_unavailable_relon_pSeries
+
#ifdef CONFIG_CBE_RAS
STD_RELON_EXCEPTION_HV(0x5200, 0x1202, cbe_system_error)
#endif /* CONFIG_CBE_RAS */
@@ -1174,6 +1183,15 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX)
b .ret_from_except
.align 7
+ .globl tm_unavailable_common
+tm_unavailable_common:
+ EXCEPTION_PROLOG_COMMON(0xf60, PACA_EXGEN)
+ bl .save_nvgprs
+ addi r3,r1,STACK_FRAME_OVERHEAD
+ bl .tm_unavailable_exception
+ b .ret_from_except
+
+ .align 7
.globl __end_handlers
__end_handlers:
@@ -1387,6 +1405,7 @@ _GLOBAL(do_stab_bolted)
STD_RELON_EXCEPTION_PSERIES(., 0xf00, performance_monitor)
STD_RELON_EXCEPTION_PSERIES(., 0xf20, altivec_unavailable)
STD_RELON_EXCEPTION_PSERIES(., 0xf40, vsx_unavailable)
+ STD_RELON_EXCEPTION_PSERIES(., 0xf60, tm_unavailable)
#if defined(CONFIG_PPC_PSERIES) || defined(CONFIG_PPC_POWERNV)
/*
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 8fed874..4acd98d 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -1171,6 +1171,27 @@ void vsx_unavailable_exception(struct pt_regs *regs)
die("Unrecoverable VSX Unavailable Exception", regs, SIGABRT);
}
+void tm_unavailable_exception(struct pt_regs *regs)
+{
+ /* We restore the interrupt state now */
+ if (!arch_irq_disabled_regs(regs))
+ local_irq_enable();
+
+ /* Currently we never expect a TMU exception. Catch
+ * this and kill the process!
+ */
+ printk(KERN_EMERG "Unexpected TM unavailable exception at %lx "
+ "(msr %lx)\n",
+ regs->nip, regs->msr);
+
+ if (user_mode(regs)) {
+ _exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
+ return;
+ }
+
+ die("Unexpected TM unavailable exception", regs, SIGABRT);
+}
+
void performance_monitor_exception(struct pt_regs *regs)
{
__get_cpu_var(irq_stat).pmu_irqs++;
--
1.7.9.5
^ permalink raw reply related
* [PATCH 09/16] powerpc: Add reclaim and recheckpoint functions for context switching transactional memory processes
From: Michael Neuling @ 2012-11-27 2:48 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: Michael Neuling, linuxppc-dev, Matt Evans
In-Reply-To: <1353984488-1283-1-git-send-email-mikey@neuling.org>
When we switch out a task, we need to save both the checkpointed and the
speculated state into the thread struct.
Similarly when we are switching in a task we need to load both the checkpointed
and speculated state. If the task was using FP, we non-lazily reload both the
original and the speculative FP register states. This is because the kernel
doesn't see if/when a TM rollback occurs, so if we take an FP unavoidable
later, we are unable to determine which set of FP regs need to be restored.
This simply adds these functions. It doesn't hook them into the existing code
yet.
Signed-off-by: Matt Evans <matt@ozlabs.org>
Signed-off-by: Michael Neuling <mikey@neuling.org>
---
arch/powerpc/kernel/process.c | 113 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 113 insertions(+)
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index fd5ce1b..1bf2c6c7 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -50,6 +50,7 @@
#include <asm/runlatch.h>
#include <asm/syscalls.h>
#include <asm/switch_to.h>
+#include <asm/tm.h>
#include <asm/debug.h>
#ifdef CONFIG_PPC64
#include <asm/firmware.h>
@@ -407,6 +408,118 @@ int set_dabr(unsigned long dabr, unsigned long dabrx)
DEFINE_PER_CPU(struct cpu_usage, cpu_usage_array);
#endif
+#ifdef CONFIG_TRANSACTIONAL_MEM
+static inline void tm_reclaim_task(struct task_struct *tsk)
+{
+ /* We have to work out if we're switching from/to a task that's in the
+ * middle of a transaction.
+ *
+ * In switching we need to maintain a 2nd register state as
+ * oldtask->thread.ckpt_regs. We tm_reclaim(oldproc); this saves the
+ * checkpointed (tbegin) state in ckpt_regs and saves the transactional
+ * (current) FPRs into oldtask->thread.transact_fpr[].
+ *
+ * We also context switch (save) TFHAR/TEXASR/TFIAR in here.
+ */
+ struct thread_struct *thr = &tsk->thread;
+
+ if (!thr->regs)
+ return;
+
+ if (!MSR_TM_ACTIVE(thr->regs->msr))
+ goto out_and_saveregs;
+
+ /* Stash the original thread MSR, as giveup_fpu et al will
+ * modify it. We hold onto it to see whether the task used
+ * FP & vector regs.
+ */
+ thr->tm_orig_msr = thr->regs->msr;
+
+ TM_DEBUG("--- tm_reclaim on pid %d (NIP=%lx, "
+ "ccr=%lx, msr=%lx, trap=%lx)\n",
+ tsk->pid, thr->regs->nip,
+ thr->regs->ccr, thr->regs->msr,
+ thr->regs->trap);
+
+ tm_reclaim(thr, thr->regs->msr, TM_CAUSE_RESCHED);
+
+ TM_DEBUG("--- tm_reclaim on pid %d complete\n",
+ tsk->pid);
+
+out_and_saveregs:
+ /* Always save the regs here, even if a transaction's not active.
+ * This context-switches a thread's TM info SPRs. We do it here to
+ * be consistent with the restore path (in recheckpoint) which
+ * cannot happen later in _switch().
+ */
+ tm_save_sprs(thr);
+}
+
+static inline void __maybe_unused tm_recheckpoint_new_task(struct task_struct *new)
+{
+ unsigned long msr;
+
+ if (!cpu_has_feature(CPU_FTR_TM))
+ return;
+
+ /* Recheckpoint the registers of the thread we're about to switch to.
+ *
+ * If the task was using FP, we non-lazily reload both the original and
+ * the speculative FP register states. This is because the kernel
+ * doesn't see if/when a TM rollback occurs, so if we take an FP
+ * unavoidable later, we are unable to determine which set of FP regs
+ * need to be restored.
+ */
+ if (!new->thread.regs)
+ return;
+
+ /* The TM SPRs are restored here, so that TEXASR.FS can be set
+ * before the trecheckpoint and no explosion occurs.
+ */
+ tm_restore_sprs(&new->thread);
+
+ if (!MSR_TM_ACTIVE(new->thread.regs->msr))
+ return;
+ msr = new->thread.tm_orig_msr;
+ /* Recheckpoint to restore original checkpointed register state. */
+ TM_DEBUG("*** tm_recheckpoint of pid %d "
+ "(new->msr 0x%lx, new->origmsr 0x%lx)\n",
+ new->pid, new->thread.regs->msr, msr);
+
+ /* This loads the checkpointed FP/VEC state, if used */
+ tm_recheckpoint(&new->thread, msr);
+
+ /* This loads the speculative FP/VEC state, if used */
+ if (msr & MSR_FP) {
+ do_load_up_transact_fpu(&new->thread);
+ new->thread.regs->msr |=
+ (MSR_FP | new->thread.fpexc_mode);
+ }
+ if (msr & MSR_VEC) {
+ do_load_up_transact_altivec(&new->thread);
+ new->thread.regs->msr |= MSR_VEC;
+ }
+ /* We may as well turn on VSX too since all the state is restored now */
+ if (msr & MSR_VSX)
+ new->thread.regs->msr |= MSR_VSX;
+
+ TM_DEBUG("*** tm_recheckpoint of pid %d complete "
+ "(kernel msr 0x%lx)\n",
+ new->pid, mfmsr());
+}
+
+static inline void __switch_to_tm(struct task_struct *prev)
+{
+ if (cpu_has_feature(CPU_FTR_TM)) {
+ tm_enable();
+ tm_reclaim_task(prev);
+ }
+}
+#else
+#define tm_recheckpoint_new_task(new)
+#define __switch_to_tm(prev)
+#endif /* CONFIG_TRANSACTIONAL_MEM */
+
struct task_struct *__switch_to(struct task_struct *prev,
struct task_struct *new)
{
--
1.7.9.5
^ permalink raw reply related
* [PATCH 08/16] powerpc: Add FP/VSX and VMX register load functions for transactional memory
From: Michael Neuling @ 2012-11-27 2:48 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: Michael Neuling, linuxppc-dev, Matt Evans
In-Reply-To: <1353984488-1283-1-git-send-email-mikey@neuling.org>
This adds functions to restore the state of the FP/VSX registers from
what's stored in the thread_struct. Two version for FP/VSX are required
since one restores them from transactional/checkpoint side of the
thread_struct and the other from the speculated side.
Similar functions are added for VMX registers.
Signed-off-by: Matt Evans <matt@ozlabs.org>
Signed-off-by: Michael Neuling <mikey@neuling.org>
---
arch/powerpc/kernel/fpu.S | 54 ++++++++++++++++++++++++++++++++++++++++++
arch/powerpc/kernel/vector.S | 51 +++++++++++++++++++++++++++++++++++++++
2 files changed, 105 insertions(+)
diff --git a/arch/powerpc/kernel/fpu.S b/arch/powerpc/kernel/fpu.S
index adb1551..6ab0e87 100644
--- a/arch/powerpc/kernel/fpu.S
+++ b/arch/powerpc/kernel/fpu.S
@@ -62,6 +62,60 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX); \
__REST_32FPVSRS_TRANSACT(n,__REG_##c,__REG_##base)
#define SAVE_32FPVSRS(n,c,base) __SAVE_32FPVSRS(n,__REG_##c,__REG_##base)
+#ifdef CONFIG_TRANSACTIONAL_MEM
+/*
+ * Wrapper to call load_up_fpu from C.
+ * void do_load_up_fpu(struct pt_regs *regs);
+ */
+_GLOBAL(do_load_up_fpu)
+ mflr r0
+ std r0, 16(r1)
+ stdu r1, -112(r1)
+
+ subi r6, r3, STACK_FRAME_OVERHEAD
+ /* load_up_fpu expects r12=MSR, r13=PACA, and returns
+ * with r12 = new MSR.
+ */
+ ld r12,_MSR(r6)
+ GET_PACA(r13)
+
+ bl load_up_fpu
+ std r12,_MSR(r6)
+
+ ld r0, 112+16(r1)
+ addi r1, r1, 112
+ mtlr r0
+ blr
+
+
+/* void do_load_up_fpu(struct thread_struct *thread)
+ *
+ * This is similar to load_up_fpu but for the transactional version of the FP
+ * register set. It doesn't mess with the task MSR or valid flags.
+ * Furthermore, we don't do lazy FP with TM currently.
+ */
+_GLOBAL(do_load_up_transact_fpu)
+ mfmsr r6
+ ori r5,r6,MSR_FP
+#ifdef CONFIG_VSX
+BEGIN_FTR_SECTION
+ oris r5,r5,MSR_VSX@h
+END_FTR_SECTION_IFSET(CPU_FTR_VSX)
+#endif
+ SYNC
+ MTMSRD(r5)
+
+ lfd fr0,THREAD_TRANSACT_FPSCR(r3)
+ MTFSF_L(fr0)
+ REST_32FPVSRS_TRANSACT(0, R4, R3)
+
+ /* FP/VSX off again */
+ MTMSRD(r6)
+ SYNC
+
+ blr
+#endif /* CONFIG_TRANSACTIONAL_MEM */
+
/*
* This task wants to use the FPU now.
* On UP, disable FP for the task which had the FPU previously,
diff --git a/arch/powerpc/kernel/vector.S b/arch/powerpc/kernel/vector.S
index e830289..330fc8c 100644
--- a/arch/powerpc/kernel/vector.S
+++ b/arch/powerpc/kernel/vector.S
@@ -7,6 +7,57 @@
#include <asm/page.h>
#include <asm/ptrace.h>
+#ifdef CONFIG_TRANSACTIONAL_MEM
+/*
+ * Wrapper to call load_up_altivec from C.
+ * void do_load_up_altivec(struct pt_regs *regs);
+ */
+_GLOBAL(do_load_up_altivec)
+ mflr r0
+ std r0, 16(r1)
+ stdu r1, -112(r1)
+
+ subi r6, r3, STACK_FRAME_OVERHEAD
+ /* load_up_altivec expects r12=MSR, r13=PACA, and returns
+ * with r12 = new MSR.
+ */
+ ld r12,_MSR(r6)
+ GET_PACA(r13)
+ bl load_up_altivec
+ std r12,_MSR(r6)
+
+ ld r0, 112+16(r1)
+ addi r1, r1, 112
+ mtlr r0
+ blr
+
+/* void do_load_up_altivec(struct thread_struct *thread)
+ *
+ * This is similar to load_up_altivec but for the transactional version of the
+ * vector regs. It doesn't mess with the task MSR or valid flags.
+ * Furthermore, VEC laziness is not supported with TM currently.
+ */
+_GLOBAL(do_load_up_transact_altivec)
+ mfmsr r6
+ oris r5,r6,MSR_VEC@h
+ MTMSRD(r5)
+ isync
+
+ li r4,1
+ stw r4,THREAD_USED_VR(r3)
+
+ li r10,THREAD_TRANSACT_VSCR
+ lvx vr0,r10,r3
+ mtvscr vr0
+ REST_32VRS_TRANSACT(0,r4,r3)
+
+ /* Disable VEC again. */
+ MTMSRD(r6)
+ isync
+
+ blr
+#endif
+
/*
* load_up_altivec(unused, unused, tsk)
* Disable VMX for the task which had it previously,
--
1.7.9.5
^ permalink raw reply related
* [PATCH 07/16] powerpc: Add helper functions for transactional memory context switching
From: Michael Neuling @ 2012-11-27 2:47 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: Michael Neuling, linuxppc-dev, Matt Evans
In-Reply-To: <1353984488-1283-1-git-send-email-mikey@neuling.org>
Here we add the helper functions to be used when context switching. These
allow us to fully reclaim and recheckpoint a transaction.
Signed-off-by: Matt Evans <matt@ozlabs.org>
Signed-off-by: Michael Neuling <mikey@neuling.org>
---
arch/powerpc/include/asm/reg.h | 2 +-
arch/powerpc/include/asm/tm.h | 19 ++
arch/powerpc/kernel/Makefile | 2 +
arch/powerpc/kernel/tm.S | 378 ++++++++++++++++++++++++++++++++++++++++
4 files changed, 400 insertions(+), 1 deletion(-)
create mode 100644 arch/powerpc/include/asm/tm.h
create mode 100644 arch/powerpc/kernel/tm.S
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index bea823f..895020f 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -784,7 +784,7 @@
* HV mode in which case it is HSPRG0
*
* 64-bit server:
- * - SPRG0 unused (reserved for HV on Power4)
+ * - SPRG0 scratch for TM recheckpoint/reclaim (reserved for HV on Power4)
* - SPRG2 scratch for exception vectors
* - SPRG3 CPU and NUMA node for VDSO getcpu (user visible)
* - HSPRG0 stores PACA in HV mode
diff --git a/arch/powerpc/include/asm/tm.h b/arch/powerpc/include/asm/tm.h
new file mode 100644
index 0000000..18f6bf7
--- /dev/null
+++ b/arch/powerpc/include/asm/tm.h
@@ -0,0 +1,19 @@
+/*
+ * Transactional memory support routines to reclaim and recheckpoint
+ * transactional process state.
+ *
+ * Copyright 2012 Matt Evans & Michael Neuling, IBM Corporation.
+ */
+
+#ifdef CONFIG_TRANSACTIONAL_MEM
+extern void do_load_up_transact_fpu(struct thread_struct *thread);
+extern void do_load_up_transact_altivec(struct thread_struct *thread);
+#endif
+
+extern void tm_enable(void);
+extern void tm_reclaim(struct thread_struct *thread,
+ unsigned long orig_msr, uint8_t cause);
+extern void tm_recheckpoint(struct thread_struct *thread,
+ unsigned long orig_msr);
+extern void tm_save_sprs(struct thread_struct *thread);
+extern void tm_restore_sprs(struct thread_struct *thread);
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 44fbbea..abf8469 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -122,6 +122,8 @@ ifneq ($(CONFIG_PPC_INDIRECT_IO),y)
obj-y += iomap.o
endif
+obj64-$(CONFIG_TRANSACTIONAL_MEM) += tm.o
+
obj-$(CONFIG_PPC64) += $(obj64-y)
obj-$(CONFIG_PPC32) += $(obj32-y)
diff --git a/arch/powerpc/kernel/tm.S b/arch/powerpc/kernel/tm.S
new file mode 100644
index 0000000..b368e4a
--- /dev/null
+++ b/arch/powerpc/kernel/tm.S
@@ -0,0 +1,378 @@
+/*
+ * Transactional memory support routines to reclaim and recheckpoint
+ * transactional process state.
+ *
+ * Copyright 2012 Matt Evans & Michael Neuling, IBM Corporation.
+ */
+
+#include <asm/asm-offsets.h>
+#include <asm/ppc_asm.h>
+#include <asm/ppc-opcode.h>
+#include <asm/ptrace.h>
+#include <asm/reg.h>
+
+#ifdef CONFIG_VSX
+/* See fpu.S, this is very similar but to save/restore checkpointed FPRs/VSRs */
+#define __SAVE_32FPRS_VSRS_TRANSACT(n,c,base) \
+BEGIN_FTR_SECTION \
+ b 2f; \
+END_FTR_SECTION_IFSET(CPU_FTR_VSX); \
+ SAVE_32FPRS_TRANSACT(n,base); \
+ b 3f; \
+2: SAVE_32VSRS_TRANSACT(n,c,base); \
+3:
+/* ...and this is just plain borrowed from there. */
+#define __REST_32FPRS_VSRS(n,c,base) \
+BEGIN_FTR_SECTION \
+ b 2f; \
+END_FTR_SECTION_IFSET(CPU_FTR_VSX); \
+ REST_32FPRS(n,base); \
+ b 3f; \
+2: REST_32VSRS(n,c,base); \
+3:
+#else
+#define __SAVE_32FPRS_VSRS_TRANSACT(n,c,base) SAVE_32FPRS_TRANSACT(n, base)
+#define __REST_32FPRS_VSRS(n,c,base) REST_32FPRS(n, base)
+#endif
+#define SAVE_32FPRS_VSRS_TRANSACT(n,c,base) \
+ __SAVE_32FPRS_VSRS_TRANSACT(n,__REG_##c,__REG_##base)
+#define REST_32FPRS_VSRS(n,c,base) \
+ __REST_32FPRS_VSRS(n,__REG_##c,__REG_##base)
+
+/* Stack frame offsets for local variables. */
+#define TM_FRAME_L0 TM_FRAME_SIZE-16
+#define TM_FRAME_L1 TM_FRAME_SIZE-8
+#define STACK_PARAM(x) (48+((x)*8))
+
+
+/* In order to access the TM SPRs, TM must be enabled. So, do so: */
+_GLOBAL(tm_enable)
+ mfmsr r4
+ li r3, MSR_TM >> 32
+ sldi r3, r3, 32
+ and. r0, r4, r3
+ bne 1f
+ or r4, r4, r3
+ mtmsrd r4
+1: blr
+
+_GLOBAL(tm_save_sprs)
+ mfspr r0, SPRN_TFHAR
+ std r0, THREAD_TM_TFHAR(r3)
+ mfspr r0, SPRN_TEXASR
+ std r0, THREAD_TM_TEXASR(r3)
+ mfspr r0, SPRN_TFIAR
+ std r0, THREAD_TM_TFIAR(r3)
+ blr
+
+_GLOBAL(tm_restore_sprs)
+ ld r0, THREAD_TM_TFHAR(r3)
+ mtspr SPRN_TFHAR, r0
+ ld r0, THREAD_TM_TEXASR(r3)
+ mtspr SPRN_TEXASR, r0
+ ld r0, THREAD_TM_TFIAR(r3)
+ mtspr SPRN_TFIAR, r0
+ blr
+
+
+/* void tm_reclaim(struct thread_struct *thread,
+ * unsigned long orig_msr,
+ * uint8_t cause)
+ *
+ * - Performs a full reclaim. This destroys outstanding
+ * transactions and updates thread->regs.tm_ckpt_* with the
+ * original checkpointed state. Note that thread->regs is
+ * unchanged.
+ * - FP regs are written back to thread->transact_fpr before
+ * reclaiming. These are the transactional (current) versions.
+ *
+ * Purpose is to both abort transactions of, and preserve the state of,
+ * a transactions at a context switch. We preserve/restore both sets of process
+ * state to restore them when the thread's scheduled again. We continue in
+ * userland as though nothing happened, but when the transaction is resumed
+ * they will abort back to the checkpointed state we save out here.
+ */
+_GLOBAL(tm_reclaim)
+ mfcr r6
+ mflr r0
+ std r6, 8(r1)
+ std r0, 16(r1)
+ std r2, 40(r1)
+ stdu r1, -TM_FRAME_SIZE(r1)
+
+ /* We've a struct pt_regs at [r1+STACK_FRAME_OVERHEAD]. */
+
+ std r3, STACK_PARAM(0)(r1)
+ SAVE_NVGPRS(r1)
+
+ /* hard_irq_disable */
+ mfmsr r14
+ li r6, MSR_EE-1
+ addi r6, r6, 1 /* Get around sxt on 0x8000 */
+ andc r15, r14, r6
+ ori r15, r15, MSR_FP
+ oris r15, r15, MSR_VEC@h
+#ifdef CONFIG_VSX
+ BEGIN_FTR_SECTION
+ oris r15,r15, MSR_VSX@h
+ END_FTR_SECTION_IFSET(CPU_FTR_VSX)
+#endif
+ mtmsrd r15
+ std r14, TM_FRAME_L0(r1)
+
+ std r1, PACAR1(r13)
+
+ /* ******************** FPR/VR/VSRs ************
+ * Before reclaiming, capture the current/transactional FPR/VR
+ * versions /if used/.
+ *
+ * (If VSX used, FP and VMX are implied. Or, we don't need to look
+ * at MSR.VSX as copying FP regs if .FP, vector regs if .VMX covers it.)
+ *
+ * We're passed the thread's MSR as parameter 2.
+ *
+ * We enabled VEC/FP/VSX in the msr above, so we can execute these
+ * instructions!
+ */
+ andis. r0, r4, MSR_VEC@h
+ beq dont_backup_vec
+
+ SAVE_32VRS_TRANSACT(0, r6, r3) /* r6 scratch, r3 thread */
+ mfvscr vr0
+ li r6, THREAD_TRANSACT_VSCR
+ stvx vr0, r3, r6
+ mfspr r0, SPRN_VRSAVE
+ std r0, THREAD_TRANSACT_VRSAVE(r3)
+
+dont_backup_vec:
+ andi. r0, r4, MSR_FP
+ beq dont_backup_fp
+
+ SAVE_32FPRS_VSRS_TRANSACT(0, R6, R3) /* r6 scratch, r3 thread */
+
+ mffs fr0
+ stfd fr0,THREAD_TRANSACT_FPSCR(r3)
+
+dont_backup_fp:
+ /* The moment we treclaim, ALL of our GPRs will switch
+ * to user register state. (FPRs, CCR etc. also!)
+ * Use an sprg and a scratch dword in the PACA to shuffle.
+ */
+ TRECLAIM(R5) /* Cause in r5 */
+
+ /* ******************** GPRs ******************** */
+ SET_SCRATCH0(r13)
+ GET_PACA(r13)
+ std r1, PACATMSCRATCH(r13)
+
+ ld r1, PACAR1(r13) /* Get our stack back */
+ /* Temporarily stash checkpointed r0 here to get another
+ * scratch reg for our userland pt_regs pointer:
+ */
+ std r7, GPR7(r1) /* Temporary stash */
+ std r12, GPR12(r1) /* '' '' '' */
+ ld r12, STACK_PARAM(0)(r1) /* Param 0, thread_struct * */
+
+ addi r7, r12, PT_CKPT_REGS /* Thread's ckpt_regs */
+
+ /* Make r7 look like an exception frame so that we
+ * can use the neat GPRx(n) macros. r7 is NOT a pt_regs ptr!
+ */
+ subi r7, r7, STACK_FRAME_OVERHEAD
+
+ /* Sync the userland GPRs 2-12, 14-31 to thread->regs: */
+ SAVE_GPR(0, r7) /* user r0 */
+ SAVE_GPR(2, r7) /* user r2 */
+ SAVE_4GPRS(3, r7) /* user r3-r6 */
+ SAVE_4GPRS(8, r7) /* user r8-r11 */
+ ld r3, PACATMSCRATCH(r13) /* user r1 */
+ ld r4, GPR7(r1) /* user r7 */
+ ld r5, GPR12(r1) /* user r12 */
+ GET_SCRATCH0(6) /* user r13 */
+ std r3, GPR1(r7)
+ std r4, GPR7(r7)
+ std r5, GPR12(r7)
+ std r6, GPR13(r7)
+
+ SAVE_NVGPRS(r7) /* user r14-r31 */
+
+ /* ******************** NIP ******************** */
+ mfspr r3, SPRN_TFHAR
+ std r3, _NIP(r7) /* Returns to failhandler */
+ /* The checkpointed NIP is ignored when rescheduling/rechkpting,
+ * but is used in signal return to 'wind back' to the abort handler.
+ */
+
+ /* ******************** CR,LR,CCR,MSR ********** */
+ mfctr r3
+ mflr r4
+ mfcr r5
+ mfxer r6
+
+ std r3, _CTR(r7)
+ std r4, _LINK(r7)
+ std r5, _CCR(r7)
+ std r6, _XER(r7)
+
+ /* MSR and flags: We don't change CRs, and we don't need to alter
+ * MSR.
+ */
+
+ /* TM regs, incl TEXASR -- these live in thread_struct. Note they've
+ * been updated by the treclaim, to explain to userland the failure
+ * cause (aborted).
+ */
+ mfspr r0, SPRN_TEXASR
+ mfspr r3, SPRN_TFHAR
+ mfspr r4, SPRN_TFIAR
+ std r0, THREAD_TM_TEXASR(r12)
+ std r3, THREAD_TM_TFHAR(r12)
+ std r4, THREAD_TM_TFIAR(r12)
+
+ /* AMR and PPR are checkpointed too, but are unsupported by Linux. */
+
+ /* Restore original MSR/IRQ state & clear TM mode */
+ ld r14, TM_FRAME_L0(r1) /* Orig MSR */
+ li r15, 0
+ rldimi r14, r15, MSR_TS_LG, (63-MSR_TS_LG)-1
+ mtmsrd r14
+
+ REST_NVGPRS(r1)
+
+ addi r1, r1, TM_FRAME_SIZE
+ ld r4, 8(r1)
+ ld r0, 16(r1)
+ mtcr r4
+ mtlr r0
+ ld r2, 40(r1)
+ blr
+
+
+ /* void tm_recheckpoint(struct thread_struct *thread,
+ * unsigned long orig_msr)
+ * - Restore the checkpointed register state saved by tm_reclaim
+ * when we switch_to a process.
+ *
+ * Call with IRQs off, stacks get all out of sync for
+ * some periods in here!
+ */
+_GLOBAL(tm_recheckpoint)
+ mfcr r5
+ mflr r0
+ std r5, 8(r1)
+ std r0, 16(r1)
+ std r2, 40(r1)
+ stdu r1, -TM_FRAME_SIZE(r1)
+
+ /* We've a struct pt_regs at [r1+STACK_FRAME_OVERHEAD].
+ * This is used for backing up the NVGPRs:
+ */
+ SAVE_NVGPRS(r1)
+
+ std r1, PACAR1(r13)
+
+ /* Load complete register state from ts_ckpt* registers */
+
+ addi r7, r3, PT_CKPT_REGS /* Thread's ckpt_regs */
+
+ /* Make r7 look like an exception frame so that we
+ * can use the neat GPRx(n) macros. r7 is now NOT a pt_regs ptr!
+ */
+ subi r7, r7, STACK_FRAME_OVERHEAD
+
+ SET_SCRATCH0(r1)
+
+ mfmsr r6
+ /* R4 = original MSR to indicate whether thread used FP/Vector etc. */
+
+ /* Enable FP/vec in MSR if necessary! */
+ lis r5, MSR_VEC@h
+ ori r5, r5, MSR_FP
+ and. r5, r4, r5
+ beq restore_gprs /* if neither, skip both */
+
+#ifdef CONFIG_VSX
+ BEGIN_FTR_SECTION
+ oris r5, r5, MSR_VSX@h
+ END_FTR_SECTION_IFSET(CPU_FTR_VSX)
+#endif
+ or r5, r6, r5 /* Set MSR.FP+.VSX/.VEC */
+ mtmsr r5
+
+ /* FP and VEC registers: These are recheckpointed from thread.fpr[]
+ * and thread.vr[] respectively. The thread.transact_fpr[] version
+ * is more modern, and will be loaded subsequently by any FPUnavailable
+ * trap.
+ */
+ andis. r0, r4, MSR_VEC@h
+ beq dont_restore_vec
+
+ li r5, THREAD_VSCR
+ lvx vr0, r3, r5
+ mtvscr vr0
+ REST_32VRS(0, r5, r3) /* r5 scratch, r3 THREAD ptr */
+ ld r5, THREAD_VRSAVE(r3)
+ mtspr SPRN_VRSAVE, r5
+
+dont_restore_vec:
+ andi. r0, r4, MSR_FP
+ beq dont_restore_fp
+
+ lfd fr0, THREAD_FPSCR(r3)
+ MTFSF_L(fr0)
+ REST_32FPRS_VSRS(0, R4, R3)
+
+dont_restore_fp:
+ mtmsr r6 /* FP/Vec off again! */
+
+restore_gprs:
+ /* ******************** CR,LR,CCR,MSR ********** */
+ ld r3, _CTR(r7)
+ ld r4, _LINK(r7)
+ ld r5, _CCR(r7)
+ ld r6, _XER(r7)
+
+ mtctr r3
+ mtlr r4
+ mtcr r5
+ mtxer r6
+
+ /* MSR and flags: We don't change CRs, and we don't need to alter
+ * MSR.
+ */
+
+ REST_4GPRS(0, r7) /* GPR0-3 */
+ REST_GPR(4, r7) /* GPR4-6 */
+ REST_GPR(5, r7)
+ REST_GPR(6, r7)
+ REST_4GPRS(8, r7) /* GPR8-11 */
+ REST_2GPRS(12, r7) /* GPR12-13 */
+
+ REST_NVGPRS(r7) /* GPR14-31 */
+
+ ld r7, GPR7(r7) /* GPR7 */
+
+ /* Commit register state as checkpointed state: */
+ TRECHKPT
+
+ /* Our transactional state has now changed.
+ *
+ * Now just get out of here. Transactional (current) state will be
+ * updated once restore is called on the return path in the _switch-ed
+ * -to process.
+ */
+
+ GET_PACA(r13)
+ GET_SCRATCH0(r1)
+
+ REST_NVGPRS(r1)
+
+ addi r1, r1, TM_FRAME_SIZE
+ ld r4, 8(r1)
+ ld r0, 16(r1)
+ mtcr r4
+ mtlr r0
+ ld r2, 40(r1)
+ blr
+
+ /* ****************************************************************** */
--
1.7.9.5
^ permalink raw reply related
* [PATCH 06/16] powerpc: Add transactional memory paca scratch register to show_regs
From: Michael Neuling @ 2012-11-27 2:47 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: Michael Neuling, linuxppc-dev, Matt Evans
In-Reply-To: <1353984488-1283-1-git-send-email-mikey@neuling.org>
Add transactional memory paca scratch register to show_regs. This is useful
for debugging.
Signed-off-by: Matt Evans <matt@ozlabs.org>
Signed-off-by: Michael Neuling <mikey@neuling.org>
---
arch/powerpc/include/asm/paca.h | 1 +
arch/powerpc/kernel/asm-offsets.c | 1 +
arch/powerpc/kernel/entry_64.S | 4 ++++
arch/powerpc/kernel/process.c | 3 +++
4 files changed, 9 insertions(+)
diff --git a/arch/powerpc/include/asm/paca.h b/arch/powerpc/include/asm/paca.h
index e9e7a69..0168516 100644
--- a/arch/powerpc/include/asm/paca.h
+++ b/arch/powerpc/include/asm/paca.h
@@ -137,6 +137,7 @@ struct paca_struct {
u8 irq_work_pending; /* IRQ_WORK interrupt while soft-disable */
u8 nap_state_lost; /* NV GPR values lost in power7_idle */
u64 sprg3; /* Saved user-visible sprg */
+ u64 tm_scratch; /* TM scratch area for reclaim */
#ifdef CONFIG_PPC_POWERNV
/* Pointer to OPAL machine check event structure set by the
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 1a70f02..42a4243 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -122,6 +122,7 @@ int main(void)
#endif
#ifdef CONFIG_TRANSACTIONAL_MEM
+ DEFINE(PACATMSCRATCH, offsetof(struct paca_struct, tm_scratch));
DEFINE(THREAD_TM_TFHAR, offsetof(struct thread_struct, tm_tfhar));
DEFINE(THREAD_TM_TEXASR, offsetof(struct thread_struct, tm_texasr));
DEFINE(THREAD_TM_TFIAR, offsetof(struct thread_struct, tm_tfiar));
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index df6857f..5ae8e51 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -755,6 +755,10 @@ fast_exception_return:
andc r4,r4,r0 /* r0 contains MSR_RI here */
mtmsrd r4,1
+#ifdef CONFIG_TRANSACTIONAL_MEM
+ /* TM debug */
+ std r3, PACATMSCRATCH(r13) /* Stash returned-to MSR */
+#endif
/*
* r13 is our per cpu area, only restore it if we are returning to
* userspace the value stored in the stack frame may belong to
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 6d66a68..fd5ce1b 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -693,6 +693,9 @@ void show_regs(struct pt_regs * regs)
printk("NIP ["REG"] %pS\n", regs->nip, (void *)regs->nip);
printk("LR ["REG"] %pS\n", regs->link, (void *)regs->link);
#endif
+#ifdef CONFIG_TRANSACTIONAL_MEM
+ printk("PACATMSCRATCH [%llx]\n", get_paca()->tm_scratch);
+#endif
show_stack(current, (unsigned long *) regs->gpr[1]);
if (!user_mode(regs))
show_instructions(regs);
--
1.7.9.5
^ permalink raw reply related
* [PATCH 05/16] powerpc: Register defines for various transactional memory registers
From: Michael Neuling @ 2012-11-27 2:47 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: Michael Neuling, linuxppc-dev, Matt Evans
In-Reply-To: <1353984488-1283-1-git-send-email-mikey@neuling.org>
Defines for MSR bits and transactional memory related SPRs TFIAR, TEXASR and
TEXASRU.
Signed-off-by: Matt Evans <matt@ozlabs.org>
Signed-off-by: Michael Neuling <mikey@neuling.org>
---
arch/powerpc/include/asm/reg.h | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index 736c6af..bea823f 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -29,6 +29,8 @@
#define MSR_SF_LG 63 /* Enable 64 bit mode */
#define MSR_ISF_LG 61 /* Interrupt 64b mode valid on 630 */
#define MSR_HV_LG 60 /* Hypervisor state */
+#define MSR_TS_LG 33 /* Transactional Mem State (2 bits) */
+#define MSR_TM_LG 32 /* Transactional Mem Available */
#define MSR_VEC_LG 25 /* Enable AltiVec */
#define MSR_VSX_LG 23 /* Enable VSX */
#define MSR_POW_LG 18 /* Enable Power Management */
@@ -98,6 +100,21 @@
#define MSR_RI __MASK(MSR_RI_LG) /* Recoverable Exception */
#define MSR_LE __MASK(MSR_LE_LG) /* Little Endian */
+#define MSR_TM __MASK(MSR_TM_LG) /* Transactional Mem Available */
+#define MSR_TS_MASK (__MASK(MSR_TS_LG) | \
+ __MASK(MSR_TS_LG+1)) /* Transaction State bits */
+#define MSR_TM_ACTIVE(x) (((x) & MSR_TS_MASK) != 0) /* Transaction active? */
+
+/* Reason codes describing kernel causes for transaction aborts. By
+ convention, bit0 is copied to TEXASR[56] (IBM bit 7) which is set if
+ the failure is persistent.
+*/
+#define TM_CAUSE_RESCHED 0xfe
+#define TM_CAUSE_TLBI 0xfc
+#define TM_CAUSE_FAC_UNAV 0xfa
+#define TM_CAUSE_SYSCALL 0xf9 /* Persistent */
+#define TM_CAUSE_MISC 0xf6
+
#if defined(CONFIG_PPC_BOOK3S_64)
#define MSR_64BIT MSR_SF
@@ -193,6 +210,10 @@
#define SPRN_UAMOR 0x9d /* User Authority Mask Override Register */
#define SPRN_AMOR 0x15d /* Authority Mask Override Register */
#define SPRN_ACOP 0x1F /* Available Coprocessor Register */
+#define SPRN_TFIAR 0x81 /* Transaction Failure Inst Addr */
+#define SPRN_TEXASR 0x82 /* Transaction EXception & Summary */
+#define SPRN_TEXASRU 0x83 /* '' '' '' Upper 32 */
+#define SPRN_TFHAR 0x80 /* Transaction Failure Handler Addr */
#define SPRN_CTRLF 0x088
#define SPRN_CTRLT 0x098
#define CTRL_CT 0xc0000000 /* current thread */
--
1.7.9.5
^ permalink raw reply related
* [PATCH 04/16] powerpc: New macros for transactional memory support
From: Michael Neuling @ 2012-11-27 2:47 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: Michael Neuling, linuxppc-dev, Matt Evans
In-Reply-To: <1353984488-1283-1-git-send-email-mikey@neuling.org>
This adds new macros for saving and restoring checkpointed architected state
from and to the thread_struct.
It also adds some debugging macros for when your brain explodes trying to debug
your transactional memory enabled kernel.
Signed-off-by: Matt Evans <matt@ozlabs.org>
Signed-off-by: Michael Neuling <mikey@neuling.org>
---
arch/powerpc/include/asm/ppc_asm.h | 83 ++++++++++++++++++++++++++++++++++
arch/powerpc/include/asm/processor.h | 1 +
arch/powerpc/kernel/asm-offsets.c | 24 ++++++++++
arch/powerpc/kernel/fpu.S | 12 +++++
arch/powerpc/kernel/process.c | 10 ++++
arch/powerpc/kernel/traps.c | 11 +++++
6 files changed, 141 insertions(+)
diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h
index ea2a86e..a17a598 100644
--- a/arch/powerpc/include/asm/ppc_asm.h
+++ b/arch/powerpc/include/asm/ppc_asm.h
@@ -125,6 +125,89 @@ END_FW_FTR_SECTION_IFSET(FW_FEATURE_SPLPAR)
#define REST_16VRS(n,b,base) REST_8VRS(n,b,base); REST_8VRS(n+8,b,base)
#define REST_32VRS(n,b,base) REST_16VRS(n,b,base); REST_16VRS(n+16,b,base)
+/* Save/restore FPRs, VRs and VSRs from their checkpointed backups in
+ * thread_struct:
+ */
+#define SAVE_FPR_TRANSACT(n, base) stfd n,THREAD_TRANSACT_FPR0+ \
+ 8*TS_FPRWIDTH*(n)(base)
+#define SAVE_2FPRS_TRANSACT(n, base) SAVE_FPR_TRANSACT(n, base); \
+ SAVE_FPR_TRANSACT(n+1, base)
+#define SAVE_4FPRS_TRANSACT(n, base) SAVE_2FPRS_TRANSACT(n, base); \
+ SAVE_2FPRS_TRANSACT(n+2, base)
+#define SAVE_8FPRS_TRANSACT(n, base) SAVE_4FPRS_TRANSACT(n, base); \
+ SAVE_4FPRS_TRANSACT(n+4, base)
+#define SAVE_16FPRS_TRANSACT(n, base) SAVE_8FPRS_TRANSACT(n, base); \
+ SAVE_8FPRS_TRANSACT(n+8, base)
+#define SAVE_32FPRS_TRANSACT(n, base) SAVE_16FPRS_TRANSACT(n, base); \
+ SAVE_16FPRS_TRANSACT(n+16, base)
+
+#define REST_FPR_TRANSACT(n, base) lfd n,THREAD_TRANSACT_FPR0+ \
+ 8*TS_FPRWIDTH*(n)(base)
+#define REST_2FPRS_TRANSACT(n, base) REST_FPR_TRANSACT(n, base); \
+ REST_FPR_TRANSACT(n+1, base)
+#define REST_4FPRS_TRANSACT(n, base) REST_2FPRS_TRANSACT(n, base); \
+ REST_2FPRS_TRANSACT(n+2, base)
+#define REST_8FPRS_TRANSACT(n, base) REST_4FPRS_TRANSACT(n, base); \
+ REST_4FPRS_TRANSACT(n+4, base)
+#define REST_16FPRS_TRANSACT(n, base) REST_8FPRS_TRANSACT(n, base); \
+ REST_8FPRS_TRANSACT(n+8, base)
+#define REST_32FPRS_TRANSACT(n, base) REST_16FPRS_TRANSACT(n, base); \
+ REST_16FPRS_TRANSACT(n+16, base)
+
+
+#define SAVE_VR_TRANSACT(n,b,base) li b,THREAD_TRANSACT_VR0+(16*(n)); \
+ stvx n,b,base
+#define SAVE_2VRS_TRANSACT(n,b,base) SAVE_VR_TRANSACT(n,b,base); \
+ SAVE_VR_TRANSACT(n+1,b,base)
+#define SAVE_4VRS_TRANSACT(n,b,base) SAVE_2VRS_TRANSACT(n,b,base); \
+ SAVE_2VRS_TRANSACT(n+2,b,base)
+#define SAVE_8VRS_TRANSACT(n,b,base) SAVE_4VRS_TRANSACT(n,b,base); \
+ SAVE_4VRS_TRANSACT(n+4,b,base)
+#define SAVE_16VRS_TRANSACT(n,b,base) SAVE_8VRS_TRANSACT(n,b,base); \
+ SAVE_8VRS_TRANSACT(n+8,b,base)
+#define SAVE_32VRS_TRANSACT(n,b,base) SAVE_16VRS_TRANSACT(n,b,base); \
+ SAVE_16VRS_TRANSACT(n+16,b,base)
+
+#define REST_VR_TRANSACT(n,b,base) li b,THREAD_TRANSACT_VR0+(16*(n)); \
+ lvx n,b,base
+#define REST_2VRS_TRANSACT(n,b,base) REST_VR_TRANSACT(n,b,base); \
+ REST_VR_TRANSACT(n+1,b,base)
+#define REST_4VRS_TRANSACT(n,b,base) REST_2VRS_TRANSACT(n,b,base); \
+ REST_2VRS_TRANSACT(n+2,b,base)
+#define REST_8VRS_TRANSACT(n,b,base) REST_4VRS_TRANSACT(n,b,base); \
+ REST_4VRS_TRANSACT(n+4,b,base)
+#define REST_16VRS_TRANSACT(n,b,base) REST_8VRS_TRANSACT(n,b,base); \
+ REST_8VRS_TRANSACT(n+8,b,base)
+#define REST_32VRS_TRANSACT(n,b,base) REST_16VRS_TRANSACT(n,b,base); \
+ REST_16VRS_TRANSACT(n+16,b,base)
+
+
+#define SAVE_VSR_TRANSACT(n,b,base) li b,THREAD_TRANSACT_VSR0+(16*(n)); \
+ STXVD2X(n,R##base,R##b)
+#define SAVE_2VSRS_TRANSACT(n,b,base) SAVE_VSR_TRANSACT(n,b,base); \
+ SAVE_VSR_TRANSACT(n+1,b,base)
+#define SAVE_4VSRS_TRANSACT(n,b,base) SAVE_2VSRS_TRANSACT(n,b,base); \
+ SAVE_2VSRS_TRANSACT(n+2,b,base)
+#define SAVE_8VSRS_TRANSACT(n,b,base) SAVE_4VSRS_TRANSACT(n,b,base); \
+ SAVE_4VSRS_TRANSACT(n+4,b,base)
+#define SAVE_16VSRS_TRANSACT(n,b,base) SAVE_8VSRS_TRANSACT(n,b,base); \
+ SAVE_8VSRS_TRANSACT(n+8,b,base)
+#define SAVE_32VSRS_TRANSACT(n,b,base) SAVE_16VSRS_TRANSACT(n,b,base); \
+ SAVE_16VSRS_TRANSACT(n+16,b,base)
+
+#define REST_VSR_TRANSACT(n,b,base) li b,THREAD_TRANSACT_VSR0+(16*(n)); \
+ LXVD2X(n,R##base,R##b)
+#define REST_2VSRS_TRANSACT(n,b,base) REST_VSR_TRANSACT(n,b,base); \
+ REST_VSR_TRANSACT(n+1,b,base)
+#define REST_4VSRS_TRANSACT(n,b,base) REST_2VSRS_TRANSACT(n,b,base); \
+ REST_2VSRS_TRANSACT(n+2,b,base)
+#define REST_8VSRS_TRANSACT(n,b,base) REST_4VSRS_TRANSACT(n,b,base); \
+ REST_4VSRS_TRANSACT(n+4,b,base)
+#define REST_16VSRS_TRANSACT(n,b,base) REST_8VSRS_TRANSACT(n,b,base); \
+ REST_8VSRS_TRANSACT(n+8,b,base)
+#define REST_32VSRS_TRANSACT(n,b,base) REST_16VSRS_TRANSACT(n,b,base); \
+ REST_16VSRS_TRANSACT(n+16,b,base)
+
/* Save the lower 32 VSRs in the thread VSR region */
#define SAVE_VSR(n,b,base) li b,THREAD_VSR0+(16*(n)); STXVD2X(n,R##base,R##b)
#define SAVE_2VSRS(n,b,base) SAVE_VSR(n,b,base); SAVE_VSR(n+1,b,base)
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index 0d1c188..8b2bf7a 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -141,6 +141,7 @@ typedef struct {
#define TS_FPROFFSET 0
#define TS_VSRLOWOFFSET 1
#define TS_FPR(i) fpr[i][TS_FPROFFSET]
+#define TS_TRANS_FPR(i) transact_fpr[i][TS_FPROFFSET]
struct thread_struct {
unsigned long ksp; /* Kernel stack pointer */
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c
index 7523539..1a70f02 100644
--- a/arch/powerpc/kernel/asm-offsets.c
+++ b/arch/powerpc/kernel/asm-offsets.c
@@ -121,6 +121,30 @@ int main(void)
DEFINE(THREAD_KVM_VCPU, offsetof(struct thread_struct, kvm_vcpu));
#endif
+#ifdef CONFIG_TRANSACTIONAL_MEM
+ DEFINE(THREAD_TM_TFHAR, offsetof(struct thread_struct, tm_tfhar));
+ DEFINE(THREAD_TM_TEXASR, offsetof(struct thread_struct, tm_texasr));
+ DEFINE(THREAD_TM_TFIAR, offsetof(struct thread_struct, tm_tfiar));
+ DEFINE(PT_CKPT_REGS, offsetof(struct thread_struct, ckpt_regs));
+ DEFINE(THREAD_TRANSACT_VR0, offsetof(struct thread_struct,
+ transact_vr[0]));
+ DEFINE(THREAD_TRANSACT_VSCR, offsetof(struct thread_struct,
+ transact_vscr));
+ DEFINE(THREAD_TRANSACT_VRSAVE, offsetof(struct thread_struct,
+ transact_vrsave));
+ DEFINE(THREAD_TRANSACT_FPR0, offsetof(struct thread_struct,
+ transact_fpr[0]));
+ DEFINE(THREAD_TRANSACT_FPSCR, offsetof(struct thread_struct,
+ transact_fpscr));
+#ifdef CONFIG_VSX
+ DEFINE(THREAD_TRANSACT_VSR0, offsetof(struct thread_struct,
+ transact_fpr[0]));
+#endif
+ /* Local pt_regs on stack for Transactional Memory funcs. */
+ DEFINE(TM_FRAME_SIZE, STACK_FRAME_OVERHEAD +
+ sizeof(struct pt_regs) + 16);
+#endif /* CONFIG_TRANSACTIONAL_MEM */
+
DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
DEFINE(TI_LOCAL_FLAGS, offsetof(struct thread_info, local_flags));
DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count));
diff --git a/arch/powerpc/kernel/fpu.S b/arch/powerpc/kernel/fpu.S
index e0ada05..adb1551 100644
--- a/arch/powerpc/kernel/fpu.S
+++ b/arch/powerpc/kernel/fpu.S
@@ -35,6 +35,15 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX); \
2: REST_32VSRS(n,c,base); \
3:
+#define __REST_32FPVSRS_TRANSACT(n,c,base) \
+BEGIN_FTR_SECTION \
+ b 2f; \
+END_FTR_SECTION_IFSET(CPU_FTR_VSX); \
+ REST_32FPRS_TRANSACT(n,base); \
+ b 3f; \
+2: REST_32VSRS_TRANSACT(n,c,base); \
+3:
+
#define __SAVE_32FPVSRS(n,c,base) \
BEGIN_FTR_SECTION \
b 2f; \
@@ -45,9 +54,12 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX); \
3:
#else
#define __REST_32FPVSRS(n,b,base) REST_32FPRS(n, base)
+#define __REST_32FPVSRS_TRANSACT(n,b,base) REST_32FPRS(n, base)
#define __SAVE_32FPVSRS(n,b,base) SAVE_32FPRS(n, base)
#endif
#define REST_32FPVSRS(n,c,base) __REST_32FPVSRS(n,__REG_##c,__REG_##base)
+#define REST_32FPVSRS_TRANSACT(n,c,base) \
+ __REST_32FPVSRS_TRANSACT(n,__REG_##c,__REG_##base)
#define SAVE_32FPVSRS(n,c,base) __SAVE_32FPVSRS(n,__REG_##c,__REG_##base)
/*
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index ba48233..6d66a68 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -57,6 +57,16 @@
#include <linux/kprobes.h>
#include <linux/kdebug.h>
+#ifdef CONFIG_TRANSACTIONAL_MEM
+/* Transactional Memory debug */
+// #define TM_DEBUG_SW
+#ifdef TM_DEBUG_SW
+#define TM_DEBUG(x...) printk(KERN_INFO x)
+#else
+#define TM_DEBUG(x...) do { } while(0)
+#endif
+#endif
+
extern unsigned long _get_SP(void);
#ifndef CONFIG_SMP
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 3251840..8fed874 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -78,6 +78,16 @@ EXPORT_SYMBOL(__debugger_dabr_match);
EXPORT_SYMBOL(__debugger_fault_handler);
#endif
+#ifdef CONFIG_TRANSACTIONAL_MEM
+/* Transactional Memory trap debug */
+// #define TM_DEBUG_SW
+#ifdef TM_DEBUG_SW
+#define TM_DEBUG(x...) printk(KERN_INFO x)
+#else
+#define TM_DEBUG(x...) do { } while(0)
+#endif
+#endif
+
/*
* Trap & Exception support
*/
@@ -350,6 +360,7 @@ static inline int check_io_access(struct pt_regs *regs)
exception is in the MSR. */
#define get_reason(regs) ((regs)->msr)
#define get_mc_reason(regs) ((regs)->msr)
+#define REASON_TM 0x200000
#define REASON_FP 0x100000
#define REASON_ILLEGAL 0x80000
#define REASON_PRIVILEGED 0x40000
--
1.7.9.5
^ permalink raw reply related
* [PATCH 03/16] powerpc: Add additional state needed for transactional memory to thread struct
From: Michael Neuling @ 2012-11-27 2:47 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: Michael Neuling, linuxppc-dev, Matt Evans
In-Reply-To: <1353984488-1283-1-git-send-email-mikey@neuling.org>
Set of new archtected state for saving away on context switch.
Signed-off-by: Matt Evans <matt@ozlabs.org>
Signed-off-by: Michael Neuling <mikey@neuling.org>
---
arch/powerpc/include/asm/processor.h | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h
index 8750204..0d1c188 100644
--- a/arch/powerpc/include/asm/processor.h
+++ b/arch/powerpc/include/asm/processor.h
@@ -236,6 +236,34 @@ struct thread_struct {
unsigned long spefscr; /* SPE & eFP status */
int used_spe; /* set if process has used spe */
#endif /* CONFIG_SPE */
+#ifdef CONFIG_TRANSACTIONAL_MEM
+ u64 tm_tfhar; /* Transaction fail handler addr */
+ u64 tm_texasr; /* Transaction exception & summary */
+ u64 tm_tfiar; /* Transaction fail instr address reg */
+ unsigned long tm_orig_msr; /* Thread's MSR on ctx switch */
+ struct pt_regs ckpt_regs; /* Checkpointed registers */
+
+ /*
+ * Transactional FP and VSX 0-31 register set.
+ * NOTE: the sense of these is the opposite of the integer ckpt_regs!
+ *
+ * When a transaction is active/signalled/scheduled etc., *regs is the
+ * most recent set of/speculated GPRs with ckpt_regs being the older
+ * checkpointed regs to which we roll back if transaction aborts.
+ *
+ * However, fpr[] is the checkpointed 'base state' of FP regs, and
+ * transact_fpr[] is the new set of transactional values.
+ * VRs work the same way.
+ */
+ double transact_fpr[32][TS_FPRWIDTH];
+ struct {
+ unsigned int pad;
+ unsigned int val; /* Floating point status */
+ } transact_fpscr;
+ vector128 transact_vr[32] __attribute__((aligned(16)));
+ vector128 transact_vscr __attribute__((aligned(16)));
+ unsigned long transact_vrsave;
+#endif /* CONFIG_TRANSACTIONAL_MEM */
#ifdef CONFIG_KVM_BOOK3S_32_HANDLER
void* kvm_shadow_vcpu; /* KVM internal data */
#endif /* CONFIG_KVM_BOOK3S_32_HANDLER */
--
1.7.9.5
^ permalink raw reply related
* [PATCH 02/16] powerpc: Add new instructions for transactional memory
From: Michael Neuling @ 2012-11-27 2:47 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: Michael Neuling, linuxppc-dev, Matt Evans
In-Reply-To: <1353984488-1283-1-git-send-email-mikey@neuling.org>
Here we define the new instructions we need for transactional memory in the
kernel. This is so we can support compiling with binutils that don't support
the new transactional memory instructions.
Transactional memory results in two sets of architected state (GPRs/VSRs
etc).
treclaim allows us to read the checkpointed state (from the tbegin) so that we
can store it away on a context switch. It does this by overwriting the exiting
architected state, so you have to save that away before you treclaim. treclaim
will also abort a transaction, so you can give a register value which contains
an abort reason.
trecheckpoint allows us to inject into the checkpointed state as if it were at
the tbegin. It does this by copying the current architected state into the
checkpointed state.
Signed-off-by: Matt Evans <matt@ozlabs.org>
Signed-off-by: Michael Neuling <mikey@neuling.org>
---
arch/powerpc/include/asm/ppc-opcode.h | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h
index 45fd394..3674ffc 100644
--- a/arch/powerpc/include/asm/ppc-opcode.h
+++ b/arch/powerpc/include/asm/ppc-opcode.h
@@ -129,6 +129,8 @@
#define PPC_INST_TLBSRX_DOT 0x7c0006a5
#define PPC_INST_XXLOR 0xf0000510
#define PPC_INST_XVCPSGNDP 0xf0000780
+#define PPC_INST_TRECHKPT 0x7c0007dd
+#define PPC_INST_TRECLAIM 0x7c00075d
#define PPC_INST_NAP 0x4c000364
#define PPC_INST_SLEEP 0x4c0003a4
@@ -291,4 +293,9 @@
#define PPC_NAP stringify_in_c(.long PPC_INST_NAP)
#define PPC_SLEEP stringify_in_c(.long PPC_INST_SLEEP)
+/* Transactional memory instructions */
+#define TRECHKPT stringify_in_c(.long PPC_INST_TRECHKPT)
+#define TRECLAIM(r) stringify_in_c(.long PPC_INST_TRECLAIM \
+ | __PPC_RA(r))
+
#endif /* _ASM_POWERPC_PPC_OPCODE_H */
--
1.7.9.5
^ permalink raw reply related
* [PATCH 01/16] powerpc: Add new CPU feature bit for transactional memory
From: Michael Neuling @ 2012-11-27 2:47 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: Michael Neuling, linuxppc-dev, Matt Evans
In-Reply-To: <1353984488-1283-1-git-send-email-mikey@neuling.org>
Signed-off-by: Matt Evans <matt@ozlabs.org>
Signed-off-by: Michael Neuling <mikey@neuling.org>
---
arch/powerpc/include/asm/cputable.h | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h
index fc4d2c5..f2163da 100644
--- a/arch/powerpc/include/asm/cputable.h
+++ b/arch/powerpc/include/asm/cputable.h
@@ -171,6 +171,7 @@ extern const char *powerpc_base_platform;
#define CPU_FTR_POPCNTD LONG_ASM_CONST(0x0800000000000000)
#define CPU_FTR_ICSWX LONG_ASM_CONST(0x1000000000000000)
#define CPU_FTR_VMX_COPY LONG_ASM_CONST(0x2000000000000000)
+#define CPU_FTR_TM LONG_ASM_CONST(0x4000000000000000)
#ifndef __ASSEMBLY__
@@ -216,6 +217,13 @@ extern const char *powerpc_base_platform;
#define PPC_FEATURE_HAS_EFP_DOUBLE_COMP 0
#endif
+/* We only set the TM feature if the kernel was compiled with TM supprt */
+#ifdef CONFIG_TRANSACTIONAL_MEM
+#define CPU_FTR_TM_COMP CPU_FTR_TM
+#else
+#define CPU_FTR_TM_COMP 0
+#endif
+
/* We need to mark all pages as being coherent if we're SMP or we have a
* 74[45]x and an MPC107 host bridge. Also 83xx and PowerQUICC II
* require it for PCI "streaming/prefetch" to work properly.
--
1.7.9.5
^ permalink raw reply related
* [PATCH 00/16] powerpc: Hardware transactional memory support for POWER8
From: Michael Neuling @ 2012-11-27 2:47 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev
POWER8 implements hardware transactional memory support. This patch series
adds kernel support so that user programs can use this hardware transactional
memory and the new state is properly context switched. It is not currently
used by the kernel itself.
This patch series was originally developed by Matt Evans.
Basic overview of a POWER8 hardware transaction memory
=====================================================
Hardware transactional memory is a feature that enables a different form of
atomic memory access. Several new instructions are presented to delimit
transactions; transactions are guaranteed to either complete atomically or roll
back and undo any partial changes.
A simple transaction looks like this:
begin_move_money:
tbegin
beq abort_handler
ld r4, SAVINGS_ACCT(r3)
ld r5, CURRENT_ACCT(r3)
subi r5, r5, 1
addi r4, r4, 1
std r4, SAVINGS_ACCT(r3)
std r5, CURRENT_ACCT(r3)
tend
b continue
abort_handler:
... test for odd failures ...
/* Retry the transaction if it failed because it conflicted with
* someone else: */
b begin_move_money
The 'tbegin' instruction denotes the start point, and 'tend' the end point.
Between these points the processor is in 'Transactional' state; any memory
references will complete in one go if there are no conflicts with other
transactional or non-transactional accesses within the system. In this
example, the transaction completes as though it were normal straight-line code
IF no other processor has touched SAVINGS_ACCT(r3) or CURRENT_ACCT(r3); an
atomic move of money from the current account to the savings account has been
performed. Even though the normal ld/std instructions are used (note no
lwarx/stwcx), either *both* SAVINGS_ACCT(r3) and CURRENT_ACCT(r3) will be
updated, or neither will be updated.
If, in the meantime, there is a conflict with the locations accessed by the
transaction, the transaction will be aborted by the CPU. Register and memory
state will roll back to that at the 'tbegin', and control will continue from
'tbegin+4'. The branch to abort_handler will be taken this second time; the
abort handler can check the cause of the failure, and retry.
Checkpointed registers include all GPRs, FPRs, VRs/VSRs, LR, CCR/CR, CTR, FPCSR
and a few other status/flag regs;
--
1.7.9.5
^ permalink raw reply
* Re: [PATCH v3 11/12] memory-hotplug: remove sysfs file of node
From: Wen Congyang @ 2012-11-27 2:24 UTC (permalink / raw)
To: Jianguo Wu
Cc: linux-s390, linux-ia64, Len Brown, linux-acpi, linux-sh, x86,
linux-kernel, cmetcalf, Jianguo Wu, linux-mm, Yasuaki Ishimatsu,
paulus, Minchan Kim, KOSAKI Motohiro, David Rientjes, sparclinux,
Christoph Lameter, linuxppc-dev, Andrew Morton, Jiang Liu
In-Reply-To: <50B37C52.2060301@gmail.com>
At 11/26/2012 10:27 PM, Jianguo Wu Wrote:
> On 2012/11/1 17:44, Wen Congyang wrote:
>> This patch introduces a new function try_offline_node() to
>> remove sysfs file of node when all memory sections of this
>> node are removed. If some memory sections of this node are
>> not removed, this function does nothing.
>>
>> CC: David Rientjes <rientjes@google.com>
>> CC: Jiang Liu <liuj97@gmail.com>
>> CC: Len Brown <len.brown@intel.com>
>> CC: Christoph Lameter <cl@linux.com>
>> Cc: Minchan Kim <minchan.kim@gmail.com>
>> CC: Andrew Morton <akpm@linux-foundation.org>
>> CC: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
>> CC: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
>> Signed-off-by: Wen Congyang <wency@cn.fujitsu.com>
>> ---
>> drivers/acpi/acpi_memhotplug.c | 8 +++++-
>> include/linux/memory_hotplug.h | 2 +-
>> mm/memory_hotplug.c | 58 ++++++++++++++++++++++++++++++++++++++++--
>> 3 files changed, 64 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
>> index 24c807f..0780f99 100644
>> --- a/drivers/acpi/acpi_memhotplug.c
>> +++ b/drivers/acpi/acpi_memhotplug.c
>> @@ -310,7 +310,9 @@ static int acpi_memory_disable_device(struct acpi_memory_device *mem_device)
>> {
>> int result;
>> struct acpi_memory_info *info, *n;
>> + int node;
>>
>> + node = acpi_get_node(mem_device->device->handle);
>>
>> /*
>> * Ask the VM to offline this memory range.
>> @@ -318,7 +320,11 @@ static int acpi_memory_disable_device(struct acpi_memory_device *mem_device)
>> */
>> list_for_each_entry_safe(info, n, &mem_device->res_list, list) {
>> if (info->enabled) {
>> - result = remove_memory(info->start_addr, info->length);
>> + if (node < 0)
>> + node = memory_add_physaddr_to_nid(
>> + info->start_addr);
>> + result = remove_memory(node, info->start_addr,
>> + info->length);
>> if (result)
>> return result;
>> }
>> diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h
>> index d4c4402..7b4cfe6 100644
>> --- a/include/linux/memory_hotplug.h
>> +++ b/include/linux/memory_hotplug.h
>> @@ -231,7 +231,7 @@ extern int arch_add_memory(int nid, u64 start, u64 size);
>> extern int offline_pages(unsigned long start_pfn, unsigned long nr_pages);
>> extern int offline_memory_block(struct memory_block *mem);
>> extern bool is_memblock_offlined(struct memory_block *mem);
>> -extern int remove_memory(u64 start, u64 size);
>> +extern int remove_memory(int node, u64 start, u64 size);
>> extern int sparse_add_one_section(struct zone *zone, unsigned long start_pfn,
>> int nr_pages);
>> extern void sparse_remove_one_section(struct zone *zone, struct mem_section *ms);
>> diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
>> index 7bcced0..d965da3 100644
>> --- a/mm/memory_hotplug.c
>> +++ b/mm/memory_hotplug.c
>> @@ -29,6 +29,7 @@
>> #include <linux/suspend.h>
>> #include <linux/mm_inline.h>
>> #include <linux/firmware-map.h>
>> +#include <linux/stop_machine.h>
>>
>> #include <asm/tlbflush.h>
>>
>> @@ -1299,7 +1300,58 @@ static int is_memblock_offlined_cb(struct memory_block *mem, void *arg)
>> return ret;
>> }
>>
>> -int __ref remove_memory(u64 start, u64 size)
>> +static int check_cpu_on_node(void *data)
>> +{
>> + struct pglist_data *pgdat = data;
>> + int cpu;
>> +
>> + for_each_present_cpu(cpu) {
>> + if (cpu_to_node(cpu) == pgdat->node_id)
>> + /*
>> + * the cpu on this node isn't removed, and we can't
>> + * offline this node.
>> + */
>> + return -EBUSY;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +/* offline the node if all memory sections of this node are removed */
>> +static void try_offline_node(int nid)
>> +{
>> + unsigned long start_pfn = NODE_DATA(nid)->node_start_pfn;
>> + unsigned long end_pfn = start_pfn + NODE_DATA(nid)->node_spanned_pages;
>> + unsigned long pfn;
>> +
>> + for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) {
>> + unsigned long section_nr = pfn_to_section_nr(pfn);
>> +
>> + if (!present_section_nr(section_nr))
>> + continue;
>> +
>> + if (pfn_to_nid(pfn) != nid)
>> + continue;
>> +
>> + /*
>> + * some memory sections of this node are not removed, and we
>> + * can't offline node now.
>> + */
>> + return;
>> + }
>> +
>> + if (stop_machine(check_cpu_on_node, NODE_DATA(nid), NULL))
>> + return;
>
> how about:
> if (nr_cpus_node(nid))
If all cpus on the node is offlined, but not removed, nr_cpus_node(nid) will
return 0. In this case, we still can't offline the node.
Another purpose to use stop_machine() is to prevent cpu hotplug. We can't lock
cpuhotplug here.
Thanks
Wen Congyang
> return;
>> +
>> + /*
>> + * all memory/cpu of this node are removed, we can offline this
>> + * node now.
>> + */
>> + node_set_offline(nid);
>> + unregister_one_node(nid);
>> +}
>> +
>> +int __ref remove_memory(int nid, u64 start, u64 size)
>> {
>> unsigned long start_pfn, end_pfn;
>> int ret = 0;
>> @@ -1346,6 +1398,8 @@ repeat:
>>
>> arch_remove_memory(start, size);
>>
>> + try_offline_node(nid);
>> +
>> unlock_memory_hotplug();
>>
>> return 0;
>> @@ -1355,7 +1409,7 @@ int offline_pages(unsigned long start_pfn, unsigned long nr_pages)
>> {
>> return -EINVAL;
>> }
>> -int remove_memory(u64 start, u64 size)
>> +int remove_memory(int nid, u64 start, u64 size)
>> {
>> return -EINVAL;
>> }
>>
>
>
^ permalink raw reply
* Re: [PATCH 5/6] powerpc: Macros for saving/restore PPR
From: Haren Myneni @ 2012-11-27 1:49 UTC (permalink / raw)
To: Michael Neuling; +Cc: anton, paulus, linuxppc-dev
In-Reply-To: <27433.1353641997@neuling.org>
On 11/22/2012 07:39 PM, Michael Neuling wrote:
> Haren Myneni <haren@linux.vnet.ibm.com> wrote:
>
>> [PATCH 5/6] powerpc: Macros for saving/restore PPR
>>
>> Several macros are defined for saving and restore user defined PPR value.
>>
>> Signed-off-by: Haren Myneni <haren@us.ibm.com>
>> ---
>> arch/powerpc/include/asm/exception-64s.h | 29 +++++++++++++++++++++++++++++
>> arch/powerpc/include/asm/ppc_asm.h | 25 +++++++++++++++++++++++++
>> arch/powerpc/include/asm/reg.h | 1 +
>> 3 files changed, 55 insertions(+), 0 deletions(-)
>>
>> diff --git a/arch/powerpc/include/asm/exception-64s.h b/arch/powerpc/include/asm/exception-64s.h
>> index bfd3f1f..880ef7d 100644
>> --- a/arch/powerpc/include/asm/exception-64s.h
>> +++ b/arch/powerpc/include/asm/exception-64s.h
>> @@ -62,6 +62,35 @@
>> #define EXC_HV H
>> #define EXC_STD
>>
>> +/*
>> + * PPR save/restore macros used in exceptions_64s.S
>> + * Used for P7 or later processors
>> + */
>> +#define SAVE_PPR(area, ra, rb) \
>> +BEGIN_FTR_SECTION_NESTED(940) \
>> + ld ra,PACACURRENT(r13); \
>> + ld rb,area+EX_PPR(r13); /* Read PPR from paca */ \
>> + std rb,TASKTHREADPPR(ra); \
>> +END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,940)
>> +
>> +#define RESTORE_PPR_PACA(area, ra) \
>> +BEGIN_FTR_SECTION_NESTED(941) \
>> + ld ra,area+EX_PPR(r13); \
>> + mtspr SPRN_PPR,ra; \
>> +END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,941)
>> +
>
> Can you add some documentation here on why we should use the different
> versions.
>
> I'm trying to read the next patch and it's not clear to my why some have
> HMT_MEDIUM_NO_PPR and other times HMT_MEDIUM and others
> HTM_MEDIUM_HAS_PPR.
>
> Looks like HTM_MEDIUM_NO_PPR sets the priority to medium on systems
> where we can't save/restore the PPR, hence it can be called earlier in
> the exception handler before we have free GPRs. HTM_MEDIUM_HAS_PPR
> saves the priority on systems where it can, and then sets the priority
> to medium.
>
> Maybe we should change the names
> HTM_MEDIUM_NO_PPR => HTM_MEDIUM_PPR_DISCARD and
> HTM_MEDIUM_HAS_PPR => HTM_MEDIUM_PPR_SAVE
> But now I'm heading into bike shedding territory... plus I think I
> suggested the names you have currently, so I'm feeling a bit dumb now
> :-)
No problem, We can change these macro names if HTM_MEDIUM_PPR_DISCARD/
HTM_MEDIUM_PPR_SAVE gives better description.
Right, HTM_MEDIUM_NO_PPR is used on systems where we do not save/restore
PPR. So the behaviour is same as before - just increases the priority.
HTM_MEDIUM_HAS_PPR will be executed on systems where CPU_FTR_HAS_PPR is
enabled. I will write some comments around these macros to make it clear.
We can also name them HMT_MEDIUM_CPU_NO_PPR_SAVE and
HMT_MEDIUM_CPU_HAS_PPR_SAVE since we are enabling PPR save/restore using
CPU_FTR macro.
Otherwise I will follow with your suggestions.
Thanks
Haren
> Mikey
>
>> +#define HMT_MEDIUM_NO_PPR \
>> +BEGIN_FTR_SECTION_NESTED(942) \
>> + HMT_MEDIUM; \
>> +END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,0,942) /*non P7*/
>> +
>> +#define HMT_MEDIUM_HAS_PPR(area, ra) \
>> +BEGIN_FTR_SECTION_NESTED(943) \
>> + mfspr ra,SPRN_PPR; \
>> + std ra,area+EX_PPR(r13); \
>> + HMT_MEDIUM; \
>> +END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,943)
>> +
>> #define __EXCEPTION_PROLOG_1(area, extra, vec) \
>> GET_PACA(r13); \
>> std r9,area+EX_R9(r13); /* save r9 - r12 */ \
>
>
>> diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h
>> index 376e36d..52649cc 100644
>> --- a/arch/powerpc/include/asm/ppc_asm.h
>> +++ b/arch/powerpc/include/asm/ppc_asm.h
>> @@ -389,6 +389,31 @@ END_FTR_SECTION_IFCLR(CPU_FTR_601)
>> FTR_SECTION_ELSE_NESTED(848); \
>> mtocrf (FXM), RS; \
>> ALT_FTR_SECTION_END_NESTED_IFCLR(CPU_FTR_NOEXECUTE, 848)
>> +
>> +/*
>> + * PPR restore macros used in entry_64.S
>> + * Used for P7 or later processors
>> + */
>> +#define HMT_MEDIUM_LOW_HAS_PPR \
>> +BEGIN_FTR_SECTION_NESTED(944) \
>> + HMT_MEDIUM_LOW; \
>> +END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,944)
>> +
>> +#define SET_DEFAULT_THREAD_PPR(ra, rb) \
>> +BEGIN_FTR_SECTION_NESTED(945) \
>> + lis ra,0xc; /* default ppr=3 */ \
>> + ld rb,PACACURRENT(r13); \
>> + sldi ra,ra,32; /* 11- 13 bits are used for ppr */ \
>> + std ra,TASKTHREADPPR(rb); \
>> +END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,945)
>> +
>> +#define RESTORE_PPR(ra, rb) \
>> +BEGIN_FTR_SECTION_NESTED(946) \
>> + ld ra,PACACURRENT(r13); \
>> + ld rb,TASKTHREADPPR(ra); \
>> + mtspr SPRN_PPR,rb; /* Restore PPR */ \
>> +END_FTR_SECTION_NESTED(CPU_FTR_HAS_PPR,CPU_FTR_HAS_PPR,946)
>> +
>> #endif
>>
>> /*
>> diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
>> index d24c141..1723be3 100644
>> --- a/arch/powerpc/include/asm/reg.h
>> +++ b/arch/powerpc/include/asm/reg.h
>> @@ -287,6 +287,7 @@
>> #define SPRN_DBAT6U 0x23C /* Data BAT 6 Upper Register */
>> #define SPRN_DBAT7L 0x23F /* Data BAT 7 Lower Register */
>> #define SPRN_DBAT7U 0x23E /* Data BAT 7 Upper Register */
>> +#define SPRN_PPR 0x380 /* SMT Thread status Register */
>>
>> #define SPRN_DEC 0x016 /* Decrement Register */
>> #define SPRN_DER 0x095 /* Debug Enable Regsiter */
>> --
>> 1.7.1
>>
>>
>>
>> _______________________________________________
>> Linuxppc-dev mailing list
>> Linuxppc-dev@lists.ozlabs.org
>> https://lists.ozlabs.org/listinfo/linuxppc-dev
>>
^ permalink raw reply
* Re: [PATCH 2/6] powerpc: Define CPU_FTR_HAS_PPR
From: Haren Myneni @ 2012-11-27 0:52 UTC (permalink / raw)
To: Michael Neuling; +Cc: anton, paulus, linuxppc-dev
In-Reply-To: <28905.1353643302@neuling.org>
On 11/22/2012 08:01 PM, Michael Neuling wrote:
> Heaven Myneni <haren@linux.vnet.ibm.com> wrote:
>
>> [PATCH 2/6] powerpc: Define CPU_FTR_HAS_PPR
>>
>> CPU_FTR_HAS_PPR is defined for POWER7.
>>
>> Signed-off-by: Haren Myneni <haren@us.ibm.com>
>> ---
>> arch/powerpc/include/asm/cputable.h | 6 ++++--
>> 1 files changed, 4 insertions(+), 2 deletions(-)
>>
>> diff --git a/arch/powerpc/include/asm/cputable.h b/arch/powerpc/include/asm/cputable.h
>> index 21a0687..12e3a1d 100644
>> --- a/arch/powerpc/include/asm/cputable.h
>> +++ b/arch/powerpc/include/asm/cputable.h
>> @@ -171,6 +171,7 @@ extern const char *powerpc_base_platform;
>> #define CPU_FTR_POPCNTD LONG_ASM_CONST(0x0800000000000000)
>> #define CPU_FTR_ICSWX LONG_ASM_CONST(0x1000000000000000)
>> #define CPU_FTR_VMX_COPY LONG_ASM_CONST(0x2000000000000000)
>> +#define CPU_FTR_HAS_PPR LONG_ASM_CONST(0x4000000000000000)
>>
>> #ifndef __ASSEMBLY__
>>
>> @@ -400,7 +401,8 @@ extern const char *powerpc_base_platform;
>> CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \
>> CPU_FTR_DSCR | CPU_FTR_SAO | CPU_FTR_ASYM_SMT | \
>> CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \
>> - CPU_FTR_ICSWX | CPU_FTR_CFAR | CPU_FTR_HVMODE | CPU_FTR_VMX_COPY)
>> + CPU_FTR_ICSWX | CPU_FTR_CFAR | CPU_FTR_HVMODE | \
>> + CPU_FTR_VMX_COPY | CPU_FTR_HAS_PPR)
>> #define CPU_FTRS_CELL (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \
>> CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \
>> CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
>> @@ -422,7 +424,7 @@ extern const char *powerpc_base_platform;
>> (CPU_FTRS_POWER3 | CPU_FTRS_RS64 | CPU_FTRS_POWER4 | \
>> CPU_FTRS_PPC970 | CPU_FTRS_POWER5 | CPU_FTRS_POWER6 | \
>> CPU_FTRS_POWER7 | CPU_FTRS_CELL | CPU_FTRS_PA6T | \
>> - CPU_FTR_VSX)
>> + CPU_FTR_VSX | CPU_FTR_HAS_PPR)
>
> FYI, there is no need to add this to POSSIBLE, since you are adding it
> to POWER7 anyway.
Will remove CPU_FTR_HAS_PPR for POSSIBLE macro. Added this in second
version for enabling this feature with command parameter, but forgot to
remove it.
Thanks
Haren
>
> Mikey
>
^ permalink raw reply
* Re: [PATCH] vfio powerpc: enabled and supported on powernv platform
From: Benjamin Herrenschmidt @ 2012-11-27 0:21 UTC (permalink / raw)
To: Alex Williamson
Cc: kvm@vger.kernel.org, Alexey Kardashevskiy,
linux-kernel@vger.kernel.org, Paul Mackerras, Sethi Varun-B16395,
linuxppc-dev@lists.ozlabs.org, David Gibson
In-Reply-To: <1353953070.1809.103.camel@bling.home>
On Mon, 2012-11-26 at 11:04 -0700, Alex Williamson wrote:
> Ok, I see tces are put on shutdown via tce_iommu_detach_group, so you're
> more concerned about the guest simply mapping over top of it's own
> mappings. Is that common? Is it common enough for every multi-page
> mapping to assume it will happen? I know this is a performance
> sensitive path for you and it seems like a map-only w/ fallback to
> unmap, remap would be better in the general case.
>
> On x86 we do exactly that, but we do the unmap, remap from userspace
> when we get an EBUSY. Thanks,
Right, Linux as guest at least will never map "over" an existing
mapping. It will always unmap first. IE. The only transition we do on
H_PUT_TCE are 0 -> valid and valid -> 0.
So it would be fine to simplify the code and keep the "map over map" as
a slow fallback. I can't tell for other operating systems but we don't
care about those at this point :-)
Cheers,
Ben.
^ permalink raw reply
* Re: Build regressions/improvements in v3.7-rc7
From: Geert Uytterhoeven @ 2012-11-26 20:56 UTC (permalink / raw)
To: linux-kernel; +Cc: linuxppc-dev, Linux-sh list
In-Reply-To: <1353963243-21887-1-git-send-email-geert@linux-m68k.org>
On Mon, Nov 26, 2012 at 9:54 PM, Geert Uytterhoeven
<geert@linux-m68k.org> wrote:
> JFYI, when comparing v3.7-rc7 to v3.7-rc6[3], the summaries are:
> - build errors: +4/-8
+ error: "__sync_fetch_and_and_4"
[drivers/staging/line6/line6usb.ko] undefined!: => N/A
+ error: "__sync_fetch_and_or_4" [drivers/staging/line6/line6usb.ko]
undefined!: => N/A
sh4/sh-randconfig
+ error: "smp_send_reschedule" [arch/powerpc/kvm/kvm.ko] undefined!: => N/A
powerpc/powerpc-randconfig
> [1] http://kisskb.ellerman.id.au/kisskb/head/5646/ (all 117 configs)
> [3] http://kisskb.ellerman.id.au/kisskb/head/5628/ (all 117 configs)
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* Re: [PATCH 437/493] char: remove use of __devexit
From: Kent Yoder @ 2012-11-26 20:36 UTC (permalink / raw)
To: Bill Pemberton
Cc: David Airlie, gregkh, Marcel Selhorst, platform-driver-x86,
Rajiv Andrade, Mattia Dongili, tpmdd-devel, Olof Johansson,
openipmi-developer, linuxppc-dev, Sirrix AG, linux-arm-kernel
In-Reply-To: <1353349642-3677-437-git-send-email-wfp5p@virginia.edu>
On Mon, Nov 19, 2012 at 01:26:26PM -0500, Bill Pemberton wrote:
> CONFIG_HOTPLUG is going away as an option so __devexit is no
> longer needed.
>
> Signed-off-by: Bill Pemberton <wfp5p@virginia.edu>
> Cc: David Airlie <airlied@linux.ie>
> Cc: Olof Johansson <olof@lixom.net>
> Cc: Mattia Dongili <malattia@linux.it>
> Cc: Kent Yoder <key@linux.vnet.ibm.com>
> Cc: Rajiv Andrade <mail@srajiv.net>
> Cc: Marcel Selhorst <tpmdd@selhorst.net>
> Cc: Sirrix AG <tpmdd@sirrix.com>
> Cc: linuxppc-dev@lists.ozlabs.org
> Cc: linux-arm-kernel@lists.infradead.org
> Cc: openipmi-developer@lists.sourceforge.net
> Cc: platform-driver-x86@vger.kernel.org
> Cc: tpmdd-devel@lists.sourceforge.net
Acked-by: Kent Yoder <key@linux.vnet.ibm.com>
> ---
> drivers/char/agp/ali-agp.c | 2 +-
> drivers/char/agp/amd-k7-agp.c | 2 +-
> drivers/char/agp/amd64-agp.c | 2 +-
> drivers/char/agp/ati-agp.c | 2 +-
> drivers/char/agp/efficeon-agp.c | 2 +-
> drivers/char/agp/i460-agp.c | 2 +-
> drivers/char/agp/intel-agp.c | 2 +-
> drivers/char/agp/nvidia-agp.c | 2 +-
> drivers/char/agp/sgi-agp.c | 2 +-
> drivers/char/agp/sis-agp.c | 2 +-
> drivers/char/agp/sworks-agp.c | 2 +-
> drivers/char/agp/uninorth-agp.c | 2 +-
> drivers/char/agp/via-agp.c | 2 +-
> drivers/char/hw_random/atmel-rng.c | 2 +-
> drivers/char/hw_random/bcm63xx-rng.c | 2 +-
> drivers/char/hw_random/exynos-rng.c | 2 +-
> drivers/char/hw_random/n2-drv.c | 2 +-
> drivers/char/hw_random/pasemi-rng.c | 2 +-
> drivers/char/hw_random/picoxcell-rng.c | 2 +-
> drivers/char/hw_random/ppc4xx-rng.c | 2 +-
> drivers/char/hw_random/timeriomem-rng.c | 2 +-
> drivers/char/hw_random/virtio-rng.c | 2 +-
> drivers/char/ipmi/ipmi_si_intf.c | 6 +++---
> drivers/char/sonypi.c | 2 +-
> drivers/char/tb0219.c | 2 +-
> drivers/char/tpm/tpm_i2c_infineon.c | 2 +-
> drivers/char/tpm/tpm_ibmvtpm.c | 2 +-
> drivers/char/tpm/tpm_infineon.c | 2 +-
> drivers/char/tpm/tpm_tis.c | 2 +-
> drivers/char/xilinx_hwicap/xilinx_hwicap.c | 4 ++--
> 30 files changed, 33 insertions(+), 33 deletions(-)
>
> diff --git a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c
> index 9eb629b..0e69e60 100644
> --- a/drivers/char/agp/ali-agp.c
> +++ b/drivers/char/agp/ali-agp.c
> @@ -374,7 +374,7 @@ found:
> return agp_add_bridge(bridge);
> }
>
> -static void __devexit agp_ali_remove(struct pci_dev *pdev)
> +static void agp_ali_remove(struct pci_dev *pdev)
> {
> struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
>
> diff --git a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c
> index 2e1efa9..cb9c9f9 100644
> --- a/drivers/char/agp/amd-k7-agp.c
> +++ b/drivers/char/agp/amd-k7-agp.c
> @@ -480,7 +480,7 @@ static int agp_amdk7_probe(struct pci_dev *pdev,
> return agp_add_bridge(bridge);
> }
>
> -static void __devexit agp_amdk7_remove(struct pci_dev *pdev)
> +static void agp_amdk7_remove(struct pci_dev *pdev)
> {
> struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
>
> diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c
> index f4086c5..280c0d5 100644
> --- a/drivers/char/agp/amd64-agp.c
> +++ b/drivers/char/agp/amd64-agp.c
> @@ -579,7 +579,7 @@ static int agp_amd64_probe(struct pci_dev *pdev,
> return 0;
> }
>
> -static void __devexit agp_amd64_remove(struct pci_dev *pdev)
> +static void agp_amd64_remove(struct pci_dev *pdev)
> {
> struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
>
> diff --git a/drivers/char/agp/ati-agp.c b/drivers/char/agp/ati-agp.c
> index 6aeb624..485b15c 100644
> --- a/drivers/char/agp/ati-agp.c
> +++ b/drivers/char/agp/ati-agp.c
> @@ -533,7 +533,7 @@ found:
> return agp_add_bridge(bridge);
> }
>
> -static void __devexit agp_ati_remove(struct pci_dev *pdev)
> +static void agp_ati_remove(struct pci_dev *pdev)
> {
> struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
>
> diff --git a/drivers/char/agp/efficeon-agp.c b/drivers/char/agp/efficeon-agp.c
> index bf80cf1..08a465e 100644
> --- a/drivers/char/agp/efficeon-agp.c
> +++ b/drivers/char/agp/efficeon-agp.c
> @@ -407,7 +407,7 @@ static int agp_efficeon_probe(struct pci_dev *pdev,
> return agp_add_bridge(bridge);
> }
>
> -static void __devexit agp_efficeon_remove(struct pci_dev *pdev)
> +static void agp_efficeon_remove(struct pci_dev *pdev)
> {
> struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
>
> diff --git a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c
> index bda2215..0436bf1 100644
> --- a/drivers/char/agp/i460-agp.c
> +++ b/drivers/char/agp/i460-agp.c
> @@ -611,7 +611,7 @@ static int agp_intel_i460_probe(struct pci_dev *pdev,
> return agp_add_bridge(bridge);
> }
>
> -static void __devexit agp_intel_i460_remove(struct pci_dev *pdev)
> +static void agp_intel_i460_remove(struct pci_dev *pdev)
> {
> struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
>
> diff --git a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
> index ad6739e..362e744 100644
> --- a/drivers/char/agp/intel-agp.c
> +++ b/drivers/char/agp/intel-agp.c
> @@ -819,7 +819,7 @@ found_gmch:
> return err;
> }
>
> -static void __devexit agp_intel_remove(struct pci_dev *pdev)
> +static void agp_intel_remove(struct pci_dev *pdev)
> {
> struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
>
> diff --git a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c
> index 1f7fddf..adaa47b 100644
> --- a/drivers/char/agp/nvidia-agp.c
> +++ b/drivers/char/agp/nvidia-agp.c
> @@ -388,7 +388,7 @@ static int agp_nvidia_probe(struct pci_dev *pdev,
> return agp_add_bridge(bridge);
> }
>
> -static void __devexit agp_nvidia_remove(struct pci_dev *pdev)
> +static void agp_nvidia_remove(struct pci_dev *pdev)
> {
> struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
>
> diff --git a/drivers/char/agp/sgi-agp.c b/drivers/char/agp/sgi-agp.c
> index 8356e89..05b8d02 100644
> --- a/drivers/char/agp/sgi-agp.c
> +++ b/drivers/char/agp/sgi-agp.c
> @@ -327,7 +327,7 @@ static int agp_sgi_init(void)
> return 0;
> }
>
> -static void __devexit agp_sgi_cleanup(void)
> +static void agp_sgi_cleanup(void)
> {
> kfree(sgi_tioca_agp_bridges);
> sgi_tioca_agp_bridges = NULL;
> diff --git a/drivers/char/agp/sis-agp.c b/drivers/char/agp/sis-agp.c
> index 7d6f3c6..37ee0eb 100644
> --- a/drivers/char/agp/sis-agp.c
> +++ b/drivers/char/agp/sis-agp.c
> @@ -211,7 +211,7 @@ static int agp_sis_probe(struct pci_dev *pdev,
> return agp_add_bridge(bridge);
> }
>
> -static void __devexit agp_sis_remove(struct pci_dev *pdev)
> +static void agp_sis_remove(struct pci_dev *pdev)
> {
> struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
>
> diff --git a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c
> index d1b063b..d046de9 100644
> --- a/drivers/char/agp/sworks-agp.c
> +++ b/drivers/char/agp/sworks-agp.c
> @@ -518,7 +518,7 @@ static int agp_serverworks_probe(struct pci_dev *pdev,
> return agp_add_bridge(bridge);
> }
>
> -static void __devexit agp_serverworks_remove(struct pci_dev *pdev)
> +static void agp_serverworks_remove(struct pci_dev *pdev)
> {
> struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
>
> diff --git a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c
> index d7168ca..2d29f04 100644
> --- a/drivers/char/agp/uninorth-agp.c
> +++ b/drivers/char/agp/uninorth-agp.c
> @@ -663,7 +663,7 @@ static int agp_uninorth_probe(struct pci_dev *pdev,
> return agp_add_bridge(bridge);
> }
>
> -static void __devexit agp_uninorth_remove(struct pci_dev *pdev)
> +static void agp_uninorth_remove(struct pci_dev *pdev)
> {
> struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
>
> diff --git a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c
> index 774fe1e..8b2c285 100644
> --- a/drivers/char/agp/via-agp.c
> +++ b/drivers/char/agp/via-agp.c
> @@ -485,7 +485,7 @@ static int agp_via_probe(struct pci_dev *pdev,
> return agp_add_bridge(bridge);
> }
>
> -static void __devexit agp_via_remove(struct pci_dev *pdev)
> +static void agp_via_remove(struct pci_dev *pdev)
> {
> struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
>
> diff --git a/drivers/char/hw_random/atmel-rng.c b/drivers/char/hw_random/atmel-rng.c
> index 0f6ca8f..7c73d4a 100644
> --- a/drivers/char/hw_random/atmel-rng.c
> +++ b/drivers/char/hw_random/atmel-rng.c
> @@ -98,7 +98,7 @@ err_enable:
> return ret;
> }
>
> -static int __devexit atmel_trng_remove(struct platform_device *pdev)
> +static int atmel_trng_remove(struct platform_device *pdev)
> {
> struct atmel_trng *trng = platform_get_drvdata(pdev);
>
> diff --git a/drivers/char/hw_random/bcm63xx-rng.c b/drivers/char/hw_random/bcm63xx-rng.c
> index c46fc74..f343b7d 100644
> --- a/drivers/char/hw_random/bcm63xx-rng.c
> +++ b/drivers/char/hw_random/bcm63xx-rng.c
> @@ -145,7 +145,7 @@ out:
> return ret;
> }
>
> -static int __devexit bcm63xx_rng_remove(struct platform_device *pdev)
> +static int bcm63xx_rng_remove(struct platform_device *pdev)
> {
> struct hwrng *rng = platform_get_drvdata(pdev);
> struct bcm63xx_rng_priv *priv = to_rng_priv(rng);
> diff --git a/drivers/char/hw_random/exynos-rng.c b/drivers/char/hw_random/exynos-rng.c
> index 92d302a..48bbfec 100644
> --- a/drivers/char/hw_random/exynos-rng.c
> +++ b/drivers/char/hw_random/exynos-rng.c
> @@ -134,7 +134,7 @@ static int exynos_rng_probe(struct platform_device *pdev)
> return hwrng_register(&exynos_rng->rng);
> }
>
> -static int __devexit exynos_rng_remove(struct platform_device *pdev)
> +static int exynos_rng_remove(struct platform_device *pdev)
> {
> struct exynos_rng *exynos_rng = platform_get_drvdata(pdev);
>
> diff --git a/drivers/char/hw_random/n2-drv.c b/drivers/char/hw_random/n2-drv.c
> index 5819c7b..20b962e 100644
> --- a/drivers/char/hw_random/n2-drv.c
> +++ b/drivers/char/hw_random/n2-drv.c
> @@ -719,7 +719,7 @@ out:
> return err;
> }
>
> -static int __devexit n2rng_remove(struct platform_device *op)
> +static int n2rng_remove(struct platform_device *op)
> {
> struct n2rng *np = dev_get_drvdata(&op->dev);
>
> diff --git a/drivers/char/hw_random/pasemi-rng.c b/drivers/char/hw_random/pasemi-rng.c
> index da5dfb5..c6df5b2 100644
> --- a/drivers/char/hw_random/pasemi-rng.c
> +++ b/drivers/char/hw_random/pasemi-rng.c
> @@ -122,7 +122,7 @@ static int rng_probe(struct platform_device *ofdev)
> return err;
> }
>
> -static int __devexit rng_remove(struct platform_device *dev)
> +static int rng_remove(struct platform_device *dev)
> {
> void __iomem *rng_regs = (void __iomem *)pasemi_rng.priv;
>
> diff --git a/drivers/char/hw_random/picoxcell-rng.c b/drivers/char/hw_random/picoxcell-rng.c
> index b4f7f06..973b951 100644
> --- a/drivers/char/hw_random/picoxcell-rng.c
> +++ b/drivers/char/hw_random/picoxcell-rng.c
> @@ -151,7 +151,7 @@ err_enable:
> return ret;
> }
>
> -static int __devexit picoxcell_trng_remove(struct platform_device *pdev)
> +static int picoxcell_trng_remove(struct platform_device *pdev)
> {
> hwrng_unregister(&picoxcell_trng);
> clk_disable(rng_clk);
> diff --git a/drivers/char/hw_random/ppc4xx-rng.c b/drivers/char/hw_random/ppc4xx-rng.c
> index c4b89c2..732c330 100644
> --- a/drivers/char/hw_random/ppc4xx-rng.c
> +++ b/drivers/char/hw_random/ppc4xx-rng.c
> @@ -111,7 +111,7 @@ static int ppc4xx_rng_probe(struct platform_device *dev)
> return err;
> }
>
> -static int __devexit ppc4xx_rng_remove(struct platform_device *dev)
> +static int ppc4xx_rng_remove(struct platform_device *dev)
> {
> void __iomem *rng_regs = (void __iomem *) ppc4xx_rng.priv;
>
> diff --git a/drivers/char/hw_random/timeriomem-rng.c b/drivers/char/hw_random/timeriomem-rng.c
> index 0153d0c..849db19 100644
> --- a/drivers/char/hw_random/timeriomem-rng.c
> +++ b/drivers/char/hw_random/timeriomem-rng.c
> @@ -130,7 +130,7 @@ failed:
> return ret;
> }
>
> -static int __devexit timeriomem_rng_remove(struct platform_device *pdev)
> +static int timeriomem_rng_remove(struct platform_device *pdev)
> {
> del_timer_sync(&timeriomem_rng_timer);
> hwrng_unregister(&timeriomem_rng_ops);
> diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c
> index bb78033..b65c103 100644
> --- a/drivers/char/hw_random/virtio-rng.c
> +++ b/drivers/char/hw_random/virtio-rng.c
> @@ -119,7 +119,7 @@ static int virtrng_probe(struct virtio_device *vdev)
> return probe_common(vdev);
> }
>
> -static void __devexit virtrng_remove(struct virtio_device *vdev)
> +static void virtrng_remove(struct virtio_device *vdev)
> {
> remove_common(vdev);
> }
> diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
> index 94c5b88..14ab4c4 100644
> --- a/drivers/char/ipmi/ipmi_si_intf.c
> +++ b/drivers/char/ipmi/ipmi_si_intf.c
> @@ -2228,7 +2228,7 @@ err_free:
> return -EINVAL;
> }
>
> -static void __devexit ipmi_pnp_remove(struct pnp_dev *dev)
> +static void ipmi_pnp_remove(struct pnp_dev *dev)
> {
> struct smi_info *info = pnp_get_drvdata(dev);
>
> @@ -2529,7 +2529,7 @@ static int ipmi_pci_probe(struct pci_dev *pdev,
> return 0;
> }
>
> -static void __devexit ipmi_pci_remove(struct pci_dev *pdev)
> +static void ipmi_pci_remove(struct pci_dev *pdev)
> {
> struct smi_info *info = pci_get_drvdata(pdev);
> cleanup_one_si(info);
> @@ -2635,7 +2635,7 @@ static int ipmi_probe(struct platform_device *dev)
> return 0;
> }
>
> -static int __devexit ipmi_remove(struct platform_device *dev)
> +static int ipmi_remove(struct platform_device *dev)
> {
> #ifdef CONFIG_OF
> cleanup_one_si(dev_get_drvdata(&dev->dev));
> diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
> index 861efa4..d780295 100644
> --- a/drivers/char/sonypi.c
> +++ b/drivers/char/sonypi.c
> @@ -1428,7 +1428,7 @@ static int sonypi_probe(struct platform_device *dev)
> return error;
> }
>
> -static int __devexit sonypi_remove(struct platform_device *dev)
> +static int sonypi_remove(struct platform_device *dev)
> {
> sonypi_disable();
>
> diff --git a/drivers/char/tb0219.c b/drivers/char/tb0219.c
> index 76e3aea..34c63f8 100644
> --- a/drivers/char/tb0219.c
> +++ b/drivers/char/tb0219.c
> @@ -318,7 +318,7 @@ static int tb0219_probe(struct platform_device *dev)
> return 0;
> }
>
> -static int __devexit tb0219_remove(struct platform_device *dev)
> +static int tb0219_remove(struct platform_device *dev)
> {
> _machine_restart = old_machine_restart;
>
> diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c
> index bcdb078..fb447bd 100644
> --- a/drivers/char/tpm/tpm_i2c_infineon.c
> +++ b/drivers/char/tpm/tpm_i2c_infineon.c
> @@ -656,7 +656,7 @@ static int tpm_tis_i2c_probe(struct i2c_client *client,
> return rc;
> }
>
> -static int __devexit tpm_tis_i2c_remove(struct i2c_client *client)
> +static int tpm_tis_i2c_remove(struct i2c_client *client)
> {
> struct tpm_chip *chip = tpm_dev.chip;
> release_locality(chip, chip->vendor.locality, 1);
> diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c
> index a027bd8..9978609 100644
> --- a/drivers/char/tpm/tpm_ibmvtpm.c
> +++ b/drivers/char/tpm/tpm_ibmvtpm.c
> @@ -267,7 +267,7 @@ static int ibmvtpm_crq_send_init(struct ibmvtpm_dev *ibmvtpm)
> * Return value:
> * 0
> */
> -static int __devexit tpm_ibmvtpm_remove(struct vio_dev *vdev)
> +static int tpm_ibmvtpm_remove(struct vio_dev *vdev)
> {
> struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(&vdev->dev);
> int rc = 0;
> diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c
> index 0126e80..2b480c2 100644
> --- a/drivers/char/tpm/tpm_infineon.c
> +++ b/drivers/char/tpm/tpm_infineon.c
> @@ -594,7 +594,7 @@ err_last:
> return rc;
> }
>
> -static __devexit void tpm_inf_pnp_remove(struct pnp_dev *dev)
> +static void tpm_inf_pnp_remove(struct pnp_dev *dev)
> {
> struct tpm_chip *chip = pnp_get_drvdata(dev);
>
> diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
> index 419a7e0..ea31daf 100644
> --- a/drivers/char/tpm/tpm_tis.c
> +++ b/drivers/char/tpm/tpm_tis.c
> @@ -783,7 +783,7 @@ static struct pnp_device_id tpm_pnp_tbl[] = {
> };
> MODULE_DEVICE_TABLE(pnp, tpm_pnp_tbl);
>
> -static __devexit void tpm_tis_pnp_remove(struct pnp_dev *dev)
> +static void tpm_tis_pnp_remove(struct pnp_dev *dev)
> {
> struct tpm_chip *chip = pnp_get_drvdata(dev);
>
> diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
> index d10085f..5224da52 100644
> --- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c
> +++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c
> @@ -717,7 +717,7 @@ static struct hwicap_driver_config fifo_icap_config = {
> .reset = fifo_icap_reset,
> };
>
> -static int __devexit hwicap_remove(struct device *dev)
> +static int hwicap_remove(struct device *dev)
> {
> struct hwicap_drvdata *drvdata;
>
> @@ -822,7 +822,7 @@ static int hwicap_drv_probe(struct platform_device *pdev)
> &buffer_icap_config, regs);
> }
>
> -static int __devexit hwicap_drv_remove(struct platform_device *pdev)
> +static int hwicap_drv_remove(struct platform_device *pdev)
> {
> return hwicap_remove(&pdev->dev);
> }
> --
> 1.8.0
>
^ permalink raw reply
* Re: [PATCH 1/2] vfio powerpc: implemented IOMMU driver for VFIO
From: Alex Williamson @ 2012-11-26 18:20 UTC (permalink / raw)
To: Alexey Kardashevskiy
Cc: kvm, linux-kernel, Paul Mackerras, linuxppc-dev, David Gibson
In-Reply-To: <1353661396-14374-2-git-send-email-aik@ozlabs.ru>
On Fri, 2012-11-23 at 20:03 +1100, Alexey Kardashevskiy wrote:
> VFIO implements platform independent stuff such as
> a PCI driver, BAR access (via read/write on a file descriptor
> or direct mapping when possible) and IRQ signaling.
>
> The platform dependent part includes IOMMU initialization
> and handling. This patch implements an IOMMU driver for VFIO
> which does mapping/unmapping pages for the guest IO and
> provides information about DMA window (required by a POWERPC
> guest).
>
> The counterpart in QEMU is required to support this functionality.
>
> Cc: David Gibson <david@gibson.dropbear.id.au>
> Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
> ---
> drivers/vfio/Kconfig | 6 +
> drivers/vfio/Makefile | 1 +
> drivers/vfio/vfio_iommu_spapr_tce.c | 247 +++++++++++++++++++++++++++++++++++
> include/linux/vfio.h | 20 +++
> 4 files changed, 274 insertions(+)
> create mode 100644 drivers/vfio/vfio_iommu_spapr_tce.c
>
> diff --git a/drivers/vfio/Kconfig b/drivers/vfio/Kconfig
> index 7cd5dec..b464687 100644
> --- a/drivers/vfio/Kconfig
> +++ b/drivers/vfio/Kconfig
> @@ -3,10 +3,16 @@ config VFIO_IOMMU_TYPE1
> depends on VFIO
> default n
>
> +config VFIO_IOMMU_SPAPR_TCE
> + tristate
> + depends on VFIO && SPAPR_TCE_IOMMU
> + default n
> +
> menuconfig VFIO
> tristate "VFIO Non-Privileged userspace driver framework"
> depends on IOMMU_API
> select VFIO_IOMMU_TYPE1 if X86
> + select VFIO_IOMMU_SPAPR_TCE if PPC_POWERNV
> help
> VFIO provides a framework for secure userspace device drivers.
> See Documentation/vfio.txt for more details.
> diff --git a/drivers/vfio/Makefile b/drivers/vfio/Makefile
> index 2398d4a..72bfabc 100644
> --- a/drivers/vfio/Makefile
> +++ b/drivers/vfio/Makefile
> @@ -1,3 +1,4 @@
> obj-$(CONFIG_VFIO) += vfio.o
> obj-$(CONFIG_VFIO_IOMMU_TYPE1) += vfio_iommu_type1.o
> +obj-$(CONFIG_VFIO_IOMMU_SPAPR_TCE) += vfio_iommu_spapr_tce.o
> obj-$(CONFIG_VFIO_PCI) += pci/
> diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c
> new file mode 100644
> index 0000000..46a6298
> --- /dev/null
> +++ b/drivers/vfio/vfio_iommu_spapr_tce.c
> @@ -0,0 +1,247 @@
> +/*
> + * VFIO: IOMMU DMA mapping support for TCE on POWER
> + *
> + * Copyright (C) 2012 IBM Corp. All rights reserved.
> + * Author: Alexey Kardashevskiy <aik@ozlabs.ru>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + *
> + * Derived from original vfio_iommu_type1.c:
> + * Copyright (C) 2012 Red Hat, Inc. All rights reserved.
> + * Author: Alex Williamson <alex.williamson@redhat.com>
> + */
> +
> +#include <linux/module.h>
> +#include <linux/pci.h>
> +#include <linux/slab.h>
> +#include <linux/uaccess.h>
> +#include <linux/err.h>
> +#include <linux/vfio.h>
> +#include <asm/iommu.h>
> +
> +#define DRIVER_VERSION "0.1"
> +#define DRIVER_AUTHOR "aik@ozlabs.ru"
> +#define DRIVER_DESC "VFIO IOMMU SPAPR TCE"
> +
> +static void tce_iommu_detach_group(void *iommu_data,
> + struct iommu_group *iommu_group);
> +
> +/*
> + * VFIO IOMMU fd for SPAPR_TCE IOMMU implementation
> + */
> +
> +/*
> + * The container descriptor supports only a single group per container.
> + * Required by the API as the container is not supplied with the IOMMU group
> + * at the moment of initialization.
> + */
> +struct tce_container {
> + struct mutex lock;
> + struct iommu_table *tbl;
> +};
> +
> +static void *tce_iommu_open(unsigned long arg)
> +{
> + struct tce_container *container;
> +
> + if (arg != VFIO_SPAPR_TCE_IOMMU) {
> + printk(KERN_ERR "tce_vfio: Wrong IOMMU type\n");
> + return ERR_PTR(-EINVAL);
> + }
> +
> + container = kzalloc(sizeof(*container), GFP_KERNEL);
> + if (!container)
> + return ERR_PTR(-ENOMEM);
> +
> + mutex_init(&container->lock);
> +
> + return container;
> +}
> +
> +static void tce_iommu_release(void *iommu_data)
> +{
> + struct tce_container *container = iommu_data;
> +
> + WARN_ON(container->tbl && !container->tbl->it_group);
I think your patch ordering is backwards here. it_group isn't added
until 2/2. I'd really like to see the arch/powerpc code approved and
merged by the powerpc maintainer before we add the code that makes use
of it into vfio. Otherwise we just get lots of churn if interfaces
change or they disapprove of it altogether.
> + if (container->tbl && container->tbl->it_group)
> + tce_iommu_detach_group(iommu_data, container->tbl->it_group);
> +
> + mutex_destroy(&container->lock);
> +
> + kfree(container);
> +}
> +
> +static long tce_iommu_ioctl(void *iommu_data,
> + unsigned int cmd, unsigned long arg)
> +{
> + struct tce_container *container = iommu_data;
> + unsigned long minsz;
> +
> + switch (cmd) {
> + case VFIO_CHECK_EXTENSION: {
> + return (arg == VFIO_SPAPR_TCE_IOMMU) ? 1 : 0;
> + }
> + case VFIO_IOMMU_SPAPR_TCE_GET_INFO: {
> + struct vfio_iommu_spapr_tce_info info;
> + struct iommu_table *tbl = container->tbl;
> +
> + if (WARN_ON(!tbl))
> + return -ENXIO;
> +
> + minsz = offsetofend(struct vfio_iommu_spapr_tce_info,
> + dma64_window_size);
> +
> + if (copy_from_user(&info, (void __user *)arg, minsz))
> + return -EFAULT;
> +
> + if (info.argsz < minsz)
> + return -EINVAL;
> +
> + info.dma32_window_start = tbl->it_offset << IOMMU_PAGE_SHIFT;
> + info.dma32_window_size = tbl->it_size << IOMMU_PAGE_SHIFT;
> + info.dma64_window_start = 0;
> + info.dma64_window_size = 0;
> + info.flags = 0;
> +
> + if (copy_to_user((void __user *)arg, &info, minsz))
> + return -EFAULT;
> +
> + return 0;
> + }
> + case VFIO_IOMMU_MAP_DMA: {
> + vfio_iommu_spapr_tce_dma_map param;
> + struct iommu_table *tbl = container->tbl;
> + enum dma_data_direction direction = DMA_NONE;
> +
> + if (WARN_ON(!tbl))
> + return -ENXIO;
> +
> + minsz = offsetofend(vfio_iommu_spapr_tce_dma_map, size);
> +
> + if (copy_from_user(¶m, (void __user *)arg, minsz))
> + return -EFAULT;
> +
> + if (param.argsz < minsz)
> + return -EINVAL;
> +
> + if ((param.flags & VFIO_DMA_MAP_FLAG_READ) &&
> + (param.flags & VFIO_DMA_MAP_FLAG_WRITE)) {
> + direction = DMA_BIDIRECTIONAL;
> + } else if (param.flags & VFIO_DMA_MAP_FLAG_READ) {
> + direction = DMA_TO_DEVICE;
> + } else if (param.flags & VFIO_DMA_MAP_FLAG_WRITE) {
> + direction = DMA_FROM_DEVICE;
> + }
> +
> + param.size += param.iova & ~IOMMU_PAGE_MASK;
> + param.size = _ALIGN_UP(param.size, IOMMU_PAGE_SIZE);
On x86 we force iova, vaddr, and size to all be aligned to the smallest
page granularity of the iommu and return -EINVAL if it doesn't fit.
What does it imply to the user if they're always aligned to work here?
Won't this interface happily map overlapping entries with no indication
to the user that the previous mapping is no longer valid?
Maybe another reason why a combined unmap/map makes me nervous, we have
to assume the user knows what they're doing.
> +
> + return iommu_put_tces(tbl, param.iova >> IOMMU_PAGE_SHIFT,
> + param.vaddr & IOMMU_PAGE_MASK, direction,
> + param.size >> IOMMU_PAGE_SHIFT);
> + }
> + case VFIO_IOMMU_UNMAP_DMA: {
> + vfio_iommu_spapr_tce_dma_unmap param;
> + struct iommu_table *tbl = container->tbl;
> +
> + if (WARN_ON(!tbl))
> + return -ENXIO;
> +
> + minsz = offsetofend(vfio_iommu_spapr_tce_dma_unmap, size);
> +
> + if (copy_from_user(¶m, (void __user *)arg, minsz))
> + return -EFAULT;
> +
> + if (param.argsz < minsz)
> + return -EINVAL;
> +
> + param.size += param.iova & ~IOMMU_PAGE_MASK;
> + param.size = _ALIGN_UP(param.size, IOMMU_PAGE_SIZE);
> +
> + return iommu_put_tces(tbl, param.iova >> IOMMU_PAGE_SHIFT,
> + 0, DMA_NONE, param.size >> IOMMU_PAGE_SHIFT);
> + }
> + default:
> + printk(KERN_WARNING "tce_vfio: unexpected cmd %x\n", cmd);
pr_warn
> + }
> +
> + return -ENOTTY;
> +}
> +
> +static int tce_iommu_attach_group(void *iommu_data,
> + struct iommu_group *iommu_group)
> +{
> + struct tce_container *container = iommu_data;
> + struct iommu_table *tbl = iommu_group_get_iommudata(iommu_group);
> +
> + BUG_ON(!tbl);
> + mutex_lock(&container->lock);
> + pr_debug("tce_vfio: Attaching group #%u to iommu %p\n",
> + iommu_group_id(iommu_group), iommu_group);
> + if (container->tbl) {
> + printk(KERN_WARNING "tce_vfio: Only one group per IOMMU container is allowed, existing id=%d, attaching id=%d\n",
pr_warn
> + iommu_group_id(container->tbl->it_group),
> + iommu_group_id(iommu_group));
> + mutex_unlock(&container->lock);
> + return -EBUSY;
> + }
> +
> + container->tbl = tbl;
Would it be too much paranoia to clear all the tce here as you do below
on detach? ie. is there any risk that there's leftover programming?
x86 allocates a new domain on open of the iommu, so we always start out
clean.
> + mutex_unlock(&container->lock);
> +
> + return 0;
> +}
> +
> +static void tce_iommu_detach_group(void *iommu_data,
> + struct iommu_group *iommu_group)
> +{
> + struct tce_container *container = iommu_data;
> + struct iommu_table *tbl = iommu_group_get_iommudata(iommu_group);
> +
> + BUG_ON(!tbl);
> + mutex_lock(&container->lock);
> + if (tbl != container->tbl) {
> + printk(KERN_WARNING "tce_vfio: detaching group #%u, expected group is #%u\n",
pr_warn
> + iommu_group_id(iommu_group),
> + iommu_group_id(tbl->it_group));
> + } else {
> +
> + pr_debug("tce_vfio: detaching group #%u from iommu %p\n",
> + iommu_group_id(iommu_group), iommu_group);
> +
> + iommu_put_tces(tbl, tbl->it_offset, 0, DMA_NONE, tbl->it_size);
So this cleans out any mappings when vfio is closed, good.
> + container->tbl = NULL;
> + }
> + mutex_unlock(&container->lock);
> +}
> +
> +const struct vfio_iommu_driver_ops tce_iommu_driver_ops = {
> + .name = "iommu-vfio-powerpc",
> + .owner = THIS_MODULE,
> + .open = tce_iommu_open,
> + .release = tce_iommu_release,
> + .ioctl = tce_iommu_ioctl,
> + .attach_group = tce_iommu_attach_group,
> + .detach_group = tce_iommu_detach_group,
> +};
> +
> +static int __init tce_iommu_init(void)
> +{
> + return vfio_register_iommu_driver(&tce_iommu_driver_ops);
> +}
> +
> +static void __exit tce_iommu_cleanup(void)
> +{
> + vfio_unregister_iommu_driver(&tce_iommu_driver_ops);
> +}
> +
> +module_init(tce_iommu_init);
> +module_exit(tce_iommu_cleanup);
> +
> +MODULE_VERSION(DRIVER_VERSION);
> +MODULE_LICENSE("GPL v2");
> +MODULE_AUTHOR(DRIVER_AUTHOR);
> +MODULE_DESCRIPTION(DRIVER_DESC);
> +
> diff --git a/include/linux/vfio.h b/include/linux/vfio.h
> index 0a4f180..3ecd65c 100644
> --- a/include/linux/vfio.h
> +++ b/include/linux/vfio.h
> @@ -99,6 +99,7 @@ extern void vfio_unregister_iommu_driver(
> /* Extensions */
>
> #define VFIO_TYPE1_IOMMU 1
> +#define VFIO_SPAPR_TCE_IOMMU 2
>
> /*
> * The IOCTL interface is designed for extensibility by embedding the
> @@ -442,4 +443,23 @@ struct vfio_iommu_type1_dma_unmap {
>
> #define VFIO_IOMMU_UNMAP_DMA _IO(VFIO_TYPE, VFIO_BASE + 14)
>
> +/* -------- Additional API for SPAPR TCE (Server POWERPC) IOMMU -------- */
> +
> +struct vfio_iommu_spapr_tce_info {
> + __u32 argsz;
> + __u32 flags;
> + __u32 dma32_window_start;
> + __u32 dma32_window_size;
> + __u64 dma64_window_start;
> + __u64 dma64_window_size;
> +};
Is there anything we can document about this? It should probably list
that size is in bytes. Is there any need to communicate the IOMMU page
size here?
> +
> +#define VFIO_IOMMU_SPAPR_TCE_GET_INFO _IO(VFIO_TYPE, VFIO_BASE + 12)
> +
> +/* Reuse type1 map/unmap structs as they are the same at the moment */
> +typedef struct vfio_iommu_type1_dma_map vfio_iommu_spapr_tce_dma_map;
> +typedef struct vfio_iommu_type1_dma_unmap vfio_iommu_spapr_tce_dma_unmap;
> +
> +/* ***************************************************************** */
> +
> #endif /* VFIO_H */
Thanks,
Alex
^ permalink raw reply
* Re: [PATCH] vfio powerpc: enabled and supported on powernv platform
From: Alex Williamson @ 2012-11-26 18:04 UTC (permalink / raw)
To: Alexey Kardashevskiy
Cc: kvm@vger.kernel.org, linux-kernel@vger.kernel.org, Paul Mackerras,
Sethi Varun-B16395, linuxppc-dev@lists.ozlabs.org, David Gibson
In-Reply-To: <1353943130.1809.29.camel@bling.home>
On Mon, 2012-11-26 at 08:18 -0700, Alex Williamson wrote:
> On Fri, 2012-11-23 at 13:02 +1100, Alexey Kardashevskiy wrote:
> > On 22/11/12 22:56, Sethi Varun-B16395 wrote:
> > >
> > >
> > >> -----Original Message-----
> > >> From: linux-kernel-owner@vger.kernel.org [mailto:linux-kernel-
> > >> owner@vger.kernel.org] On Behalf Of Alex Williamson
> > >> Sent: Tuesday, November 20, 2012 11:50 PM
> > >> To: Alexey Kardashevskiy
> > >> Cc: Benjamin Herrenschmidt; Paul Mackerras; linuxppc-
> > >> dev@lists.ozlabs.org; linux-kernel@vger.kernel.org; kvm@vger.kernel.org;
> > >> David Gibson
> > >> Subject: Re: [PATCH] vfio powerpc: enabled and supported on powernv
> > >> platform
> > >>
> > >> On Tue, 2012-11-20 at 11:48 +1100, Alexey Kardashevskiy wrote:
> > >>> VFIO implements platform independent stuff such as a PCI driver, BAR
> > >>> access (via read/write on a file descriptor or direct mapping when
> > >>> possible) and IRQ signaling.
> > >>> The platform dependent part includes IOMMU initialization and
> > >>> handling.
> > >>>
> > >>> This patch initializes IOMMU groups based on the IOMMU configuration
> > >>> discovered during the PCI scan, only POWERNV platform is supported at
> > >>> the moment.
> > >>>
> > >>> Also the patch implements an VFIO-IOMMU driver which manages DMA
> > >>> mapping/unmapping requests coming from the client (now QEMU). It also
> > >>> returns a DMA window information to let the guest initialize the
> > >>> device tree for a guest OS properly. Although this driver has been
> > >>> tested only on POWERNV, it should work on any platform supporting TCE
> > >>> tables.
> > >>>
> > >>> To enable VFIO on POWER, enable SPAPR_TCE_IOMMU config option.
> > >>>
> > >>> Cc: David Gibson <david@gibson.dropbear.id.au>
> > >>> Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
> > >>> ---
> > >>> arch/powerpc/include/asm/iommu.h | 6 +
> > >>> arch/powerpc/kernel/iommu.c | 140 +++++++++++++++++++
> > >>> arch/powerpc/platforms/powernv/pci.c | 135 +++++++++++++++++++
> > >>> drivers/iommu/Kconfig | 8 ++
> > >>> drivers/vfio/Kconfig | 6 +
> > >>> drivers/vfio/Makefile | 1 +
> > >>> drivers/vfio/vfio_iommu_spapr_tce.c | 247
> > >> ++++++++++++++++++++++++++++++++++
> > >>> include/linux/vfio.h | 20 +++
> > >>> 8 files changed, 563 insertions(+)
> > >>> create mode 100644 drivers/vfio/vfio_iommu_spapr_tce.c
> > >>>
> > >>> diff --git a/arch/powerpc/include/asm/iommu.h
> > >>> b/arch/powerpc/include/asm/iommu.h
> > >>> index cbfe678..5ba66cb 100644
> > >>> --- a/arch/powerpc/include/asm/iommu.h
> > >>> +++ b/arch/powerpc/include/asm/iommu.h
> > >>> @@ -64,30 +64,33 @@ struct iommu_pool { }
> > >>> ____cacheline_aligned_in_smp;
> > >>>
> > >>> struct iommu_table {
> > >>> unsigned long it_busno; /* Bus number this table belongs to */
> > >>> unsigned long it_size; /* Size of iommu table in entries */
> > >>> unsigned long it_offset; /* Offset into global table */
> > >>> unsigned long it_base; /* mapped address of tce table */
> > >>> unsigned long it_index; /* which iommu table this is */
> > >>> unsigned long it_type; /* type: PCI or Virtual Bus */
> > >>> unsigned long it_blocksize; /* Entries in each block (cacheline)
> > >> */
> > >>> unsigned long poolsize;
> > >>> unsigned long nr_pools;
> > >>> struct iommu_pool large_pool;
> > >>> struct iommu_pool pools[IOMMU_NR_POOLS];
> > >>> unsigned long *it_map; /* A simple allocation bitmap for now
> > >> */
> > >>> +#ifdef CONFIG_IOMMU_API
> > >>> + struct iommu_group *it_group;
> > >>> +#endif
> > >>> };
> > >>>
> > >>> struct scatterlist;
> > >>>
> > >>> static inline void set_iommu_table_base(struct device *dev, void
> > >>> *base) {
> > >>> dev->archdata.dma_data.iommu_table_base = base; }
> > >>>
> > >>> static inline void *get_iommu_table_base(struct device *dev) {
> > >>> return dev->archdata.dma_data.iommu_table_base;
> > >>> }
> > >>>
> > >>> /* Frees table for an individual device node */ @@ -135,17 +138,20 @@
> > >>> static inline void pci_iommu_init(void) { } extern void
> > >>> alloc_dart_table(void); #if defined(CONFIG_PPC64) &&
> > >>> defined(CONFIG_PM) static inline void iommu_save(void) {
> > >>> if (ppc_md.iommu_save)
> > >>> ppc_md.iommu_save();
> > >>> }
> > >>>
> > >>> static inline void iommu_restore(void) {
> > >>> if (ppc_md.iommu_restore)
> > >>> ppc_md.iommu_restore();
> > >>> }
> > >>> #endif
> > >>>
> > >>> +extern long iommu_put_tces(struct iommu_table *tbl, unsigned long
> > >> entry, uint64_t tce,
> > >>> + enum dma_data_direction direction, unsigned long pages);
> > >>> +
> > >>> #endif /* __KERNEL__ */
> > >>> #endif /* _ASM_IOMMU_H */
> > >>> diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
> > >>> index ff5a6ce..94f614b 100644
> > >>> --- a/arch/powerpc/kernel/iommu.c
> > >>> +++ b/arch/powerpc/kernel/iommu.c
> > >>> @@ -32,30 +32,31 @@
> > >>> #include <linux/dma-mapping.h>
> > >>> #include <linux/bitmap.h>
> > >>> #include <linux/iommu-helper.h>
> > >>> #include <linux/crash_dump.h>
> > >>> #include <linux/hash.h>
> > >>> #include <linux/fault-inject.h>
> > >>> #include <linux/pci.h>
> > >>> #include <asm/io.h>
> > >>> #include <asm/prom.h>
> > >>> #include <asm/iommu.h>
> > >>> #include <asm/pci-bridge.h>
> > >>> #include <asm/machdep.h>
> > >>> #include <asm/kdump.h>
> > >>> #include <asm/fadump.h>
> > >>> #include <asm/vio.h>
> > >>> +#include <asm/tce.h>
> > >>>
> > >>> #define DBG(...)
> > >>>
> > >>> static int novmerge;
> > >>>
> > >>> static void __iommu_free(struct iommu_table *, dma_addr_t, unsigned
> > >>> int);
> > >>>
> > >>> static int __init setup_iommu(char *str) {
> > >>> if (!strcmp(str, "novmerge"))
> > >>> novmerge = 1;
> > >>> else if (!strcmp(str, "vmerge"))
> > >>> novmerge = 0;
> > >>> return 1;
> > >>> }
> > >>> @@ -844,15 +845,154 @@ void *iommu_alloc_coherent(struct device *dev,
> > >>> struct iommu_table *tbl, }
> > >>>
> > >>> void iommu_free_coherent(struct iommu_table *tbl, size_t size,
> > >>> void *vaddr, dma_addr_t dma_handle) {
> > >>> if (tbl) {
> > >>> unsigned int nio_pages;
> > >>>
> > >>> size = PAGE_ALIGN(size);
> > >>> nio_pages = size >> IOMMU_PAGE_SHIFT;
> > >>> iommu_free(tbl, dma_handle, nio_pages);
> > >>> size = PAGE_ALIGN(size);
> > >>> free_pages((unsigned long)vaddr, get_order(size));
> > >>> }
> > >>> }
> > >>> +
> > >>> +#ifdef CONFIG_IOMMU_API
> > >>> +/*
> > >>> + * SPAPR TCE API
> > >>> + */
> > >>> +static struct page *free_tce(struct iommu_table *tbl, unsigned long
> > >>> +entry) {
> > >>> + struct page *page = NULL;
> > >>
> > >> NULL initialization doesn't appear to be necessary
> > >>
> > >>> + unsigned long oldtce;
> > >>> +
> > >>> + oldtce = ppc_md.tce_get(tbl, entry);
> > >>> +
> > >>> + if (!(oldtce & (TCE_PCI_WRITE | TCE_PCI_READ)))
> > >>> + return NULL;
> > >>> +
> > >>> + page = pfn_to_page(oldtce >> PAGE_SHIFT);
> > >>> +
> > >>> + WARN_ON(!page);
> > >>> + if (page && (oldtce & TCE_PCI_WRITE))
> > >>> + SetPageDirty(page);
> > >>> + ppc_md.tce_free(tbl, entry, 1);
> > >>> +
> > >>> + return page;
> > >>> +}
> > >>> +
> > >>> +static int put_tce(struct iommu_table *tbl, unsigned long entry,
> > >>> + uint64_t tce, enum dma_data_direction direction) {
> > >>> + int ret;
> > >>> + struct page *page = NULL;
> > >>> + unsigned long kva, offset;
> > >>> +
> > >>> + /* Map new TCE */
> > >>> + offset = (tce & IOMMU_PAGE_MASK) - (tce & PAGE_MASK);
> > >>> + ret = get_user_pages_fast(tce & PAGE_MASK, 1,
> > >>> + direction != DMA_TO_DEVICE, &page);
> > >>> + if (ret < 1) {
> > >>> + printk(KERN_ERR "tce_vfio: get_user_pages_fast failed
> > >> tce=%llx ioba=%lx ret=%d\n",
> > >>> + tce, entry << IOMMU_PAGE_SHIFT, ret);
> > >>> + if (!ret)
> > >>> + ret = -EFAULT;
> > >>
> > >> Missing return ret? Otherwise we've got some bogus uses of page below
> > >> and we're setting ret for no reason here.
> > >>
> > >>> + }
> > >>> +
> > >>> + kva = (unsigned long) page_address(page);
> > >>> + kva += offset;
> > >>> +
> > >>> + /* tce_build receives a virtual address */
> > >>> + entry += tbl->it_offset; /* Offset into real TCE table */
> > >>> + ret = ppc_md.tce_build(tbl, entry, 1, kva, direction, NULL);
> > >>> +
> > >>> + /* tce_build() only returns non-zero for transient errors */
> > >>> + if (unlikely(ret)) {
> > >>> + printk(KERN_ERR "tce_vfio: tce_put failed on tce=%llx
> > >> ioba=%lx kva=%lx ret=%d\n",
> > >>> + tce, entry << IOMMU_PAGE_SHIFT, kva, ret);
> > >>> + put_page(page);
> > >>> + return -EIO;
> > >>> + }
> > >>> +
> > >>> + return 0;
> > >>> +}
> > >>> +
> > >>> +static void tce_flush(struct iommu_table *tbl) {
> > >>> + /* Flush/invalidate TLB caches if necessary */
> > >>> + if (ppc_md.tce_flush)
> > >>> + ppc_md.tce_flush(tbl);
> > >>> +
> > >>> + /* Make sure updates are seen by hardware */
> > >>> + mb();
> > >>> +}
> > >>> +
> > >>> +long iommu_put_tces(struct iommu_table *tbl, unsigned long entry,
> > >> uint64_t tce,
> > >>> + enum dma_data_direction direction, unsigned long pages) {
> > >>> + int i, ret = 0, pages_to_put = 0;
> > >>> + struct page *page;
> > >>> + struct iommu_pool *pool = get_pool(tbl, entry);
> > >>> + struct page **oldpages;
> > >>> + const int oldpagesnum = PAGE_SIZE/sizeof(*oldpages);
> > >>> +
> > >>> + BUILD_BUG_ON(PAGE_SIZE < IOMMU_PAGE_SIZE);
> > >>> +
> > >>> + /* Handle a single page request without allocation
> > >>> + of pages-to-release array */
> > >>> + if (pages == 1) {
> > >>> + spin_lock(&(pool->lock));
> > >>> + page = free_tce(tbl, entry);
> > >>> +
> > >>> + if (direction != DMA_NONE)
> > >>> + ret = put_tce(tbl, entry, tce, direction);
> > >>> +
> > >>> + tce_flush(tbl);
> > >>> +
> > >>> + if (page)
> > >>> + put_page(page);
> > >>> +
> > >>> + spin_unlock(&(pool->lock));
> > >>> + return ret;
> > >>> + }
> > >>> +
> > >>> + /* Releasing multiple pages */
> > >>> + /* Allocate an array for pages to be released after TCE table
> > >>> + is updated */
> > >>> + oldpages = kmalloc(PAGE_SIZE, GFP_KERNEL);
> > >>> + if (!oldpages)
> > >>> + return -ENOMEM;
> > >>> +
> > >>> + spin_lock(&(pool->lock));
> > >>> +
> > >>> + for (i = 0; (i < pages) && !ret; ++i, ++entry, tce +=
> > >> IOMMU_PAGE_SIZE) {
> > >>> + page = free_tce(tbl, entry);
> > >>> + if (page) {
> > >>> + oldpages[pages_to_put] = page;
> > >>> + ++pages_to_put;
> > >>> + }
> > >>> +
> > >>> + if (direction != DMA_NONE)
> > >>> + ret = put_tce(tbl, entry, tce, direction);
> > >>> +
> > >>> + /* Release old pages if we reached the end of oldpages[] or
> > >>> + it is the last page or we are about to exit the loop */
> > >>> + if ((pages_to_put == oldpagesnum) || (i == pages - 1) || ret)
> > >> {
> > >>> + tce_flush(tbl);
> > >>
> > >> Avoiding tce_flush() is the reason for all this extra overhead, right?
> > >> I wonder if it'd be cleaner separating map vs unmap, where the map case
> > >> can avoid the oldpages array... but that means inserting new mappings on
> > >> top of old ones wouldn't put the pages.
> >
> >
> > Yes, we do not want to loose pages if the guest forgot to unmap them.
>
> Hmm, does that mean we're not actively clearing tce entries or somehow
> disabling the iommu window when the iommu is released through vfio?
Ok, I see tces are put on shutdown via tce_iommu_detach_group, so you're
more concerned about the guest simply mapping over top of it's own
mappings. Is that common? Is it common enough for every multi-page
mapping to assume it will happen? I know this is a performance
sensitive path for you and it seems like a map-only w/ fallback to
unmap, remap would be better in the general case.
On x86 we do exactly that, but we do the unmap, remap from userspace
when we get an EBUSY. Thanks,
Alex
^ permalink raw reply
* Re: [Pv-drivers] [PATCH 192/493] scsi: remove use of __devinit
From: Dmitry Torokhov @ 2012-11-26 17:37 UTC (permalink / raw)
To: Bill Pemberton
Cc: VMware PV-Drivers, Kurt Garloff, Kai Mäkisara, GOTO Masanori,
Russell King, linux-scsi, Jamie Lenehan, osst-users, Michael Reed,
cbe-oss-dev, iss_storagedev, Matthew Wilcox, Ali Akcaagac, dc395x,
linux-arm-kernel, Neela Syam Kolli, Geoff Levand, gregkh,
Oliver Neukum, James E.J. Bottomley, Willem Riede, YOKOTA Hiroshi,
linuxppc-dev, Guennadi Liakhovetski
In-Reply-To: <1353349642-3677-192-git-send-email-wfp5p@virginia.edu>
On Mon, Nov 19, 2012 at 01:22:21PM -0500, Bill Pemberton wrote:
> CONFIG_HOTPLUG is going away as an option so __devinit is no longer
> needed.
>
...
> drivers/scsi/vmw_pvscsi.c | 6 +-
For vmw_pvscsi:
Acked-by: Dmitry Torokhov <dtor@vmware.com>
Thanks,
Dmitry
^ permalink raw reply
* Re: [PATCH 0/9] dma_debug: add debug_dma_mapping_error support to architectures that support DMA_DEBUG_API
From: Shuah Khan @ 2012-11-26 16:09 UTC (permalink / raw)
To: Joerg Roedel
Cc: linux-mips, linux-ia64, a-jacquiot, catalin.marinas, Ming Lei,
shuahkhan, sparclinux, m.szyprowski, linux-c6x-dev, linux-sh,
msalter, fenghua.yu, microblaze-uclinux, linux-arm-kernel, monstr,
tony.luck, LKML, ralf, lethal, linuxppc-dev, davem
In-Reply-To: <20121126112217.GG25742@8bytes.org>
On Mon, 2012-11-26 at 12:22 +0100, Joerg Roedel wrote:
> Hi Shuah,
>
> On Fri, Nov 23, 2012 at 02:29:02PM -0700, Shuah Khan wrote:
> > x86 - done in the first patch that added the feature.
> >
> > ARM64: dma_debug: add debug_dma_mapping_error support
> > c6x: dma_debug: add debug_dma_mapping_error support
> > ia64: dma_debug: add debug_dma_mapping_error support
> > microblaze: dma-mapping: support debug_dma_mapping_error
> > mips: dma_debug: add debug_dma_mapping_error support
> > powerpc: dma_debug: add debug_dma_mapping_error support
> > sh: dma_debug: add debug_dma_mapping_error support
> > sparc: dma_debug: add debug_dma_mapping_error support
> > tile: dma_debug: add debug_dma_mapping_error support
>
> Have you compile-tested the invididual archs you are changing here?
>
Joerg,
Yes I compile tested all of them (except microblaze) on Nov 20th
linux_next git. The patch for microblaze is already in linux_next when I
tried to apply the patch to Nov 20th linux-next and figured that is
already covered and skipped that one.
-- Shuah
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox