]>
Commit | Line | Data |
---|---|---|
2874c5fd | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
620165f9 KG |
2 | /* |
3 | * Author: Kumar Gala <galak@kernel.crashing.org> | |
4 | * | |
5 | * Copyright 2009 Freescale Semiconductor Inc. | |
620165f9 KG |
6 | */ |
7 | ||
8 | #include <linux/stddef.h> | |
9 | #include <linux/kernel.h> | |
10 | #include <linux/smp.h> | |
11 | #include <linux/threads.h> | |
23d72bfd | 12 | #include <linux/hardirq.h> |
620165f9 KG |
13 | |
14 | #include <asm/dbell.h> | |
0e37d259 | 15 | #include <asm/irq_regs.h> |
755563bc | 16 | #include <asm/kvm_ppc.h> |
5b2a1529 | 17 | #include <asm/trace.h> |
620165f9 KG |
18 | |
19 | #ifdef CONFIG_SMP | |
b866cc21 NP |
20 | |
21 | /* | |
22 | * Doorbells must only be used if CPU_FTR_DBELL is available. | |
23 | * msgsnd is used in HV, and msgsndp is used in !HV. | |
24 | * | |
25 | * These should be used by platform code that is aware of restrictions. | |
26 | * Other arch code should use ->cause_ipi. | |
27 | * | |
28 | * doorbell_global_ipi() sends a dbell to any target CPU. | |
29 | * Must be used only by architectures that address msgsnd target | |
30 | * by PIR/get_hard_smp_processor_id. | |
31 | */ | |
32 | void doorbell_global_ipi(int cpu) | |
b9f1cd71 | 33 | { |
b866cc21 | 34 | u32 tag = get_hard_smp_processor_id(cpu); |
b9f1cd71 | 35 | |
b866cc21 NP |
36 | kvmppc_set_host_ipi(cpu, 1); |
37 | /* Order previous accesses vs. msgsnd, which is treated as a store */ | |
b87ac021 | 38 | ppc_msgsnd_sync(); |
b866cc21 | 39 | ppc_msgsnd(PPC_DBELL_MSGTYPE, 0, tag); |
b9f1cd71 BH |
40 | } |
41 | ||
b866cc21 NP |
42 | /* |
43 | * doorbell_core_ipi() sends a dbell to a target CPU in the same core. | |
44 | * Must be used only by architectures that address msgsnd target | |
45 | * by TIR/cpu_thread_in_core. | |
46 | */ | |
47 | void doorbell_core_ipi(int cpu) | |
620165f9 | 48 | { |
b866cc21 NP |
49 | u32 tag = cpu_thread_in_core(cpu); |
50 | ||
51 | kvmppc_set_host_ipi(cpu, 1); | |
9fb1b36c | 52 | /* Order previous accesses vs. msgsnd, which is treated as a store */ |
b87ac021 | 53 | ppc_msgsnd_sync(); |
b866cc21 NP |
54 | ppc_msgsnd(PPC_DBELL_MSGTYPE, 0, tag); |
55 | } | |
56 | ||
57 | /* | |
58 | * Attempt to cause a core doorbell if destination is on the same core. | |
59 | * Returns 1 on success, 0 on failure. | |
60 | */ | |
61 | int doorbell_try_core_ipi(int cpu) | |
62 | { | |
63 | int this_cpu = get_cpu(); | |
64 | int ret = 0; | |
65 | ||
66 | if (cpumask_test_cpu(cpu, cpu_sibling_mask(this_cpu))) { | |
67 | doorbell_core_ipi(cpu); | |
68 | ret = 1; | |
69 | } | |
70 | ||
71 | put_cpu(); | |
72 | ||
73 | return ret; | |
620165f9 | 74 | } |
e3145b38 BH |
75 | |
76 | void doorbell_exception(struct pt_regs *regs) | |
77 | { | |
0e37d259 | 78 | struct pt_regs *old_regs = set_irq_regs(regs); |
e3145b38 | 79 | |
23d72bfd | 80 | irq_enter(); |
5b2a1529 | 81 | trace_doorbell_entry(regs); |
b9f1cd71 | 82 | |
b87ac021 NP |
83 | ppc_msgsync(); |
84 | ||
7230c564 BH |
85 | may_hard_irq_enable(); |
86 | ||
755563bc | 87 | kvmppc_set_host_ipi(smp_processor_id(), 0); |
69111bac | 88 | __this_cpu_inc(irq_stat.doorbell_irqs); |
a6a058e5 | 89 | |
b87ac021 | 90 | smp_ipi_demux_relaxed(); /* already performed the barrier */ |
e3145b38 | 91 | |
5b2a1529 | 92 | trace_doorbell_exit(regs); |
23d72bfd | 93 | irq_exit(); |
0e37d259 | 94 | set_irq_regs(old_regs); |
e3145b38 | 95 | } |
e3145b38 BH |
96 | #else /* CONFIG_SMP */ |
97 | void doorbell_exception(struct pt_regs *regs) | |
98 | { | |
99 | printk(KERN_WARNING "Received doorbell on non-smp system\n"); | |
100 | } | |
101 | #endif /* CONFIG_SMP */ | |
102 |