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()) |