]>
Commit | Line | Data |
---|---|---|
2874c5fd | 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ |
620165f9 | 2 | /* |
8a56e1ee | 3 | * Copyright 2009 Freescale Semiconductor, Inc. |
620165f9 | 4 | * |
620165f9 KG |
5 | * provides masks and opcode images for use by code generation, emulation |
6 | * and for instructions that older assemblers might not know about | |
7 | */ | |
8 | #ifndef _ASM_POWERPC_DBELL_H | |
9 | #define _ASM_POWERPC_DBELL_H | |
10 | ||
11 | #include <linux/smp.h> | |
12 | #include <linux/threads.h> | |
13 | ||
1f0ce497 | 14 | #include <asm/cputhreads.h> |
620165f9 | 15 | #include <asm/ppc-opcode.h> |
2c86cd18 | 16 | #include <asm/feature-fixups.h> |
1f0ce497 | 17 | #include <asm/kvm_ppc.h> |
620165f9 KG |
18 | |
19 | #define PPC_DBELL_MSG_BRDCAST (0x04000000) | |
dc28518f | 20 | #define PPC_DBELL_TYPE(x) (((x) & 0xf) << (63-36)) |
4ab96919 | 21 | #define PPC_DBELL_TYPE_MASK PPC_DBELL_TYPE(0xf) |
d30f6e48 | 22 | #define PPC_DBELL_LPID(x) ((x) << (63 - 49)) |
4ab96919 | 23 | #define PPC_DBELL_PIR_MASK 0x3fff |
620165f9 KG |
24 | enum ppc_dbell { |
25 | PPC_DBELL = 0, /* doorbell */ | |
26 | PPC_DBELL_CRIT = 1, /* critical doorbell */ | |
27 | PPC_G_DBELL = 2, /* guest doorbell */ | |
28 | PPC_G_DBELL_CRIT = 3, /* guest critical doorbell */ | |
29 | PPC_G_DBELL_MC = 4, /* guest mcheck doorbell */ | |
42d02b81 | 30 | PPC_DBELL_SERVER = 5, /* doorbell on server */ |
620165f9 KG |
31 | }; |
32 | ||
42d02b81 IM |
33 | #ifdef CONFIG_PPC_BOOK3S |
34 | ||
35 | #define PPC_DBELL_MSGTYPE PPC_DBELL_SERVER | |
42d02b81 | 36 | |
919ca868 IM |
37 | static inline void _ppc_msgsnd(u32 msg) |
38 | { | |
a5adf282 NP |
39 | __asm__ __volatile__ (ASM_FTR_IFSET(PPC_MSGSND(%1), PPC_MSGSNDP(%1), %0) |
40 | : : "i" (CPU_FTR_HVMODE), "r" (msg)); | |
919ca868 IM |
41 | } |
42 | ||
b87ac021 NP |
43 | /* sync before sending message */ |
44 | static inline void ppc_msgsnd_sync(void) | |
45 | { | |
46 | __asm__ __volatile__ ("sync" : : : "memory"); | |
47 | } | |
48 | ||
49 | /* sync after taking message interrupt */ | |
50 | static inline void ppc_msgsync(void) | |
51 | { | |
6b3edefe NP |
52 | /* sync is not required when taking messages from the same core */ |
53 | __asm__ __volatile__ (ASM_FTR_IFSET(PPC_MSGSYNC " ; lwsync", "", %0) | |
54 | : : "i" (CPU_FTR_HVMODE|CPU_FTR_ARCH_300)); | |
b87ac021 NP |
55 | } |
56 | ||
a9af97aa NP |
57 | static inline void _ppc_msgclr(u32 msg) |
58 | { | |
59 | __asm__ __volatile__ (ASM_FTR_IFSET(PPC_MSGCLR(%1), PPC_MSGCLRP(%1), %0) | |
60 | : : "i" (CPU_FTR_HVMODE), "r" (msg)); | |
61 | } | |
62 | ||
63 | static inline void ppc_msgclr(enum ppc_dbell type) | |
64 | { | |
65 | u32 msg = PPC_DBELL_TYPE(type); | |
66 | ||
67 | _ppc_msgclr(msg); | |
68 | } | |
69 | ||
42d02b81 IM |
70 | #else /* CONFIG_PPC_BOOK3S */ |
71 | ||
72 | #define PPC_DBELL_MSGTYPE PPC_DBELL | |
42d02b81 | 73 | |
919ca868 IM |
74 | static inline void _ppc_msgsnd(u32 msg) |
75 | { | |
76 | __asm__ __volatile__ (PPC_MSGSND(%0) : : "r" (msg)); | |
77 | } | |
78 | ||
b87ac021 NP |
79 | /* sync before sending message */ |
80 | static inline void ppc_msgsnd_sync(void) | |
81 | { | |
82 | __asm__ __volatile__ ("sync" : : : "memory"); | |
83 | } | |
84 | ||
85 | /* sync after taking message interrupt */ | |
86 | static inline void ppc_msgsync(void) | |
87 | { | |
88 | } | |
89 | ||
42d02b81 IM |
90 | #endif /* CONFIG_PPC_BOOK3S */ |
91 | ||
b9f1cd71 | 92 | extern void doorbell_exception(struct pt_regs *regs); |
620165f9 KG |
93 | |
94 | static inline void ppc_msgsnd(enum ppc_dbell type, u32 flags, u32 tag) | |
95 | { | |
96 | u32 msg = PPC_DBELL_TYPE(type) | (flags & PPC_DBELL_MSG_BRDCAST) | | |
97 | (tag & 0x07ffffff); | |
98 | ||
919ca868 | 99 | _ppc_msgsnd(msg); |
620165f9 KG |
100 | } |
101 | ||
1f0ce497 NP |
102 | #ifdef CONFIG_SMP |
103 | ||
104 | /* | |
105 | * Doorbells must only be used if CPU_FTR_DBELL is available. | |
106 | * msgsnd is used in HV, and msgsndp is used in !HV. | |
107 | * | |
108 | * These should be used by platform code that is aware of restrictions. | |
109 | * Other arch code should use ->cause_ipi. | |
110 | * | |
111 | * doorbell_global_ipi() sends a dbell to any target CPU. | |
112 | * Must be used only by architectures that address msgsnd target | |
113 | * by PIR/get_hard_smp_processor_id. | |
114 | */ | |
115 | static inline void doorbell_global_ipi(int cpu) | |
116 | { | |
117 | u32 tag = get_hard_smp_processor_id(cpu); | |
118 | ||
119 | kvmppc_set_host_ipi(cpu); | |
120 | /* Order previous accesses vs. msgsnd, which is treated as a store */ | |
121 | ppc_msgsnd_sync(); | |
122 | ppc_msgsnd(PPC_DBELL_MSGTYPE, 0, tag); | |
123 | } | |
124 | ||
125 | /* | |
126 | * doorbell_core_ipi() sends a dbell to a target CPU in the same core. | |
127 | * Must be used only by architectures that address msgsnd target | |
128 | * by TIR/cpu_thread_in_core. | |
129 | */ | |
130 | static inline void doorbell_core_ipi(int cpu) | |
131 | { | |
132 | u32 tag = cpu_thread_in_core(cpu); | |
133 | ||
134 | kvmppc_set_host_ipi(cpu); | |
135 | /* Order previous accesses vs. msgsnd, which is treated as a store */ | |
136 | ppc_msgsnd_sync(); | |
137 | ppc_msgsnd(PPC_DBELL_MSGTYPE, 0, tag); | |
138 | } | |
139 | ||
140 | /* | |
141 | * Attempt to cause a core doorbell if destination is on the same core. | |
142 | * Returns 1 on success, 0 on failure. | |
143 | */ | |
144 | static inline int doorbell_try_core_ipi(int cpu) | |
145 | { | |
146 | int this_cpu = get_cpu(); | |
147 | int ret = 0; | |
148 | ||
149 | if (cpumask_test_cpu(cpu, cpu_sibling_mask(this_cpu))) { | |
150 | doorbell_core_ipi(cpu); | |
151 | ret = 1; | |
152 | } | |
153 | ||
154 | put_cpu(); | |
155 | ||
156 | return ret; | |
157 | } | |
158 | ||
159 | #endif /* CONFIG_SMP */ | |
160 | ||
620165f9 | 161 | #endif /* _ASM_POWERPC_DBELL_H */ |