 755563bc79
			
		
	
	
	755563bc79
	
	
	
		
			
			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>
		
			
				
	
	
		
			59 lines
		
	
	
	
		
			1.3 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			59 lines
		
	
	
	
		
			1.3 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Author: Kumar Gala <galak@kernel.crashing.org>
 | |
|  *
 | |
|  * Copyright 2009 Freescale Semiconductor Inc.
 | |
|  *
 | |
|  * This program is free software; you can redistribute  it and/or modify it
 | |
|  * under  the terms of  the GNU General  Public License as published by the
 | |
|  * Free Software Foundation;  either version 2 of the  License, or (at your
 | |
|  * option) any later version.
 | |
|  */
 | |
| 
 | |
| #include <linux/stddef.h>
 | |
| #include <linux/kernel.h>
 | |
| #include <linux/smp.h>
 | |
| #include <linux/threads.h>
 | |
| #include <linux/hardirq.h>
 | |
| 
 | |
| #include <asm/dbell.h>
 | |
| #include <asm/irq_regs.h>
 | |
| #include <asm/kvm_ppc.h>
 | |
| 
 | |
| #ifdef CONFIG_SMP
 | |
| void doorbell_setup_this_cpu(void)
 | |
| {
 | |
| 	unsigned long tag = mfspr(SPRN_DOORBELL_CPUTAG) & PPC_DBELL_TAG_MASK;
 | |
| 
 | |
| 	smp_muxed_ipi_set_data(smp_processor_id(), tag);
 | |
| }
 | |
| 
 | |
| void doorbell_cause_ipi(int cpu, unsigned long data)
 | |
| {
 | |
| 	/* Order previous accesses vs. msgsnd, which is treated as a store */
 | |
| 	mb();
 | |
| 	ppc_msgsnd(PPC_DBELL_MSGTYPE, 0, data);
 | |
| }
 | |
| 
 | |
| void doorbell_exception(struct pt_regs *regs)
 | |
| {
 | |
| 	struct pt_regs *old_regs = set_irq_regs(regs);
 | |
| 
 | |
| 	irq_enter();
 | |
| 
 | |
| 	may_hard_irq_enable();
 | |
| 
 | |
| 	kvmppc_set_host_ipi(smp_processor_id(), 0);
 | |
| 	__this_cpu_inc(irq_stat.doorbell_irqs);
 | |
| 
 | |
| 	smp_ipi_demux();
 | |
| 
 | |
| 	irq_exit();
 | |
| 	set_irq_regs(old_regs);
 | |
| }
 | |
| #else /* CONFIG_SMP */
 | |
| void doorbell_exception(struct pt_regs *regs)
 | |
| {
 | |
| 	printk(KERN_WARNING "Received doorbell on non-smp system\n");
 | |
| }
 | |
| #endif /* CONFIG_SMP */
 | |
| 
 |