forked from mirrors/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>
This commit is contained in:
		
							parent
							
								
									06e5801b8c
								
							
						
					
					
						commit
						755563bc79
					
				
					 4 changed files with 20 additions and 2 deletions
				
			
		| 
						 | 
					@ -153,6 +153,7 @@
 | 
				
			||||||
#define PPC_INST_MFSPR_PVR_MASK		0xfc1fffff
 | 
					#define PPC_INST_MFSPR_PVR_MASK		0xfc1fffff
 | 
				
			||||||
#define PPC_INST_MFTMR			0x7c0002dc
 | 
					#define PPC_INST_MFTMR			0x7c0002dc
 | 
				
			||||||
#define PPC_INST_MSGSND			0x7c00019c
 | 
					#define PPC_INST_MSGSND			0x7c00019c
 | 
				
			||||||
 | 
					#define PPC_INST_MSGCLR			0x7c0001dc
 | 
				
			||||||
#define PPC_INST_MSGSNDP		0x7c00011c
 | 
					#define PPC_INST_MSGSNDP		0x7c00011c
 | 
				
			||||||
#define PPC_INST_MTTMR			0x7c0003dc
 | 
					#define PPC_INST_MTTMR			0x7c0003dc
 | 
				
			||||||
#define PPC_INST_NOP			0x60000000
 | 
					#define PPC_INST_NOP			0x60000000
 | 
				
			||||||
| 
						 | 
					@ -309,6 +310,8 @@
 | 
				
			||||||
					___PPC_RB(b) | __PPC_EH(eh))
 | 
										___PPC_RB(b) | __PPC_EH(eh))
 | 
				
			||||||
#define PPC_MSGSND(b)		stringify_in_c(.long PPC_INST_MSGSND | \
 | 
					#define PPC_MSGSND(b)		stringify_in_c(.long PPC_INST_MSGSND | \
 | 
				
			||||||
					___PPC_RB(b))
 | 
										___PPC_RB(b))
 | 
				
			||||||
 | 
					#define PPC_MSGCLR(b)		stringify_in_c(.long PPC_INST_MSGCLR | \
 | 
				
			||||||
 | 
										___PPC_RB(b))
 | 
				
			||||||
#define PPC_MSGSNDP(b)		stringify_in_c(.long PPC_INST_MSGSNDP | \
 | 
					#define PPC_MSGSNDP(b)		stringify_in_c(.long PPC_INST_MSGSNDP | \
 | 
				
			||||||
					___PPC_RB(b))
 | 
										___PPC_RB(b))
 | 
				
			||||||
#define PPC_POPCNTB(a, s)	stringify_in_c(.long PPC_INST_POPCNTB | \
 | 
					#define PPC_POPCNTB(a, s)	stringify_in_c(.long PPC_INST_POPCNTB | \
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -608,13 +608,16 @@
 | 
				
			||||||
#define   SRR1_ISI_N_OR_G	0x10000000 /* ISI: Access is no-exec or G */
 | 
					#define   SRR1_ISI_N_OR_G	0x10000000 /* ISI: Access is no-exec or G */
 | 
				
			||||||
#define   SRR1_ISI_PROT		0x08000000 /* ISI: Other protection fault */
 | 
					#define   SRR1_ISI_PROT		0x08000000 /* ISI: Other protection fault */
 | 
				
			||||||
#define   SRR1_WAKEMASK		0x00380000 /* reason for wakeup */
 | 
					#define   SRR1_WAKEMASK		0x00380000 /* reason for wakeup */
 | 
				
			||||||
 | 
					#define   SRR1_WAKEMASK_P8	0x003c0000 /* reason for wakeup on POWER8 */
 | 
				
			||||||
#define   SRR1_WAKESYSERR	0x00300000 /* System error */
 | 
					#define   SRR1_WAKESYSERR	0x00300000 /* System error */
 | 
				
			||||||
#define   SRR1_WAKEEE		0x00200000 /* External interrupt */
 | 
					#define   SRR1_WAKEEE		0x00200000 /* External interrupt */
 | 
				
			||||||
#define   SRR1_WAKEMT		0x00280000 /* mtctrl */
 | 
					#define   SRR1_WAKEMT		0x00280000 /* mtctrl */
 | 
				
			||||||
#define	  SRR1_WAKEHMI		0x00280000 /* Hypervisor maintenance */
 | 
					#define	  SRR1_WAKEHMI		0x00280000 /* Hypervisor maintenance */
 | 
				
			||||||
#define   SRR1_WAKEDEC		0x00180000 /* Decrementer interrupt */
 | 
					#define   SRR1_WAKEDEC		0x00180000 /* Decrementer interrupt */
 | 
				
			||||||
 | 
					#define   SRR1_WAKEDBELL	0x00140000 /* Privileged doorbell on P8 */
 | 
				
			||||||
#define   SRR1_WAKETHERM	0x00100000 /* Thermal management interrupt */
 | 
					#define   SRR1_WAKETHERM	0x00100000 /* Thermal management interrupt */
 | 
				
			||||||
#define	  SRR1_WAKERESET	0x00100000 /* System reset */
 | 
					#define	  SRR1_WAKERESET	0x00100000 /* System reset */
 | 
				
			||||||
 | 
					#define   SRR1_WAKEHDBELL	0x000c0000 /* Hypervisor doorbell on P8 */
 | 
				
			||||||
