aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2017-02-06 19:35:31 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-02-14 18:25:40 -0500
commite7f9f10bcc8dbbf0e09aba6765e9e07bc59910f1 (patch)
tree426c8148dfbf28a2f7ce3b209ec367198979f15c
parent3433972d049f256a57b3538b2d29a7ee38748019 (diff)
powerpc/powernv: Fix CPU hotplug to handle waking on HVI
commit 9b256714979fad61ae11d90b53cf67dd5e6484eb upstream. The IPIs come in as HVI not EE, so we need to test the appropriate SRR1 bits. The encoding is such that it won't have false positives on P7 and P8 so we can just test it like that. We also need to handle the icp-opal variant of the flush. Fixes: d74361881f0d ("powerpc/xics: Add ICP OPAL backend") Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--arch/powerpc/include/asm/reg.h3
-rw-r--r--arch/powerpc/include/asm/xics.h1
-rw-r--r--arch/powerpc/platforms/powernv/smp.c12
-rw-r--r--arch/powerpc/sysdev/xics/icp-opal.c29
4 files changed, 42 insertions, 3 deletions
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h
index 9e1499f98def..13f5fad21066 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -641,9 +641,10 @@
641#define SRR1_ISI_N_OR_G 0x10000000 /* ISI: Access is no-exec or G */ 641#define SRR1_ISI_N_OR_G 0x10000000 /* ISI: Access is no-exec or G */
642#define SRR1_ISI_PROT 0x08000000 /* ISI: Other protection fault */ 642#define SRR1_ISI_PROT 0x08000000 /* ISI: Other protection fault */
643#define SRR1_WAKEMASK 0x00380000 /* reason for wakeup */ 643#define SRR1_WAKEMASK 0x00380000 /* reason for wakeup */
644#define SRR1_WAKEMASK_P8 0x003c0000 /* reason for wakeup on POWER8 */ 644#define SRR1_WAKEMASK_P8 0x003c0000 /* reason for wakeup on POWER8 and 9 */
645#define SRR1_WAKESYSERR 0x00300000 /* System error */ 645#define SRR1_WAKESYSERR 0x00300000 /* System error */
646#define SRR1_WAKEEE 0x00200000 /* External interrupt */ 646#define SRR1_WAKEEE 0x00200000 /* External interrupt */
647#define SRR1_WAKEHVI 0x00240000 /* Hypervisor Virtualization Interrupt (P9) */
647#define SRR1_WAKEMT 0x00280000 /* mtctrl */ 648#define SRR1_WAKEMT 0x00280000 /* mtctrl */
648#define SRR1_WAKEHMI 0x00280000 /* Hypervisor maintenance */ 649#define SRR1_WAKEHMI 0x00280000 /* Hypervisor maintenance */
649#define SRR1_WAKEDEC 0x00180000 /* Decrementer interrupt */ 650#define SRR1_WAKEDEC 0x00180000 /* Decrementer interrupt */
diff --git a/arch/powerpc/include/asm/xics.h b/arch/powerpc/include/asm/xics.h
index f0b238516e9b..e0b9e576905a 100644
--- a/arch/powerpc/include/asm/xics.h
+++ b/arch/powerpc/include/asm/xics.h
@@ -44,6 +44,7 @@ static inline int icp_hv_init(void) { return -ENODEV; }
44 44
45#ifdef CONFIG_PPC_POWERNV 45#ifdef CONFIG_PPC_POWERNV
46extern int icp_opal_init(void); 46extern int icp_opal_init(void);
47extern void icp_opal_flush_interrupt(void);
47#else 48#else
48static inline int icp_opal_init(void) { return -ENODEV; } 49static inline int icp_opal_init(void) { return -ENODEV; }
49#endif 50#endif
diff --git a/arch/powerpc/platforms/powernv/smp.c b/arch/powerpc/platforms/powernv/smp.c
index c789258ae1e1..eec0e8d0454d 100644
--- a/arch/powerpc/platforms/powernv/smp.c
+++ b/arch/powerpc/platforms/powernv/smp.c
@@ -155,8 +155,10 @@ static void pnv_smp_cpu_kill_self(void)
155 wmask = SRR1_WAKEMASK_P8; 155 wmask = SRR1_WAKEMASK_P8;
156 156
157 idle_states = pnv_get_supported_cpuidle_states(); 157 idle_states = pnv_get_supported_cpuidle_states();
158
158 /* We don't want to take decrementer interrupts while we are offline, 159 /* We don't want to take decrementer interrupts while we are offline,
159 * so clear LPCR:PECE1. We keep PECE2 enabled. 160 * so clear LPCR:PECE1. We keep PECE2 (and LPCR_PECE_HVEE on P9)
161 * enabled as to let IPIs in.
160 */ 162 */
161 mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) & ~(u64)LPCR_PECE1); 163 mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) & ~(u64)LPCR_PECE1);
162 164
@@ -206,8 +208,12 @@ static void pnv_smp_cpu_kill_self(void)
206 * contains 0. 208 * contains 0.
207 */ 209 */
208 if (((srr1 & wmask) == SRR1_WAKEEE) || 210 if (((srr1 & wmask) == SRR1_WAKEEE) ||
211 ((srr1 & wmask) == SRR1_WAKEHVI) ||
209 (local_paca->irq_happened & PACA_IRQ_EE)) { 212 (local_paca->irq_happened & PACA_IRQ_EE)) {
210 icp_native_flush_interrupt(); 213 if (cpu_has_feature(CPU_FTR_ARCH_300))
214 icp_opal_flush_interrupt();
215 else
216 icp_native_flush_interrupt();
211 } else if ((srr1 & wmask) == SRR1_WAKEHDBELL) { 217 } else if ((srr1 & wmask) == SRR1_WAKEHDBELL) {
212 unsigned long msg = PPC_DBELL_TYPE(PPC_DBELL_SERVER); 218 unsigned long msg = PPC_DBELL_TYPE(PPC_DBELL_SERVER);
213 asm volatile(PPC_MSGCLR(%0) : : "r" (msg)); 219 asm volatile(PPC_MSGCLR(%0) : : "r" (msg));
@@ -221,6 +227,8 @@ static void pnv_smp_cpu_kill_self(void)
221 if (srr1 && !generic_check_cpu_restart(cpu)) 227 if (srr1 && !generic_check_cpu_restart(cpu))
222 DBG("CPU%d Unexpected exit while offline !\n", cpu); 228 DBG("CPU%d Unexpected exit while offline !\n", cpu);
223 } 229 }
230
231 /* Re-enable decrementer interrupts */
224 mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) | LPCR_PECE1); 232 mtspr(SPRN_LPCR, mfspr(SPRN_LPCR) | LPCR_PECE1);
225 DBG("CPU%d coming online...\n", cpu); 233 DBG("CPU%d coming online...\n", cpu);
226} 234}
diff --git a/arch/powerpc/sysdev/xics/icp-opal.c b/arch/powerpc/sysdev/xics/icp-opal.c
index 60c57657c772..c96c0cb95d87 100644
--- a/arch/powerpc/sysdev/xics/icp-opal.c
+++ b/arch/powerpc/sysdev/xics/icp-opal.c
@@ -132,6 +132,35 @@ static irqreturn_t icp_opal_ipi_action(int irq, void *dev_id)
132 return smp_ipi_demux(); 132 return smp_ipi_demux();
133} 133}
134 134
135/*
136 * Called when an interrupt is received on an off-line CPU to
137 * clear the interrupt, so that the CPU can go back to nap mode.
138 */
139void icp_opal_flush_interrupt(void)
140{
141 unsigned int xirr;
142 unsigned int vec;
143
144 do {
145 xirr = icp_opal_get_xirr();
146 vec = xirr & 0x00ffffff;
147 if (vec == XICS_IRQ_SPURIOUS)
148 break;
149 if (vec == XICS_IPI) {
150 /* Clear pending IPI */
151 int cpu = smp_processor_id();
152 kvmppc_set_host_ipi(cpu, 0);
153 opal_int_set_mfrr(get_hard_smp_processor_id(cpu), 0xff);
154 } else {
155 pr_err("XICS: hw interrupt 0x%x to offline cpu, "
156 "disabling\n", vec);
157 xics_mask_unknown_vec(vec);
158 }
159
160 /* EOI the interrupt */
161 } while (opal_int_eoi(xirr) > 0);
162}
163
135#endif /* CONFIG_SMP */ 164#endif /* CONFIG_SMP */
136 165
137static const struct icp_ops icp_opal_ops = { 166static const struct icp_ops icp_opal_ops = {