aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2014-12-09 13:56:50 -0500
committerMichael Ellerman <mpe@ellerman.id.au>2014-12-14 18:46:32 -0500
commit8117ac6a6c2fa0f847ff6a21a1f32c8d2c8501d0 (patch)
tree5a241a94c1ebbfce37287e753c45404b6b0bbded
parent470834508f87877f680738a10a305280582c7aed (diff)
powerpc/powernv: Switch off MMU before entering nap/sleep/rvwinkle mode
Currently, when going idle, we set the flag indicating that we are in nap mode (paca->kvm_hstate.hwthread_state) and then execute the nap (or sleep or rvwinkle) instruction, all with the MMU on. This is bad for two reasons: (a) the architecture specifies that those instructions must be executed with the MMU off, and in fact with only the SF, HV, ME and possibly RI bits set, and (b) this introduces a race, because as soon as we set the flag, another thread can switch the MMU to a guest context. If the race is lost, this thread will typically start looping on relocation-on ISIs at 0xc...4400. This fixes it by setting the MSR as required by the architecture before setting the flag or executing the nap/sleep/rvwinkle instruction. Cc: stable@vger.kernel.org [ shreyas@linux.vnet.ibm.com: Edited to handle LE ] Signed-off-by: Paul Mackerras <paulus@samba.org> Signed-off-by: Shreyas B. Prabhu <shreyas@linux.vnet.ibm.com> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Michael Ellerman <mpe@ellerman.id.au> Cc: linuxppc-dev@lists.ozlabs.org Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
-rw-r--r--arch/powerpc/include/asm/reg.h2
-rw-r--r--arch/powerpc/kernel/idle_power7.S18
2 files changed, 19 insertions, 1 deletions
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index c998279bd85b..a68ee15964b3 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -118,8 +118,10 @@
118#define __MSR (MSR_ME | MSR_RI | MSR_IR | MSR_DR | MSR_ISF |MSR_HV) 118#define __MSR (MSR_ME | MSR_RI | MSR_IR | MSR_DR | MSR_ISF |MSR_HV)
119#ifdef __BIG_ENDIAN__ 119#ifdef __BIG_ENDIAN__
120#define MSR_ __MSR 120#define MSR_ __MSR
121#define MSR_IDLE (MSR_ME | MSR_SF | MSR_HV)
121#else 122#else
122#define MSR_ (__MSR | MSR_LE) 123#define MSR_ (__MSR | MSR_LE)
124#define MSR_IDLE (MSR_ME | MSR_SF | MSR_HV | MSR_LE)
123#endif 125#endif
124#define MSR_KERNEL (MSR_ | MSR_64BIT) 126#define MSR_KERNEL (MSR_ | MSR_64BIT)
125#define MSR_USER32 (MSR_ | MSR_PR | MSR_EE) 127#define MSR_USER32 (MSR_ | MSR_PR | MSR_EE)
diff --git a/arch/powerpc/kernel/idle_power7.S b/arch/powerpc/kernel/idle_power7.S
index 18c0687e5ab3..e5aba6abbe6c 100644
--- a/arch/powerpc/kernel/idle_power7.S
+++ b/arch/powerpc/kernel/idle_power7.S
@@ -101,7 +101,23 @@ _GLOBAL(power7_powersave_common)
101 std r9,_MSR(r1) 101 std r9,_MSR(r1)
102 std r1,PACAR1(r13) 102 std r1,PACAR1(r13)
103 103
104_GLOBAL(power7_enter_nap_mode) 104 /*
105 * Go to real mode to do the nap, as required by the architecture.
106 * Also, we need to be in real mode before setting hwthread_state,
107 * because as soon as we do that, another thread can switch
108 * the MMU context to the guest.
109 */
110 LOAD_REG_IMMEDIATE(r5, MSR_IDLE)
111 li r6, MSR_RI
112 andc r6, r9, r6
113 LOAD_REG_ADDR(r7, power7_enter_nap_mode)
114 mtmsrd r6, 1 /* clear RI before setting SRR0/1 */
115 mtspr SPRN_SRR0, r7
116 mtspr SPRN_SRR1, r5
117 rfid
118
119 .globl power7_enter_nap_mode
120power7_enter_nap_mode:
105#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE 121#ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
106 /* Tell KVM we're napping */ 122 /* Tell KVM we're napping */
107 li r4,KVM_HWTHREAD_IN_NAP 123 li r4,KVM_HWTHREAD_IN_NAP