diff options
| author | Paul Mackerras <paulus@samba.org> | 2015-03-19 04:29:01 -0400 |
|---|---|---|
| committer | Michael Ellerman <mpe@ellerman.id.au> | 2015-03-19 23:51:53 -0400 |
| commit | 755563bc79c764c90b9f44db5e4fe6c556d3440c (patch) | |
| tree | cfd171d1144b36cfcfac76685ad284fb54589259 | |
| parent | 06e5801b8cb3fc057d88cb4dc03c0b64b2744cda (diff) | |
powerpc/powernv: Fixes for hypervisor doorbell handling
Since we can now use hypervisor doorbells for host IPIs, this makes
sure we clear the host IPI flag when taking a doorbell interrupt, and
clears any pending doorbell IPI in pnv_smp_cpu_kill_self() (as we
already do for IPIs sent via the XICS interrupt controller). Otherwise
if there did happen to be a leftover pending doorbell interrupt for
an offline CPU thread for any reason, it would prevent that thread from
going into a power-saving mode; it would instead keep waking up because
of the interrupt.
Signed-off-by: Paul Mackerras <paulus@samba.org>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
| -rw-r--r-- | arch/powerpc/include/asm/ppc-opcode.h | 3 | ||||
| -rw-r--r-- | arch/powerpc/include/asm/reg.h | 3 | ||||
| -rw-r--r-- | arch/powerpc/kernel/dbell.c | 2 | ||||
| -rw-r--r-- | arch/powerpc/platforms/powernv/smp.c | 14 |
4 files changed, 20 insertions, 2 deletions
diff --git a/arch/powerpc/include/asm/ppc-opcode.h b/arch/powerpc/include/asm/ppc-opcode.h index 03cd858a401c..4cbe23af400a 100644 --- a/arch/powerpc/include/asm/ppc-opcode.h +++ b/arch/powerpc/include/asm/ppc-opcode.h | |||
| @@ -153,6 +153,7 @@ | |||
| 153 | #define PPC_INST_MFSPR_PVR_MASK 0xfc1fffff | 153 | #define PPC_INST_MFSPR_PVR_MASK 0xfc1fffff |
| 154 | #define PPC_INST_MFTMR 0x7c0002dc | 154 | #define PPC_INST_MFTMR 0x7c0002dc |
| 155 | #define PPC_INST_MSGSND 0x7c00019c | 155 | #define PPC_INST_MSGSND 0x7c00019c |
| 156 | #define PPC_INST_MSGCLR 0x7c0001dc | ||
| 156 | #define PPC_INST_MSGSNDP 0x7c00011c | 157 | #define PPC_INST_MSGSNDP 0x7c00011c |
| 157 | #define PPC_INST_MTTMR 0x7c0003dc | 158 | #define PPC_INST_MTTMR 0x7c0003dc |
| 158 | #define PPC_INST_NOP 0x60000000 | 159 | #define PPC_INST_NOP 0x60000000 |
| @@ -309,6 +310,8 @@ | |||
| 309 | ___PPC_RB(b) | __PPC_EH(eh)) | 310 | ___PPC_RB(b) | __PPC_EH(eh)) |
| 310 | #define PPC_MSGSND(b) stringify_in_c(.long PPC_INST_MSGSND | \ | 311 | #define PPC_MSGSND(b) stringify_in_c(.long PPC_INST_MSGSND | \ |
| 311 | ___PPC_RB(b)) | 312 | ___PPC_RB(b)) |
| 313 | #define PPC_MSGCLR(b) stringify_in_c(.long PPC_INST_MSGCLR | \ | ||
| 314 | ___PPC_RB(b)) | ||
| 312 | #define PPC_MSGSNDP(b) stringify_in_c(.long PPC_INST_MSGSNDP | \ | 315 | #define PPC_MSGSNDP(b) stringify_in_c(.long PPC_INST_MSGSNDP | \ |
| 313 | ___PPC_RB(b)) | 316 | ___PPC_RB(b)) |
| 314 | #define PPC_POPCNTB(a, s) stringify_in_c(.long PPC_INST_POPCNTB | \ | 317 | #define PPC_POPCNTB(a, s) stringify_in_c(.long PPC_INST_POPCNTB | \ |
diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index 1c874fb533bb..af56b5c6c81a 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h | |||
| @@ -608,13 +608,16 @@ | |||
| 608 | #define SRR1_ISI_N_OR_G 0x10000000 /* ISI: Access is no-exec or G */ | 608 | #define SRR1_ISI_N_OR_G 0x10000000 /* ISI: Access is no-exec or G */ |
| 609 | #define SRR1_ISI_PROT 0x08000000 /* ISI: Other protection fault */ | 609 | #define SRR1_ISI_PROT 0x08000000 /* ISI: Other protection fault */ |
| 610 | #define SRR1_WAKEMASK 0x00380000 /* reason for wakeup */ | 610 | #define SRR1_WAKEMASK 0x00380000 /* reason for wakeup */ |
| 611 | #define SRR1_WAKEMASK_P8 0x003c0000 /* reason for wakeup on POWER8 */ | ||
| 611 | #define SRR1_WAKESYSERR 0x00300000 /* System error */ | 612 | #define SRR1_WAKESYSERR 0x00300000 /* System error */ |
| 612 | #define SRR1_WAKEEE 0x00200000 /* External interrupt */ | 613 | #define SRR1_WAKEEE 0x00200000 /* External interrupt */ |
| 613 | #define SRR1_WAKEMT 0x00280000 /* mtctrl */ | 614 | #define SRR1_WAKEMT 0x00280000 /* mtctrl */ |
| 614 | #define SRR1_WAKEHMI 0x00280000 /* Hypervisor maintenance */ | 615 | #define SRR1_WAKEHMI 0x00280000 /* Hypervisor maintenance */ |
| 615 | #define SRR1_WAKEDEC 0x00180000 /* Decrementer interrupt */ | 616 | #define SRR1_WAKEDEC 0x00180000 /* Decrementer interrupt */ |
| 617 | #define SRR1_WAKEDBELL 0x00140000 /* Privileged doorbell on P8 */ | ||
| 616 | #define SRR1_WAKETHERM 0x00100000 /* Thermal management interrupt */ | 618 | #define SRR1_WAKETHERM 0x00100000 /* Thermal management interrupt */ |
| 617 | #define SRR1_WAKERESET 0x00100000 /* System reset */ | 619 | #define SRR1_WAKERESET 0x00100000 /* System reset */ |
| 620 | #define SRR1_WAKEHDBELL 0x000c0000 /* Hypervisor doorbell on P8 */ | ||
| 618 | #define SRR1_WAKESTATE 0x00030000 /* Powersave exit mask [46:47] */ | 621 | #define SRR1_WAKESTATE 0x00030000 /* Powersave exit mask [46:47] */ |
| 619 | #define SRR1_WS_DEEPEST 0x00030000 /* Some resources not maintained, | 622 | #define SRR1_WS_DEEPEST 0x00030000 /* Some resources not maintained, |
| 620 | * may not be recoverable */ | 623 | * may not be recoverable */ |
diff --git a/arch/powerpc/kernel/dbell.c b/arch/powerpc/kernel/dbell.c index f4217819cc31..2128f3a96c32 100644 --- a/arch/powerpc/kernel/dbell.c +++ b/arch/powerpc/kernel/dbell.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | 17 | ||
| 18 | #include <asm/dbell.h> | 18 | #include <asm/dbell.h> |
| 19 | #include <asm/irq_regs.h> | 19 | #include <asm/irq_regs.h> |
| 20 | #include <asm/kvm_ppc.h> | ||
| 20 | 21 | ||
| 21 | #ifdef CONFIG_SMP | 22 | #ifdef CONFIG_SMP |
| 22 | void doorbell_setup_this_cpu(void) | 23 | void doorbell_setup_this_cpu(void) |
| @@ -41,6 +42,7 @@ void doorbell_exception(struct pt_regs *regs) | |||
| 41 | 42 | ||
| 42 | may_hard_irq_enable(); | 43 | may_hard_irq_enable(); |
| 43 | 44 | ||
| 45 | kvmppc_set_host_ipi(smp_processor_id(), 0); | ||
| 44 | __this_cpu_inc(irq_stat.doorbell_irqs); | 46 | __this_cpu_inc(irq_stat.doorbell_irqs); |
| 45 | 47 | ||
| 46 | smp_ipi_demux(); | 48 | smp_ipi_demux(); |
diff --git a/arch/powerpc/platforms/powernv/smp.c b/arch/powerpc/platforms/powernv/smp.c index fc34025ef822..38a45088f633 100644 --- a/arch/powerpc/platforms/powernv/smp.c +++ b/arch/powerpc/platforms/powernv/smp.c | |||
| @@ -33,6 +33,8 @@ | |||
| 33 | #include <asm/runlatch.h> | 33 | #include <asm/runlatch.h> |
| 34 | #include <asm/code-patching.h> | 34 | #include <asm/code-patching.h> |
| 35 | #include <asm/dbell.h> | 35 | #include <asm/dbell.h> |
| 36 | #include <asm/kvm_ppc.h> | ||
| 37 | #include <asm/ppc-opcode.h> | ||
| 36 | 38 | ||
| 37 | #include "powernv.h" | 39 | #include "powernv.h" |
| 38 | 40 | ||
| @@ -149,7 +151,7 @@ static int pnv_smp_cpu_disable(void) | |||
| 149 | static void pnv_smp_cpu_kill_self(void) | 151 | static void pnv_smp_cpu_kill_self(void) |
| 150 | { | 152 | { |
| 151 | unsigned int cpu; | 153 | unsigned int cpu; |
| 152 | unsigned long srr1; | 154 | unsigned long srr1, wmask; |
| 153 | u32 idle_states; | 155 | u32 idle_states; |
| 154 | 156 | ||
| 155 | /* Standard hot unplug procedure */ | 157 | /* Standard hot unplug procedure */ |
| @@ -161,6 +163,10 @@ static void pnv_smp_cpu_kill_self(void) | |||
| 161 | generic_set_cpu_dead(cpu); | 163 | generic_set_cpu_dead(cpu); |
| 162 | smp_wmb(); | 164 | smp_wmb(); |
| 163 | 165 | ||
| 166 | wmask = SRR1_WAKEMASK; | ||
| 167 | if (cpu_has_feature(CPU_FTR_ARCH_207S)) | ||
| 168 | wmask = SRR1_WAKEMASK_P8; | ||
| 169 | |||
| 164 | idle_states = pnv_get_supported_cpuidle_states(); | 170 | idle_states = pnv_get_supported_cpuidle_states(); |
| 165 | /* We don't want to take decrementer interrupts while we are offline, | 171 | /* We don't want to take decrementer interrupts while we are offline, |
| 166 | * so clear LPCR:PECE1. We keep PECE2 enabled. | 172 | * so clear LPCR:PECE1. We keep PECE2 enabled. |
| @@ -191,10 +197,14 @@ static void pnv_smp_cpu_kill_self(void) | |||
| 191 | * having finished executing in a KVM guest, then srr1 | 197 | * having finished executing in a KVM guest, then srr1 |
| 192 | * contains 0. | 198 | * contains 0. |
| 193 | */ | 199 | */ |
| 194 | if ((srr1 & SRR1_WAKEMASK) == SRR1_WAKEEE) { | 200 | if ((srr1 & wmask) == SRR1_WAKEEE) { |
| 195 | icp_native_flush_interrupt(); | 201 | icp_native_flush_interrupt(); |
| 196 | local_paca->irq_happened &= PACA_IRQ_HARD_DIS; | 202 | local_paca->irq_happened &= PACA_IRQ_HARD_DIS; |
| 197 | smp_mb(); | 203 | smp_mb(); |
| 204 | } else if ((srr1 & wmask) == SRR1_WAKEHDBELL) { | ||
| 205 | unsigned long msg = PPC_DBELL_TYPE(PPC_DBELL_SERVER); | ||
| 206 | asm volatile(PPC_MSGCLR(%0) : : "r" (msg)); | ||
| 207 | kvmppc_set_host_ipi(cpu, 0); | ||
| 198 | } | 208 | } |
| 199 | 209 | ||
| 200 | if (cpu_core_split_required()) | 210 | if (cpu_core_split_required()) |
