Commit | Line | Data |
---|---|---|
620165f9 KG |
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> | |
23d72bfd | 16 | #include <linux/hardirq.h> |
620165f9 KG |
17 | |
18 | #include <asm/dbell.h> | |
0e37d259 | 19 | #include <asm/irq_regs.h> |
755563bc | 20 | #include <asm/kvm_ppc.h> |
620165f9 KG |
21 | |
22 | #ifdef CONFIG_SMP | |
b866cc21 NP |
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) | |
b9f1cd71 | 36 | { |
b866cc21 | 37 | u32 tag = get_hard_smp_processor_id(cpu); |
b9f1cd71 | 38 | |
b866cc21 NP |
39 | kvmppc_set_host_ipi(cpu, 1); |
40 | /* Order previous accesses vs. msgsnd, which is treated as a store */ | |
b87ac021 | 41 | ppc_msgsnd_sync(); |
b866cc21 | 42 | ppc_msgsnd(PPC_DBELL_MSGTYPE, 0, tag); |
b9f1cd71 BH |
43 | } |
44 | ||
b866cc21 NP |
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) | |
620165f9 | 51 | { |
b866cc21 NP |
52 | u32 tag = cpu_thread_in_core(cpu); |
53 | ||
54 | kvmppc_set_host_ipi(cpu, 1); | |
9fb1b36c | 55 | /* Order previous accesses vs. msgsnd, which is treated as a store */ |
b87ac021 | 56 | ppc_msgsnd_sync(); |
b866cc21 NP |
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; | |
620165f9 | 77 | } |
e3145b38 BH |
78 | |
79 | void doorbell_exception(struct pt_regs *regs) | |
80 | { | |
0e37d259 | 81 | struct pt_regs *old_regs = set_irq_regs(regs); |
e3145b38 | 82 | |
23d72bfd | 83 | irq_enter(); |
b9f1cd71 | 84 | |
b87ac021 NP |
85 | ppc_msgsync(); |
86 | ||
7230c564 BH |
87 | may_hard_irq_enable(); |
88 | ||
755563bc | 89 | kvmppc_set_host_ipi(smp_processor_id(), 0); |
69111bac | 90 | __this_cpu_inc(irq_stat.doorbell_irqs); |
a6a058e5 | 91 | |
b87ac021 | 92 | smp_ipi_demux_relaxed(); /* already performed the barrier */ |
e3145b38 | 93 | |
23d72bfd | 94 | irq_exit(); |
0e37d259 | 95 | set_irq_regs(old_regs); |
e3145b38 | 96 | } |
e3145b38 BH |
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 |