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>
60 lines
1.3 KiB
C
60 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 */
|
|
|