Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Paul Mackerras and committed by
Michael Ellerman
755563bc 06e5801b

+20 -2
+3
arch/powerpc/include/asm/ppc-opcode.h
··· 153 153 #define PPC_INST_MFSPR_PVR_MASK 0xfc1fffff 154 154 #define PPC_INST_MFTMR 0x7c0002dc 155 155 #define PPC_INST_MSGSND 0x7c00019c 156 + #define PPC_INST_MSGCLR 0x7c0001dc 156 157 #define PPC_INST_MSGSNDP 0x7c00011c 157 158 #define PPC_INST_MTTMR 0x7c0003dc 158 159 #define PPC_INST_NOP 0x60000000 ··· 309 308 ___PPC_RT(t) | ___PPC_RA(a) | \ 310 309 ___PPC_RB(b) | __PPC_EH(eh)) 311 310 #define PPC_MSGSND(b) stringify_in_c(.long PPC_INST_MSGSND | \ 311 + ___PPC_RB(b)) 312 + #define PPC_MSGCLR(b) stringify_in_c(.long PPC_INST_MSGCLR | \ 312 313 ___PPC_RB(b)) 313 314 #define PPC_MSGSNDP(b) stringify_in_c(.long PPC_INST_MSGSNDP | \ 314 315 ___PPC_RB(b))
+3
arch/powerpc/include/asm/reg.h
··· 608 608 #define SRR1_ISI_N_OR_G 0x10000000 /* ISI: Access is no-exec or G */ 609 609 #define SRR1_ISI_PROT 0x08000000 /* ISI: Other protection fault */ 610 610 #define SRR1_WAKEMASK 0x00380000 /* reason for wakeup */ 611 + #define SRR1_WAKEMASK_P8 0x003c0000 /* reason for wakeup on POWER8 */ 611 612 #define SRR1_WAKESYSERR 0x00300000 /* System error */ 612 613 #define SRR1_WAKEEE 0x00200000 /* External interrupt */ 613 614 #define SRR1_WAKEMT 0x00280000 /* mtctrl */ 614 615 #define SRR1_WAKEHMI 0x00280000 /* Hypervisor maintenance */ 615 616 #define SRR1_WAKEDEC 0x00180000 /* Decrementer interrupt */ 617 + #define SRR1_WAKEDBELL 0x00140000 /* Privileged doorbell on P8 */ 616 618 #define SRR1_WAKETHERM 0x00100000 /* Thermal management interrupt */ 617 619 #define SRR1_WAKERESET 0x00100000 /* System reset */ 620 + #define SRR1_WAKEHDBELL 0x000c0000 /* Hypervisor doorbell on P8 */ 618 621 #define SRR1_WAKESTATE 0x00030000 /* Powersave exit mask [46:47] */ 619 622 #define SRR1_WS_DEEPEST 0x00030000 /* Some resources not maintained, 620 623 * may not be recoverable */
+2
arch/powerpc/kernel/dbell.c
··· 17 17 18 18 #include <asm/dbell.h> 19 19 #include <asm/irq_regs.h> 20 + #include <asm/kvm_ppc.h> 20 21 21 22 #ifdef CONFIG_SMP 22 23 void doorbell_setup_this_cpu(void) ··· 42 41 43 42 may_hard_irq_enable(); 44 43 44 + kvmppc_set_host_ipi(smp_processor_id(), 0); 45 45 __this_cpu_inc(irq_stat.doorbell_irqs); 46 46 47 47 smp_ipi_demux();
+12 -2
arch/powerpc/platforms/powernv/smp.c
··· 33 33 #include <asm/runlatch.h> 34 34 #include <asm/code-patching.h> 35 35 #include <asm/dbell.h> 36 + #include <asm/kvm_ppc.h> 37 + #include <asm/ppc-opcode.h> 36 38 37 39 #include "powernv.h" 38 40 ··· 151 149 static void pnv_smp_cpu_kill_self(void) 152 150 { 153 151 unsigned int cpu; 154 - unsigned long srr1; 152 + unsigned long srr1, wmask; 155 153 u32 idle_states; 156 154 157 155 /* Standard hot unplug procedure */ ··· 162 160 DBG("CPU%d offline\n", cpu); 163 161 generic_set_cpu_dead(cpu); 164 162 smp_wmb(); 163 + 164 + wmask = SRR1_WAKEMASK; 165 + if (cpu_has_feature(CPU_FTR_ARCH_207S)) 166 + wmask = SRR1_WAKEMASK_P8; 165 167 166 168 idle_states = pnv_get_supported_cpuidle_states(); 167 169 /* We don't want to take decrementer interrupts while we are offline, ··· 197 191 * having finished executing in a KVM guest, then srr1 198 192 * contains 0. 199 193 */ 200 - if ((srr1 & SRR1_WAKEMASK) == SRR1_WAKEEE) { 194 + if ((srr1 & wmask) == SRR1_WAKEEE) { 201 195 icp_native_flush_interrupt(); 202 196 local_paca->irq_happened &= PACA_IRQ_HARD_DIS; 203 197 smp_mb(); 198 + } else if ((srr1 & wmask) == SRR1_WAKEHDBELL) { 199 + unsigned long msg = PPC_DBELL_TYPE(PPC_DBELL_SERVER); 200 + asm volatile(PPC_MSGCLR(%0) : : "r" (msg)); 201 + kvmppc_set_host_ipi(cpu, 0); 204 202 } 205 203 206 204 if (cpu_core_split_required())