diff options
| -rw-r--r-- | arch/powerpc/include/asm/reg.h | 3 | ||||
| -rw-r--r-- | arch/powerpc/include/asm/xics.h | 1 | ||||
| -rw-r--r-- | arch/powerpc/platforms/powernv/smp.c | 12 | ||||
| -rw-r--r-- | arch/powerpc/sysdev/xics/icp-opal.c | 29 |
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 |
| 46 | extern int icp_opal_init(void); | 46 | extern int icp_opal_init(void); |
| 47 | extern void icp_opal_flush_interrupt(void); | ||
| 47 | #else | 48 | #else |
| 48 | static inline int icp_opal_init(void) { return -ENODEV; } | 49 | static 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 | */ | ||
| 139 | void 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 | ||
| 137 | static const struct icp_ops icp_opal_ops = { | 166 | static const struct icp_ops icp_opal_ops = { |
