aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 0d4531aa2052..dff79798903d 100644
--- a/arch/powerpc/include/asm/reg.h
+++ b/arch/powerpc/include/asm/reg.h
@@ -649,9 +649,10 @@
649#define SRR1_ISI_N_OR_G 0x10000000 /* ISI: Access is no-exec or G */ 649#define SRR1_ISI_N_OR_G 0x10000000 /* ISI: Access is no-exec or G */
650#define SRR1_ISI_PROT 0x08000000 /* ISI: Other protection fault */ 650#define SRR1_ISI_PROT 0x08000000 /* ISI: Other protection fault */
651#define SRR1_WAKEMASK 0x00380000 /* reason for wakeup */ 651#define SRR1_WAKEMASK 0x00380000 /* reason for wakeup */
652#define SRR1_WAKEMASK_P8 0x003c0000 /* reason for wakeup on POWER8 */ 652#define SRR1_WAKEMASK_P8 0x003c0000 /* reason for wakeup on POWER8 and 9 */
653#define SRR1_WAKESYSERR 0x00300000 /* System error */ 653#define SRR1_WAKESYSERR 0x00300000 /* System error */
654#define SRR1_WAKEEE 0x00200000 /* External interrupt */ 654#define SRR1_WAKEEE 0x00200000 /* External interrupt */
655#define SRR1_WAKEHVI 0x00240000 /* Hypervisor Virtualization Interrupt (P9) */
655#define SRR1_WAKEMT 0x00280000 /* mtctrl */ 656#define SRR1_WAKEMT 0x00280000 /* mtctrl */
656#define SRR1_WAKEHMI 0x00280000 /* Hypervisor maintenance */ 657#define SRR1_WAKEHMI 0x00280000 /* Hypervisor maintenance */
657#define SRR1_WAKEDEC 0x00180000 /* Decrementer interrupt */ 658#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 = {