.. | .. |
---|
| 1 | +/* SPDX-License-Identifier: GPL-2.0-only */ |
---|
1 | 2 | /* |
---|
2 | 3 | * Based on arch/arm/include/asm/cmpxchg.h |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (C) 2012 ARM Ltd. |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or modify |
---|
7 | | - * it under the terms of the GNU General Public License version 2 as |
---|
8 | | - * published by the Free Software Foundation. |
---|
9 | | - * |
---|
10 | | - * This program is distributed in the hope that it will be useful, |
---|
11 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
12 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
13 | | - * GNU General Public License for more details. |
---|
14 | | - * |
---|
15 | | - * You should have received a copy of the GNU General Public License |
---|
16 | | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
---|
17 | 6 | */ |
---|
18 | 7 | #ifndef __ASM_CMPXCHG_H |
---|
19 | 8 | #define __ASM_CMPXCHG_H |
---|
.. | .. |
---|
21 | 10 | #include <linux/build_bug.h> |
---|
22 | 11 | #include <linux/compiler.h> |
---|
23 | 12 | |
---|
24 | | -#include <asm/atomic.h> |
---|
25 | 13 | #include <asm/barrier.h> |
---|
26 | 14 | #include <asm/lse.h> |
---|
27 | 15 | |
---|
.. | .. |
---|
30 | 18 | * barrier case is generated as release+dmb for the former and |
---|
31 | 19 | * acquire+release for the latter. |
---|
32 | 20 | */ |
---|
33 | | -#define __XCHG_CASE(w, sz, name, mb, nop_lse, acq, acq_lse, rel, cl) \ |
---|
34 | | -static inline unsigned long __xchg_case_##name(unsigned long x, \ |
---|
35 | | - volatile void *ptr) \ |
---|
36 | | -{ \ |
---|
37 | | - unsigned long ret, tmp; \ |
---|
38 | | - \ |
---|
39 | | - asm volatile(ARM64_LSE_ATOMIC_INSN( \ |
---|
40 | | - /* LL/SC */ \ |
---|
41 | | - " prfm pstl1strm, %2\n" \ |
---|
42 | | - "1: ld" #acq "xr" #sz "\t%" #w "0, %2\n" \ |
---|
43 | | - " st" #rel "xr" #sz "\t%w1, %" #w "3, %2\n" \ |
---|
44 | | - " cbnz %w1, 1b\n" \ |
---|
45 | | - " " #mb, \ |
---|
46 | | - /* LSE atomics */ \ |
---|
47 | | - " swp" #acq_lse #rel #sz "\t%" #w "3, %" #w "0, %2\n" \ |
---|
48 | | - __nops(3) \ |
---|
49 | | - " " #nop_lse) \ |
---|
50 | | - : "=&r" (ret), "=&r" (tmp), "+Q" (*(unsigned long *)ptr) \ |
---|
51 | | - : "r" (x) \ |
---|
52 | | - : cl); \ |
---|
53 | | - \ |
---|
54 | | - return ret; \ |
---|
| 21 | +#define __XCHG_CASE(w, sfx, name, sz, mb, nop_lse, acq, acq_lse, rel, cl) \ |
---|
| 22 | +static inline u##sz __xchg_case_##name##sz(u##sz x, volatile void *ptr) \ |
---|
| 23 | +{ \ |
---|
| 24 | + u##sz ret; \ |
---|
| 25 | + unsigned long tmp; \ |
---|
| 26 | + \ |
---|
| 27 | + asm volatile(ARM64_LSE_ATOMIC_INSN( \ |
---|
| 28 | + /* LL/SC */ \ |
---|
| 29 | + " prfm pstl1strm, %2\n" \ |
---|
| 30 | + "1: ld" #acq "xr" #sfx "\t%" #w "0, %2\n" \ |
---|
| 31 | + " st" #rel "xr" #sfx "\t%w1, %" #w "3, %2\n" \ |
---|
| 32 | + " cbnz %w1, 1b\n" \ |
---|
| 33 | + " " #mb, \ |
---|
| 34 | + /* LSE atomics */ \ |
---|
| 35 | + " swp" #acq_lse #rel #sfx "\t%" #w "3, %" #w "0, %2\n" \ |
---|
| 36 | + __nops(3) \ |
---|
| 37 | + " " #nop_lse) \ |
---|
| 38 | + : "=&r" (ret), "=&r" (tmp), "+Q" (*(u##sz *)ptr) \ |
---|
| 39 | + : "r" (x) \ |
---|
| 40 | + : cl); \ |
---|
| 41 | + \ |
---|
| 42 | + return ret; \ |
---|
55 | 43 | } |
---|
56 | 44 | |
---|
57 | | -__XCHG_CASE(w, b, 1, , , , , , ) |
---|
58 | | -__XCHG_CASE(w, h, 2, , , , , , ) |
---|
59 | | -__XCHG_CASE(w, , 4, , , , , , ) |
---|
60 | | -__XCHG_CASE( , , 8, , , , , , ) |
---|
61 | | -__XCHG_CASE(w, b, acq_1, , , a, a, , "memory") |
---|
62 | | -__XCHG_CASE(w, h, acq_2, , , a, a, , "memory") |
---|
63 | | -__XCHG_CASE(w, , acq_4, , , a, a, , "memory") |
---|
64 | | -__XCHG_CASE( , , acq_8, , , a, a, , "memory") |
---|
65 | | -__XCHG_CASE(w, b, rel_1, , , , , l, "memory") |
---|
66 | | -__XCHG_CASE(w, h, rel_2, , , , , l, "memory") |
---|
67 | | -__XCHG_CASE(w, , rel_4, , , , , l, "memory") |
---|
68 | | -__XCHG_CASE( , , rel_8, , , , , l, "memory") |
---|
69 | | -__XCHG_CASE(w, b, mb_1, dmb ish, nop, , a, l, "memory") |
---|
70 | | -__XCHG_CASE(w, h, mb_2, dmb ish, nop, , a, l, "memory") |
---|
71 | | -__XCHG_CASE(w, , mb_4, dmb ish, nop, , a, l, "memory") |
---|
72 | | -__XCHG_CASE( , , mb_8, dmb ish, nop, , a, l, "memory") |
---|
| 45 | +__XCHG_CASE(w, b, , 8, , , , , , ) |
---|
| 46 | +__XCHG_CASE(w, h, , 16, , , , , , ) |
---|
| 47 | +__XCHG_CASE(w, , , 32, , , , , , ) |
---|
| 48 | +__XCHG_CASE( , , , 64, , , , , , ) |
---|
| 49 | +__XCHG_CASE(w, b, acq_, 8, , , a, a, , "memory") |
---|
| 50 | +__XCHG_CASE(w, h, acq_, 16, , , a, a, , "memory") |
---|
| 51 | +__XCHG_CASE(w, , acq_, 32, , , a, a, , "memory") |
---|
| 52 | +__XCHG_CASE( , , acq_, 64, , , a, a, , "memory") |
---|
| 53 | +__XCHG_CASE(w, b, rel_, 8, , , , , l, "memory") |
---|
| 54 | +__XCHG_CASE(w, h, rel_, 16, , , , , l, "memory") |
---|
| 55 | +__XCHG_CASE(w, , rel_, 32, , , , , l, "memory") |
---|
| 56 | +__XCHG_CASE( , , rel_, 64, , , , , l, "memory") |
---|
| 57 | +__XCHG_CASE(w, b, mb_, 8, dmb ish, nop, , a, l, "memory") |
---|
| 58 | +__XCHG_CASE(w, h, mb_, 16, dmb ish, nop, , a, l, "memory") |
---|
| 59 | +__XCHG_CASE(w, , mb_, 32, dmb ish, nop, , a, l, "memory") |
---|
| 60 | +__XCHG_CASE( , , mb_, 64, dmb ish, nop, , a, l, "memory") |
---|
73 | 61 | |
---|
74 | 62 | #undef __XCHG_CASE |
---|
75 | 63 | |
---|
.. | .. |
---|
80 | 68 | { \ |
---|
81 | 69 | switch (size) { \ |
---|
82 | 70 | case 1: \ |
---|
83 | | - return __xchg_case##sfx##_1(x, ptr); \ |
---|
84 | | - case 2: \ |
---|
85 | | - return __xchg_case##sfx##_2(x, ptr); \ |
---|
86 | | - case 4: \ |
---|
87 | | - return __xchg_case##sfx##_4(x, ptr); \ |
---|
88 | | - case 8: \ |
---|
89 | 71 | return __xchg_case##sfx##_8(x, ptr); \ |
---|
| 72 | + case 2: \ |
---|
| 73 | + return __xchg_case##sfx##_16(x, ptr); \ |
---|
| 74 | + case 4: \ |
---|
| 75 | + return __xchg_case##sfx##_32(x, ptr); \ |
---|
| 76 | + case 8: \ |
---|
| 77 | + return __xchg_case##sfx##_64(x, ptr); \ |
---|
90 | 78 | default: \ |
---|
91 | 79 | BUILD_BUG(); \ |
---|
92 | 80 | } \ |
---|
.. | .. |
---|
110 | 98 | }) |
---|
111 | 99 | |
---|
112 | 100 | /* xchg */ |
---|
113 | | -#define xchg_relaxed(...) __xchg_wrapper( , __VA_ARGS__) |
---|
114 | | -#define xchg_acquire(...) __xchg_wrapper(_acq, __VA_ARGS__) |
---|
115 | | -#define xchg_release(...) __xchg_wrapper(_rel, __VA_ARGS__) |
---|
116 | | -#define xchg(...) __xchg_wrapper( _mb, __VA_ARGS__) |
---|
| 101 | +#define arch_xchg_relaxed(...) __xchg_wrapper( , __VA_ARGS__) |
---|
| 102 | +#define arch_xchg_acquire(...) __xchg_wrapper(_acq, __VA_ARGS__) |
---|
| 103 | +#define arch_xchg_release(...) __xchg_wrapper(_rel, __VA_ARGS__) |
---|
| 104 | +#define arch_xchg(...) __xchg_wrapper( _mb, __VA_ARGS__) |
---|
| 105 | + |
---|
| 106 | +#define __CMPXCHG_CASE(name, sz) \ |
---|
| 107 | +static inline u##sz __cmpxchg_case_##name##sz(volatile void *ptr, \ |
---|
| 108 | + u##sz old, \ |
---|
| 109 | + u##sz new) \ |
---|
| 110 | +{ \ |
---|
| 111 | + return __lse_ll_sc_body(_cmpxchg_case_##name##sz, \ |
---|
| 112 | + ptr, old, new); \ |
---|
| 113 | +} |
---|
| 114 | + |
---|
| 115 | +__CMPXCHG_CASE( , 8) |
---|
| 116 | +__CMPXCHG_CASE( , 16) |
---|
| 117 | +__CMPXCHG_CASE( , 32) |
---|
| 118 | +__CMPXCHG_CASE( , 64) |
---|
| 119 | +__CMPXCHG_CASE(acq_, 8) |
---|
| 120 | +__CMPXCHG_CASE(acq_, 16) |
---|
| 121 | +__CMPXCHG_CASE(acq_, 32) |
---|
| 122 | +__CMPXCHG_CASE(acq_, 64) |
---|
| 123 | +__CMPXCHG_CASE(rel_, 8) |
---|
| 124 | +__CMPXCHG_CASE(rel_, 16) |
---|
| 125 | +__CMPXCHG_CASE(rel_, 32) |
---|
| 126 | +__CMPXCHG_CASE(rel_, 64) |
---|
| 127 | +__CMPXCHG_CASE(mb_, 8) |
---|
| 128 | +__CMPXCHG_CASE(mb_, 16) |
---|
| 129 | +__CMPXCHG_CASE(mb_, 32) |
---|
| 130 | +__CMPXCHG_CASE(mb_, 64) |
---|
| 131 | + |
---|
| 132 | +#undef __CMPXCHG_CASE |
---|
| 133 | + |
---|
| 134 | +#define __CMPXCHG_DBL(name) \ |
---|
| 135 | +static inline long __cmpxchg_double##name(unsigned long old1, \ |
---|
| 136 | + unsigned long old2, \ |
---|
| 137 | + unsigned long new1, \ |
---|
| 138 | + unsigned long new2, \ |
---|
| 139 | + volatile void *ptr) \ |
---|
| 140 | +{ \ |
---|
| 141 | + return __lse_ll_sc_body(_cmpxchg_double##name, \ |
---|
| 142 | + old1, old2, new1, new2, ptr); \ |
---|
| 143 | +} |
---|
| 144 | + |
---|
| 145 | +__CMPXCHG_DBL( ) |
---|
| 146 | +__CMPXCHG_DBL(_mb) |
---|
| 147 | + |
---|
| 148 | +#undef __CMPXCHG_DBL |
---|
117 | 149 | |
---|
118 | 150 | #define __CMPXCHG_GEN(sfx) \ |
---|
119 | 151 | static __always_inline unsigned long __cmpxchg##sfx(volatile void *ptr, \ |
---|
.. | .. |
---|
123 | 155 | { \ |
---|
124 | 156 | switch (size) { \ |
---|
125 | 157 | case 1: \ |
---|
126 | | - return __cmpxchg_case##sfx##_1(ptr, (u8)old, new); \ |
---|
127 | | - case 2: \ |
---|
128 | | - return __cmpxchg_case##sfx##_2(ptr, (u16)old, new); \ |
---|
129 | | - case 4: \ |
---|
130 | | - return __cmpxchg_case##sfx##_4(ptr, old, new); \ |
---|
131 | | - case 8: \ |
---|
132 | 158 | return __cmpxchg_case##sfx##_8(ptr, old, new); \ |
---|
| 159 | + case 2: \ |
---|
| 160 | + return __cmpxchg_case##sfx##_16(ptr, old, new); \ |
---|
| 161 | + case 4: \ |
---|
| 162 | + return __cmpxchg_case##sfx##_32(ptr, old, new); \ |
---|
| 163 | + case 8: \ |
---|
| 164 | + return __cmpxchg_case##sfx##_64(ptr, old, new); \ |
---|
133 | 165 | default: \ |
---|
134 | 166 | BUILD_BUG(); \ |
---|
135 | 167 | } \ |
---|
.. | .. |
---|
154 | 186 | }) |
---|
155 | 187 | |
---|
156 | 188 | /* cmpxchg */ |
---|
157 | | -#define cmpxchg_relaxed(...) __cmpxchg_wrapper( , __VA_ARGS__) |
---|
158 | | -#define cmpxchg_acquire(...) __cmpxchg_wrapper(_acq, __VA_ARGS__) |
---|
159 | | -#define cmpxchg_release(...) __cmpxchg_wrapper(_rel, __VA_ARGS__) |
---|
160 | | -#define cmpxchg(...) __cmpxchg_wrapper( _mb, __VA_ARGS__) |
---|
161 | | -#define cmpxchg_local cmpxchg_relaxed |
---|
| 189 | +#define arch_cmpxchg_relaxed(...) __cmpxchg_wrapper( , __VA_ARGS__) |
---|
| 190 | +#define arch_cmpxchg_acquire(...) __cmpxchg_wrapper(_acq, __VA_ARGS__) |
---|
| 191 | +#define arch_cmpxchg_release(...) __cmpxchg_wrapper(_rel, __VA_ARGS__) |
---|
| 192 | +#define arch_cmpxchg(...) __cmpxchg_wrapper( _mb, __VA_ARGS__) |
---|
| 193 | +#define arch_cmpxchg_local arch_cmpxchg_relaxed |
---|
162 | 194 | |
---|
163 | 195 | /* cmpxchg64 */ |
---|
164 | | -#define cmpxchg64_relaxed cmpxchg_relaxed |
---|
165 | | -#define cmpxchg64_acquire cmpxchg_acquire |
---|
166 | | -#define cmpxchg64_release cmpxchg_release |
---|
167 | | -#define cmpxchg64 cmpxchg |
---|
168 | | -#define cmpxchg64_local cmpxchg_local |
---|
| 196 | +#define arch_cmpxchg64_relaxed arch_cmpxchg_relaxed |
---|
| 197 | +#define arch_cmpxchg64_acquire arch_cmpxchg_acquire |
---|
| 198 | +#define arch_cmpxchg64_release arch_cmpxchg_release |
---|
| 199 | +#define arch_cmpxchg64 arch_cmpxchg |
---|
| 200 | +#define arch_cmpxchg64_local arch_cmpxchg_local |
---|
169 | 201 | |
---|
170 | 202 | /* cmpxchg_double */ |
---|
171 | 203 | #define system_has_cmpxchg_double() 1 |
---|
.. | .. |
---|
177 | 209 | VM_BUG_ON((unsigned long *)(ptr2) - (unsigned long *)(ptr1) != 1); \ |
---|
178 | 210 | }) |
---|
179 | 211 | |
---|
180 | | -#define cmpxchg_double(ptr1, ptr2, o1, o2, n1, n2) \ |
---|
181 | | -({\ |
---|
182 | | - int __ret;\ |
---|
183 | | - __cmpxchg_double_check(ptr1, ptr2); \ |
---|
184 | | - __ret = !__cmpxchg_double_mb((unsigned long)(o1), (unsigned long)(o2), \ |
---|
185 | | - (unsigned long)(n1), (unsigned long)(n2), \ |
---|
186 | | - ptr1); \ |
---|
187 | | - __ret; \ |
---|
| 212 | +#define arch_cmpxchg_double(ptr1, ptr2, o1, o2, n1, n2) \ |
---|
| 213 | +({ \ |
---|
| 214 | + int __ret; \ |
---|
| 215 | + __cmpxchg_double_check(ptr1, ptr2); \ |
---|
| 216 | + __ret = !__cmpxchg_double_mb((unsigned long)(o1), (unsigned long)(o2), \ |
---|
| 217 | + (unsigned long)(n1), (unsigned long)(n2), \ |
---|
| 218 | + ptr1); \ |
---|
| 219 | + __ret; \ |
---|
188 | 220 | }) |
---|
189 | 221 | |
---|
190 | | -#define cmpxchg_double_local(ptr1, ptr2, o1, o2, n1, n2) \ |
---|
191 | | -({\ |
---|
192 | | - int __ret;\ |
---|
193 | | - __cmpxchg_double_check(ptr1, ptr2); \ |
---|
194 | | - __ret = !__cmpxchg_double((unsigned long)(o1), (unsigned long)(o2), \ |
---|
195 | | - (unsigned long)(n1), (unsigned long)(n2), \ |
---|
196 | | - ptr1); \ |
---|
197 | | - __ret; \ |
---|
| 222 | +#define arch_cmpxchg_double_local(ptr1, ptr2, o1, o2, n1, n2) \ |
---|
| 223 | +({ \ |
---|
| 224 | + int __ret; \ |
---|
| 225 | + __cmpxchg_double_check(ptr1, ptr2); \ |
---|
| 226 | + __ret = !__cmpxchg_double((unsigned long)(o1), (unsigned long)(o2), \ |
---|
| 227 | + (unsigned long)(n1), (unsigned long)(n2), \ |
---|
| 228 | + ptr1); \ |
---|
| 229 | + __ret; \ |
---|
198 | 230 | }) |
---|
199 | 231 | |
---|
200 | | -#define __CMPWAIT_CASE(w, sz, name) \ |
---|
201 | | -static inline void __cmpwait_case_##name(volatile void *ptr, \ |
---|
202 | | - unsigned long val) \ |
---|
| 232 | +#define __CMPWAIT_CASE(w, sfx, sz) \ |
---|
| 233 | +static inline void __cmpwait_case_##sz(volatile void *ptr, \ |
---|
| 234 | + unsigned long val) \ |
---|
203 | 235 | { \ |
---|
204 | 236 | unsigned long tmp; \ |
---|
205 | 237 | \ |
---|
206 | 238 | asm volatile( \ |
---|
207 | 239 | " sevl\n" \ |
---|
208 | 240 | " wfe\n" \ |
---|
209 | | - " ldxr" #sz "\t%" #w "[tmp], %[v]\n" \ |
---|
| 241 | + " ldxr" #sfx "\t%" #w "[tmp], %[v]\n" \ |
---|
210 | 242 | " eor %" #w "[tmp], %" #w "[tmp], %" #w "[val]\n" \ |
---|
211 | 243 | " cbnz %" #w "[tmp], 1f\n" \ |
---|
212 | 244 | " wfe\n" \ |
---|
.. | .. |
---|
215 | 247 | : [val] "r" (val)); \ |
---|
216 | 248 | } |
---|
217 | 249 | |
---|
218 | | -__CMPWAIT_CASE(w, b, 1); |
---|
219 | | -__CMPWAIT_CASE(w, h, 2); |
---|
220 | | -__CMPWAIT_CASE(w, , 4); |
---|
221 | | -__CMPWAIT_CASE( , , 8); |
---|
| 250 | +__CMPWAIT_CASE(w, b, 8); |
---|
| 251 | +__CMPWAIT_CASE(w, h, 16); |
---|
| 252 | +__CMPWAIT_CASE(w, , 32); |
---|
| 253 | +__CMPWAIT_CASE( , , 64); |
---|
222 | 254 | |
---|
223 | 255 | #undef __CMPWAIT_CASE |
---|
224 | 256 | |
---|
.. | .. |
---|
229 | 261 | { \ |
---|
230 | 262 | switch (size) { \ |
---|
231 | 263 | case 1: \ |
---|
232 | | - return __cmpwait_case##sfx##_1(ptr, (u8)val); \ |
---|
| 264 | + return __cmpwait_case##sfx##_8(ptr, (u8)val); \ |
---|
233 | 265 | case 2: \ |
---|
234 | | - return __cmpwait_case##sfx##_2(ptr, (u16)val); \ |
---|
| 266 | + return __cmpwait_case##sfx##_16(ptr, (u16)val); \ |
---|
235 | 267 | case 4: \ |
---|
236 | | - return __cmpwait_case##sfx##_4(ptr, val); \ |
---|
| 268 | + return __cmpwait_case##sfx##_32(ptr, val); \ |
---|
237 | 269 | case 8: \ |
---|
238 | | - return __cmpwait_case##sfx##_8(ptr, val); \ |
---|
| 270 | + return __cmpwait_case##sfx##_64(ptr, val); \ |
---|
239 | 271 | default: \ |
---|
240 | 272 | BUILD_BUG(); \ |
---|
241 | 273 | } \ |
---|