#define	  SRR1_WAKESTATE	0x00030000 /* Powersave exit mask [46:47] */
 | 
					#define	  SRR1_WAKESTATE	0x00030000 /* Powersave exit mask [46:47] */
 | 
				
			||||||
#define	  SRR1_WS_DEEPEST	0x00030000 /* Some resources not maintained,
 | 
					#define	  SRR1_WS_DEEPEST	0x00030000 /* Some resources not maintained,
 | 
				
			||||||
					  * may not be recoverable */
 | 
										  * may not be recoverable */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,6 +17,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <asm/dbell.h>
 | 
					#include <asm/dbell.h>
 | 
				
			||||||
#include <asm/irq_regs.h>
 | 
					#include <asm/irq_regs.h>
 | 
				
			||||||
 | 
					#include <asm/kvm_ppc.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_SMP
 | 
					#ifdef CONFIG_SMP
 | 
				
			||||||
void doorbell_setup_this_cpu(void)
 | 
					void doorbell_setup_this_cpu(void)
 | 
				
			||||||
| 
						 | 
					@ -41,6 +42,7 @@ void doorbell_exception(struct pt_regs *regs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	may_hard_irq_enable();
 | 
						may_hard_irq_enable();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						kvmppc_set_host_ipi(smp_processor_id(), 0);
 | 
				
			||||||
	__this_cpu_inc(irq_stat.doorbell_irqs);
 | 
						__this_cpu_inc(irq_stat.doorbell_irqs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	smp_ipi_demux();
 | 
						smp_ipi_demux();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,6 +33,8 @@
 | 
				
			||||||
#include <asm/runlatch.h>
 | 
					#include <asm/runlatch.h>
 | 
				
			||||||
#include <asm/code-patching.h>
 | 
					#include <asm/code-patching.h>
 | 
				
			||||||
#include <asm/dbell.h>
 | 
					#include <asm/dbell.h>
 | 
				
			||||||
 | 
					#include <asm/kvm_ppc.h>
 | 
				
			||||||
 | 
					#include <asm/ppc-opcode.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "powernv.h"
 | 
					#include "powernv.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -149,7 +151,7 @@ static int pnv_smp_cpu_disable(void)
 | 
				
			||||||
static void pnv_smp_cpu_kill_self(void)
 | 
					static void pnv_smp_cpu_kill_self(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned int cpu;
 | 
						unsigned int cpu;
 | 
				
			||||||
	unsigned long srr1;
 | 
						unsigned long srr1, wmask;
 | 
				
			||||||
	u32 idle_states;
 | 
						u32 idle_states;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Standard hot unplug procedure */
 | 
						/* Standard hot unplug procedure */
 | 
				
			||||||
| 
						 | 
					@ -161,6 +163,10 @@ static void pnv_smp_cpu_kill_self(void)
 | 
				
			||||||
	generic_set_cpu_dead(cpu);
 | 
						generic_set_cpu_dead(cpu);
 | 
				
			||||||
	smp_wmb();
 | 
						smp_wmb();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wmask = SRR1_WAKEMASK;
 | 
				
			||||||
 | 
						if (cpu_has_feature(CPU_FTR_ARCH_207S))
 | 
				
			||||||
 | 
							wmask = SRR1_WAKEMASK_P8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	idle_states = pnv_get_supported_cpuidle_states();
 | 
						idle_states = pnv_get_supported_cpuidle_states();
 | 
				
			||||||
	/* We don't want to take decrementer interrupts while we are offline,
 | 
						/* We don't want to take decrementer interrupts while we are offline,
 | 
				
			||||||
	 * so clear LPCR:PECE1. We keep PECE2 enabled.
 | 
						 * so clear LPCR:PECE1. We keep PECE2 enabled.
 | 
				
			||||||
| 
						 | 
					@ -191,10 +197,14 @@ static void pnv_smp_cpu_kill_self(void)
 | 
				
			||||||
		 * having finished executing in a KVM guest, then srr1
 | 
							 * having finished executing in a KVM guest, then srr1
 | 
				
			||||||
		 * contains 0.
 | 
							 * contains 0.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		if ((srr1 & SRR1_WAKEMASK) == SRR1_WAKEEE) {
 | 
							if ((srr1 & wmask) == SRR1_WAKEEE) {
 | 
				
			||||||
			icp_native_flush_interrupt();
 | 
								icp_native_flush_interrupt();
 | 
				
			||||||
			local_paca->irq_happened &= PACA_IRQ_HARD_DIS;
 | 
								local_paca->irq_happened &= PACA_IRQ_HARD_DIS;
 | 
				
			||||||
			smp_mb();
 | 
								smp_mb();
 | 
				
			||||||
 | 
							} else if ((srr1 & wmask) == SRR1_WAKEHDBELL) {
 | 
				
			||||||
 | 
								unsigned long msg = PPC_DBELL_TYPE(PPC_DBELL_SERVER);
 | 
				
			||||||
 | 
								asm volatile(PPC_MSGCLR(%0) : : "r" (msg));
 | 
				
			||||||
 | 
								kvmppc_set_host_ipi(cpu, 0);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (cpu_core_split_required())
 | 
							if (cpu_core_split_required())
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue