Merge tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost
[sfrench/cifs-2.6.git] / arch / powerpc / kernel / dbell.c
1 /*
2  * Author: Kumar Gala <galak@kernel.crashing.org>
3  *
4  * Copyright 2009 Freescale Semiconductor Inc.
5  *
6  * This program is free software; you can redistribute  it and/or modify it
7  * under  the terms of  the GNU General  Public License as published by the
8  * Free Software Foundation;  either version 2 of the  License, or (at your
9  * option) any later version.
10  */
11
12 #include <linux/stddef.h>
13 #include <linux/kernel.h>
14 #include <linux/smp.h>
15 #include <linux/threads.h>
16 #include <linux/hardirq.h>
17
18 #include <asm/dbell.h>
19 #include <asm/irq_regs.h>
20 #include <asm/kvm_ppc.h>
21
22 #ifdef CONFIG_SMP
23
24 /*
25  * Doorbells must only be used if CPU_FTR_DBELL is available.
26  * msgsnd is used in HV, and msgsndp is used in !HV.
27  *
28  * These should be used by platform code that is aware of restrictions.
29  * Other arch code should use ->cause_ipi.
30  *
31  * doorbell_global_ipi() sends a dbell to any target CPU.
32  * Must be used only by architectures that address msgsnd target
33  * by PIR/get_hard_smp_processor_id.
34  */
35 void doorbell_global_ipi(int cpu)
36 {
37         u32 tag = get_hard_smp_processor_id(cpu);
38
39         kvmppc_set_host_ipi(cpu, 1);
40         /* Order previous accesses vs. msgsnd, which is treated as a store */
41         ppc_msgsnd_sync();
42         ppc_msgsnd(PPC_DBELL_MSGTYPE, 0, tag);
43 }
44
45 /*
46  * doorbell_core_ipi() sends a dbell to a target CPU in the same core.
47  * Must be used only by architectures that address msgsnd target
48  * by TIR/cpu_thread_in_core.
49  */
50 void doorbell_core_ipi(int cpu)
51 {
52         u32 tag = cpu_thread_in_core(cpu);
53
54         kvmppc_set_host_ipi(cpu, 1);
55         /* Order previous accesses vs. msgsnd, which is treated as a store */
56         ppc_msgsnd_sync();
57         ppc_msgsnd(PPC_DBELL_MSGTYPE, 0, tag);
58 }
59
60 /*
61  * Attempt to cause a core doorbell if destination is on the same core.
62  * Returns 1 on success, 0 on failure.
63  */
64 int doorbell_try_core_ipi(int cpu)
65 {
66         int this_cpu = get_cpu();
67         int ret = 0;
68
69         if (cpumask_test_cpu(cpu, cpu_sibling_mask(this_cpu))) {
70                 doorbell_core_ipi(cpu);
71                 ret = 1;
72         }
73
74         put_cpu();
75
76         return ret;
77 }
78
79 void doorbell_exception(struct pt_regs *regs)
80 {
81         struct pt_regs *old_regs = set_irq_regs(regs);
82
83         irq_enter();
84
85         ppc_msgsync();
86
87         may_hard_irq_enable();
88
89         kvmppc_set_host_ipi(smp_processor_id(), 0);
90         __this_cpu_inc(irq_stat.doorbell_irqs);
91
92         smp_ipi_demux_relaxed(); /* already performed the barrier */
93
94         irq_exit();
95         set_irq_regs(old_regs);
96 }
97 #else /* CONFIG_SMP */
98 void doorbell_exception(struct pt_regs *regs)
99 {
100         printk(KERN_WARNING "Received doorbell on non-smp system\n");
101 }
102 #endif /* CONFIG_SMP */
103