1a9643ea8Slogwang /*-
2a9643ea8Slogwang * Copyright (c) 2013 Andrew Turner <[email protected]>
3a9643ea8Slogwang * All rights reserved.
4a9643ea8Slogwang *
5a9643ea8Slogwang * Redistribution and use in source and binary forms, with or without
6a9643ea8Slogwang * modification, are permitted provided that the following conditions
7a9643ea8Slogwang * are met:
8a9643ea8Slogwang * 1. Redistributions of source code must retain the above copyright
9a9643ea8Slogwang * notice, this list of conditions and the following disclaimer.
10a9643ea8Slogwang * 2. Redistributions in binary form must reproduce the above copyright
11a9643ea8Slogwang * notice, this list of conditions and the following disclaimer in the
12a9643ea8Slogwang * documentation and/or other materials provided with the distribution.
13a9643ea8Slogwang *
14a9643ea8Slogwang * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15a9643ea8Slogwang * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16a9643ea8Slogwang * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17a9643ea8Slogwang * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18a9643ea8Slogwang * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19a9643ea8Slogwang * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20a9643ea8Slogwang * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21a9643ea8Slogwang * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22a9643ea8Slogwang * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23a9643ea8Slogwang * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24a9643ea8Slogwang * SUCH DAMAGE.
25a9643ea8Slogwang *
26a9643ea8Slogwang * $FreeBSD$
27a9643ea8Slogwang */
28a9643ea8Slogwang
29a9643ea8Slogwang #ifndef _MACHINE_ATOMIC_H_
30a9643ea8Slogwang #define _MACHINE_ATOMIC_H_
31a9643ea8Slogwang
32a9643ea8Slogwang #define isb() __asm __volatile("isb" : : : "memory")
33a9643ea8Slogwang
34a9643ea8Slogwang /*
35a9643ea8Slogwang * Options for DMB and DSB:
36a9643ea8Slogwang * oshld Outer Shareable, load
37a9643ea8Slogwang * oshst Outer Shareable, store
38a9643ea8Slogwang * osh Outer Shareable, all
39a9643ea8Slogwang * nshld Non-shareable, load
40a9643ea8Slogwang * nshst Non-shareable, store
41a9643ea8Slogwang * nsh Non-shareable, all
42a9643ea8Slogwang * ishld Inner Shareable, load
43a9643ea8Slogwang * ishst Inner Shareable, store
44a9643ea8Slogwang * ish Inner Shareable, all
45a9643ea8Slogwang * ld Full system, load
46a9643ea8Slogwang * st Full system, store
47a9643ea8Slogwang * sy Full system, all
48a9643ea8Slogwang */
49a9643ea8Slogwang #define dsb(opt) __asm __volatile("dsb " __STRING(opt) : : : "memory")
50a9643ea8Slogwang #define dmb(opt) __asm __volatile("dmb " __STRING(opt) : : : "memory")
51a9643ea8Slogwang
52a9643ea8Slogwang #define mb() dmb(sy) /* Full system memory barrier all */
53a9643ea8Slogwang #define wmb() dmb(st) /* Full system memory barrier store */
54a9643ea8Slogwang #define rmb() dmb(ld) /* Full system memory barrier load */
55a9643ea8Slogwang
56*22ce4affSfengbojiang #if defined(KCSAN) && !defined(KCSAN_RUNTIME)
57*22ce4affSfengbojiang #include <sys/_cscan_atomic.h>
58*22ce4affSfengbojiang #else
59*22ce4affSfengbojiang
60*22ce4affSfengbojiang #include <sys/atomic_common.h>
61*22ce4affSfengbojiang
62*22ce4affSfengbojiang #ifdef _KERNEL
63*22ce4affSfengbojiang extern bool lse_supported;
64*22ce4affSfengbojiang
65*22ce4affSfengbojiang #ifdef LSE_ATOMICS
66*22ce4affSfengbojiang #define _ATOMIC_LSE_SUPPORTED 1
67*22ce4affSfengbojiang #else
68*22ce4affSfengbojiang #define _ATOMIC_LSE_SUPPORTED lse_supported
69*22ce4affSfengbojiang #endif
70*22ce4affSfengbojiang #else
71*22ce4affSfengbojiang #define _ATOMIC_LSE_SUPPORTED 0
72*22ce4affSfengbojiang #endif
73*22ce4affSfengbojiang
74*22ce4affSfengbojiang #define _ATOMIC_OP_PROTO(t, op, bar, flav) \
75a9643ea8Slogwang static __inline void \
76*22ce4affSfengbojiang atomic_##op##_##bar##t##flav(volatile uint##t##_t *p, uint##t##_t val)
77*22ce4affSfengbojiang
78*22ce4affSfengbojiang #define _ATOMIC_OP_IMPL(t, w, s, op, llsc_asm_op, lse_asm_op, pre, bar, a, l) \
79*22ce4affSfengbojiang _ATOMIC_OP_PROTO(t, op, bar, _llsc) \
80a9643ea8Slogwang { \
81*22ce4affSfengbojiang uint##t##_t tmp; \
82a9643ea8Slogwang int res; \
83a9643ea8Slogwang \
84*22ce4affSfengbojiang pre; \
85a9643ea8Slogwang __asm __volatile( \
86*22ce4affSfengbojiang "1: ld"#a"xr"#s" %"#w"0, [%2]\n" \
87*22ce4affSfengbojiang " "#llsc_asm_op" %"#w"0, %"#w"0, %"#w"3\n" \
88*22ce4affSfengbojiang " st"#l"xr"#s" %w1, %"#w"0, [%2]\n" \
89a9643ea8Slogwang " cbnz %w1, 1b\n" \
90a9643ea8Slogwang : "=&r"(tmp), "=&r"(res) \
91a9643ea8Slogwang : "r" (p), "r" (val) \
92a9643ea8Slogwang : "memory" \
93a9643ea8Slogwang ); \
94a9643ea8Slogwang } \
95a9643ea8Slogwang \
96*22ce4affSfengbojiang _ATOMIC_OP_PROTO(t, op, bar, _lse) \
97a9643ea8Slogwang { \
98*22ce4affSfengbojiang uint##t##_t tmp; \
99a9643ea8Slogwang \
100*22ce4affSfengbojiang pre; \
101a9643ea8Slogwang __asm __volatile( \
102*22ce4affSfengbojiang ".arch_extension lse\n" \
103*22ce4affSfengbojiang "ld"#lse_asm_op#a#l#s" %"#w"2, %"#w"0, [%1]\n" \
104*22ce4affSfengbojiang ".arch_extension nolse\n" \
105*22ce4affSfengbojiang : "=r" (tmp) \
106a9643ea8Slogwang : "r" (p), "r" (val) \
107a9643ea8Slogwang : "memory" \
108a9643ea8Slogwang ); \
109*22ce4affSfengbojiang } \
110*22ce4affSfengbojiang \
111*22ce4affSfengbojiang _ATOMIC_OP_PROTO(t, op, bar, ) \
112*22ce4affSfengbojiang { \
113*22ce4affSfengbojiang if (_ATOMIC_LSE_SUPPORTED) \
114*22ce4affSfengbojiang atomic_##op##_##bar##t##_lse(p, val); \
115*22ce4affSfengbojiang else \
116*22ce4affSfengbojiang atomic_##op##_##bar##t##_llsc(p, val); \
117a9643ea8Slogwang }
118a9643ea8Slogwang
119*22ce4affSfengbojiang #define __ATOMIC_OP(op, llsc_asm_op, lse_asm_op, pre, bar, a, l) \
120*22ce4affSfengbojiang _ATOMIC_OP_IMPL(8, w, b, op, llsc_asm_op, lse_asm_op, pre, \
121*22ce4affSfengbojiang bar, a, l) \
122*22ce4affSfengbojiang _ATOMIC_OP_IMPL(16, w, h, op, llsc_asm_op, lse_asm_op, pre, \
123*22ce4affSfengbojiang bar, a, l) \
124*22ce4affSfengbojiang _ATOMIC_OP_IMPL(32, w, , op, llsc_asm_op, lse_asm_op, pre, \
125*22ce4affSfengbojiang bar, a, l) \
126*22ce4affSfengbojiang _ATOMIC_OP_IMPL(64, , , op, llsc_asm_op, lse_asm_op, pre, \
127*22ce4affSfengbojiang bar, a, l)
128a9643ea8Slogwang
129*22ce4affSfengbojiang #define _ATOMIC_OP(op, llsc_asm_op, lse_asm_op, pre) \
130*22ce4affSfengbojiang __ATOMIC_OP(op, llsc_asm_op, lse_asm_op, pre, , , ) \
131*22ce4affSfengbojiang __ATOMIC_OP(op, llsc_asm_op, lse_asm_op, pre, acq_, a, ) \
132*22ce4affSfengbojiang __ATOMIC_OP(op, llsc_asm_op, lse_asm_op, pre, rel_, , l)
133a9643ea8Slogwang
134*22ce4affSfengbojiang _ATOMIC_OP(add, add, add, )
135*22ce4affSfengbojiang _ATOMIC_OP(clear, bic, clr, )
136*22ce4affSfengbojiang _ATOMIC_OP(set, orr, set, )
137*22ce4affSfengbojiang _ATOMIC_OP(subtract, add, add, val = -val)
138*22ce4affSfengbojiang
139*22ce4affSfengbojiang #define _ATOMIC_CMPSET_PROTO(t, bar, flav) \
140a9643ea8Slogwang static __inline int \
141*22ce4affSfengbojiang atomic_cmpset_##bar##t##flav(volatile uint##t##_t *p, \
142*22ce4affSfengbojiang uint##t##_t cmpval, uint##t##_t newval)
143*22ce4affSfengbojiang
144*22ce4affSfengbojiang #define _ATOMIC_FCMPSET_PROTO(t, bar, flav) \
145*22ce4affSfengbojiang static __inline int \
146*22ce4affSfengbojiang atomic_fcmpset_##bar##t##flav(volatile uint##t##_t *p, \
147*22ce4affSfengbojiang uint##t##_t *cmpval, uint##t##_t newval)
148*22ce4affSfengbojiang
149*22ce4affSfengbojiang #define _ATOMIC_CMPSET_IMPL(t, w, s, bar, a, l) \
150*22ce4affSfengbojiang _ATOMIC_CMPSET_PROTO(t, bar, _llsc) \
151a9643ea8Slogwang { \
152*22ce4affSfengbojiang uint##t##_t tmp; \
153a9643ea8Slogwang int res; \
154a9643ea8Slogwang \
155a9643ea8Slogwang __asm __volatile( \
156a9643ea8Slogwang "1: mov %w1, #1\n" \
157*22ce4affSfengbojiang " ld"#a"xr"#s" %"#w"0, [%2]\n" \
158*22ce4affSfengbojiang " cmp %"#w"0, %"#w"3\n" \
159a9643ea8Slogwang " b.ne 2f\n" \
160*22ce4affSfengbojiang " st"#l"xr"#s" %w1, %"#w"4, [%2]\n" \
161a9643ea8Slogwang " cbnz %w1, 1b\n" \
162a9643ea8Slogwang "2:" \
163a9643ea8Slogwang : "=&r"(tmp), "=&r"(res) \
164a9643ea8Slogwang : "r" (p), "r" (cmpval), "r" (newval) \
165a9643ea8Slogwang : "cc", "memory" \
166a9643ea8Slogwang ); \
167a9643ea8Slogwang \
168a9643ea8Slogwang return (!res); \
169a9643ea8Slogwang } \
170a9643ea8Slogwang \
171*22ce4affSfengbojiang _ATOMIC_CMPSET_PROTO(t, bar, _lse) \
172a9643ea8Slogwang { \
173*22ce4affSfengbojiang uint##t##_t oldval; \
174a9643ea8Slogwang int res; \
175a9643ea8Slogwang \
176*22ce4affSfengbojiang oldval = cmpval; \
177a9643ea8Slogwang __asm __volatile( \
178*22ce4affSfengbojiang ".arch_extension lse\n" \
179*22ce4affSfengbojiang "cas"#a#l#s" %"#w"1, %"#w"4, [%3]\n" \
180*22ce4affSfengbojiang "cmp %"#w"1, %"#w"2\n" \
181*22ce4affSfengbojiang "cset %w0, eq\n" \
182*22ce4affSfengbojiang ".arch_extension nolse\n" \
183*22ce4affSfengbojiang : "=r" (res), "+&r" (cmpval) \
184*22ce4affSfengbojiang : "r" (oldval), "r" (p), "r" (newval) \
185a9643ea8Slogwang : "cc", "memory" \
186a9643ea8Slogwang ); \
187a9643ea8Slogwang \
188*22ce4affSfengbojiang return (res); \
189*22ce4affSfengbojiang } \
190*22ce4affSfengbojiang \
191*22ce4affSfengbojiang _ATOMIC_CMPSET_PROTO(t, bar, ) \
192*22ce4affSfengbojiang { \
193*22ce4affSfengbojiang if (_ATOMIC_LSE_SUPPORTED) \
194*22ce4affSfengbojiang return (atomic_cmpset_##bar##t##_lse(p, cmpval, \
195*22ce4affSfengbojiang newval)); \
196*22ce4affSfengbojiang else \
197*22ce4affSfengbojiang return (atomic_cmpset_##bar##t##_llsc(p, cmpval, \
198*22ce4affSfengbojiang newval)); \
199*22ce4affSfengbojiang } \
200*22ce4affSfengbojiang \
201*22ce4affSfengbojiang _ATOMIC_FCMPSET_PROTO(t, bar, _llsc) \
202*22ce4affSfengbojiang { \
203*22ce4affSfengbojiang uint##t##_t _cmpval, tmp; \
204*22ce4affSfengbojiang int res; \
205*22ce4affSfengbojiang \
206*22ce4affSfengbojiang _cmpval = *cmpval; \
207*22ce4affSfengbojiang __asm __volatile( \
208*22ce4affSfengbojiang " mov %w1, #1\n" \
209*22ce4affSfengbojiang " ld"#a"xr"#s" %"#w"0, [%2]\n" \
210*22ce4affSfengbojiang " cmp %"#w"0, %"#w"3\n" \
211*22ce4affSfengbojiang " b.ne 1f\n" \
212*22ce4affSfengbojiang " st"#l"xr"#s" %w1, %"#w"4, [%2]\n" \
213*22ce4affSfengbojiang "1:" \
214*22ce4affSfengbojiang : "=&r"(tmp), "=&r"(res) \
215*22ce4affSfengbojiang : "r" (p), "r" (_cmpval), "r" (newval) \
216*22ce4affSfengbojiang : "cc", "memory" \
217*22ce4affSfengbojiang ); \
218*22ce4affSfengbojiang *cmpval = tmp; \
219*22ce4affSfengbojiang \
220a9643ea8Slogwang return (!res); \
221*22ce4affSfengbojiang } \
222*22ce4affSfengbojiang \
223*22ce4affSfengbojiang _ATOMIC_FCMPSET_PROTO(t, bar, _lse) \
224*22ce4affSfengbojiang { \
225*22ce4affSfengbojiang uint##t##_t _cmpval, tmp; \
226*22ce4affSfengbojiang int res; \
227*22ce4affSfengbojiang \
228*22ce4affSfengbojiang _cmpval = tmp = *cmpval; \
229*22ce4affSfengbojiang __asm __volatile( \
230*22ce4affSfengbojiang ".arch_extension lse\n" \
231*22ce4affSfengbojiang "cas"#a#l#s" %"#w"1, %"#w"4, [%3]\n" \
232*22ce4affSfengbojiang "cmp %"#w"1, %"#w"2\n" \
233*22ce4affSfengbojiang "cset %w0, eq\n" \
234*22ce4affSfengbojiang ".arch_extension nolse\n" \
235*22ce4affSfengbojiang : "=r" (res), "+&r" (tmp) \
236*22ce4affSfengbojiang : "r" (_cmpval), "r" (p), "r" (newval) \
237*22ce4affSfengbojiang : "cc", "memory" \
238*22ce4affSfengbojiang ); \
239*22ce4affSfengbojiang *cmpval = tmp; \
240*22ce4affSfengbojiang \
241*22ce4affSfengbojiang return (res); \
242*22ce4affSfengbojiang } \
243*22ce4affSfengbojiang \
244*22ce4affSfengbojiang _ATOMIC_FCMPSET_PROTO(t, bar, ) \
245*22ce4affSfengbojiang { \
246*22ce4affSfengbojiang if (_ATOMIC_LSE_SUPPORTED) \
247*22ce4affSfengbojiang return (atomic_fcmpset_##bar##t##_lse(p, cmpval, \
248*22ce4affSfengbojiang newval)); \
249*22ce4affSfengbojiang else \
250*22ce4affSfengbojiang return (atomic_fcmpset_##bar##t##_llsc(p, cmpval, \
251*22ce4affSfengbojiang newval)); \
252a9643ea8Slogwang }
253a9643ea8Slogwang
254*22ce4affSfengbojiang #define _ATOMIC_CMPSET(bar, a, l) \
255*22ce4affSfengbojiang _ATOMIC_CMPSET_IMPL(8, w, b, bar, a, l) \
256*22ce4affSfengbojiang _ATOMIC_CMPSET_IMPL(16, w, h, bar, a, l) \
257*22ce4affSfengbojiang _ATOMIC_CMPSET_IMPL(32, w, , bar, a, l) \
258*22ce4affSfengbojiang _ATOMIC_CMPSET_IMPL(64, , , bar, a, l)
259a9643ea8Slogwang
260*22ce4affSfengbojiang #define atomic_cmpset_8 atomic_cmpset_8
261*22ce4affSfengbojiang #define atomic_fcmpset_8 atomic_fcmpset_8
262*22ce4affSfengbojiang #define atomic_cmpset_16 atomic_cmpset_16
263*22ce4affSfengbojiang #define atomic_fcmpset_16 atomic_fcmpset_16
264a9643ea8Slogwang
265*22ce4affSfengbojiang _ATOMIC_CMPSET( , , )
266*22ce4affSfengbojiang _ATOMIC_CMPSET(acq_, a, )
267*22ce4affSfengbojiang _ATOMIC_CMPSET(rel_, ,l)
268a9643ea8Slogwang
269*22ce4affSfengbojiang #define _ATOMIC_FETCHADD_PROTO(t, flav) \
270*22ce4affSfengbojiang static __inline uint##t##_t \
271*22ce4affSfengbojiang atomic_fetchadd_##t##flav(volatile uint##t##_t *p, uint##t##_t val)
272*22ce4affSfengbojiang
273*22ce4affSfengbojiang #define _ATOMIC_FETCHADD_IMPL(t, w) \
274*22ce4affSfengbojiang _ATOMIC_FETCHADD_PROTO(t, _llsc) \
275*22ce4affSfengbojiang { \
276*22ce4affSfengbojiang uint##t##_t ret, tmp; \
277*22ce4affSfengbojiang int res; \
278*22ce4affSfengbojiang \
279*22ce4affSfengbojiang __asm __volatile( \
280*22ce4affSfengbojiang "1: ldxr %"#w"2, [%3]\n" \
281*22ce4affSfengbojiang " add %"#w"0, %"#w"2, %"#w"4\n" \
282*22ce4affSfengbojiang " stxr %w1, %"#w"0, [%3]\n" \
283*22ce4affSfengbojiang " cbnz %w1, 1b\n" \
284*22ce4affSfengbojiang : "=&r" (tmp), "=&r" (res), "=&r" (ret) \
285*22ce4affSfengbojiang : "r" (p), "r" (val) \
286*22ce4affSfengbojiang : "memory" \
287*22ce4affSfengbojiang ); \
288*22ce4affSfengbojiang \
289*22ce4affSfengbojiang return (ret); \
290*22ce4affSfengbojiang } \
291*22ce4affSfengbojiang \
292*22ce4affSfengbojiang _ATOMIC_FETCHADD_PROTO(t, _lse) \
293*22ce4affSfengbojiang { \
294*22ce4affSfengbojiang uint##t##_t ret; \
295*22ce4affSfengbojiang \
296*22ce4affSfengbojiang __asm __volatile( \
297*22ce4affSfengbojiang ".arch_extension lse\n" \
298*22ce4affSfengbojiang "ldadd %"#w"2, %"#w"0, [%1]\n" \
299*22ce4affSfengbojiang ".arch_extension nolse\n" \
300*22ce4affSfengbojiang : "=r" (ret) \
301*22ce4affSfengbojiang : "r" (p), "r" (val) \
302*22ce4affSfengbojiang : "memory" \
303*22ce4affSfengbojiang ); \
304*22ce4affSfengbojiang \
305*22ce4affSfengbojiang return (ret); \
306*22ce4affSfengbojiang } \
307*22ce4affSfengbojiang \
308*22ce4affSfengbojiang _ATOMIC_FETCHADD_PROTO(t, ) \
309*22ce4affSfengbojiang { \
310*22ce4affSfengbojiang if (_ATOMIC_LSE_SUPPORTED) \
311*22ce4affSfengbojiang return (atomic_fetchadd_##t##_lse(p, val)); \
312*22ce4affSfengbojiang else \
313*22ce4affSfengbojiang return (atomic_fetchadd_##t##_llsc(p, val)); \
314a9643ea8Slogwang }
315a9643ea8Slogwang
316*22ce4affSfengbojiang _ATOMIC_FETCHADD_IMPL(32, w)
317*22ce4affSfengbojiang _ATOMIC_FETCHADD_IMPL(64, )
318a9643ea8Slogwang
319*22ce4affSfengbojiang #define _ATOMIC_SWAP_PROTO(t, flav) \
320*22ce4affSfengbojiang static __inline uint##t##_t \
321*22ce4affSfengbojiang atomic_swap_##t##flav(volatile uint##t##_t *p, uint##t##_t val)
322a9643ea8Slogwang
323*22ce4affSfengbojiang #define _ATOMIC_READANDCLEAR_PROTO(t, flav) \
324*22ce4affSfengbojiang static __inline uint##t##_t \
325*22ce4affSfengbojiang atomic_readandclear_##t##flav(volatile uint##t##_t *p)
326*22ce4affSfengbojiang
327*22ce4affSfengbojiang #define _ATOMIC_SWAP_IMPL(t, w, zreg) \
328*22ce4affSfengbojiang _ATOMIC_SWAP_PROTO(t, _llsc) \
329*22ce4affSfengbojiang { \
330*22ce4affSfengbojiang uint##t##_t ret; \
331*22ce4affSfengbojiang int res; \
332*22ce4affSfengbojiang \
333*22ce4affSfengbojiang __asm __volatile( \
334*22ce4affSfengbojiang "1: ldxr %"#w"1, [%2]\n" \
335*22ce4affSfengbojiang " stxr %w0, %"#w"3, [%2]\n" \
336*22ce4affSfengbojiang " cbnz %w0, 1b\n" \
337*22ce4affSfengbojiang : "=&r" (res), "=&r" (ret) \
338*22ce4affSfengbojiang : "r" (p), "r" (val) \
339*22ce4affSfengbojiang : "memory" \
340*22ce4affSfengbojiang ); \
341*22ce4affSfengbojiang \
342*22ce4affSfengbojiang return (ret); \
343*22ce4affSfengbojiang } \
344*22ce4affSfengbojiang \
345*22ce4affSfengbojiang _ATOMIC_SWAP_PROTO(t, _lse) \
346*22ce4affSfengbojiang { \
347*22ce4affSfengbojiang uint##t##_t ret; \
348*22ce4affSfengbojiang \
349*22ce4affSfengbojiang __asm __volatile( \
350*22ce4affSfengbojiang ".arch_extension lse\n" \
351*22ce4affSfengbojiang "swp %"#w"2, %"#w"0, [%1]\n" \
352*22ce4affSfengbojiang ".arch_extension nolse\n" \
353*22ce4affSfengbojiang : "=r" (ret) \
354*22ce4affSfengbojiang : "r" (p), "r" (val) \
355*22ce4affSfengbojiang : "memory" \
356*22ce4affSfengbojiang ); \
357*22ce4affSfengbojiang \
358*22ce4affSfengbojiang return (ret); \
359*22ce4affSfengbojiang } \
360*22ce4affSfengbojiang \
361*22ce4affSfengbojiang _ATOMIC_SWAP_PROTO(t, ) \
362*22ce4affSfengbojiang { \
363*22ce4affSfengbojiang if (_ATOMIC_LSE_SUPPORTED) \
364*22ce4affSfengbojiang return (atomic_swap_##t##_lse(p, val)); \
365*22ce4affSfengbojiang else \
366*22ce4affSfengbojiang return (atomic_swap_##t##_llsc(p, val)); \
367*22ce4affSfengbojiang } \
368*22ce4affSfengbojiang \
369*22ce4affSfengbojiang _ATOMIC_READANDCLEAR_PROTO(t, _llsc) \
370*22ce4affSfengbojiang { \
371*22ce4affSfengbojiang uint##t##_t ret; \
372*22ce4affSfengbojiang int res; \
373*22ce4affSfengbojiang \
374*22ce4affSfengbojiang __asm __volatile( \
375*22ce4affSfengbojiang "1: ldxr %"#w"1, [%2]\n" \
376*22ce4affSfengbojiang " stxr %w0, "#zreg", [%2]\n" \
377*22ce4affSfengbojiang " cbnz %w0, 1b\n" \
378*22ce4affSfengbojiang : "=&r" (res), "=&r" (ret) \
379*22ce4affSfengbojiang : "r" (p) \
380*22ce4affSfengbojiang : "memory" \
381*22ce4affSfengbojiang ); \
382*22ce4affSfengbojiang \
383*22ce4affSfengbojiang return (ret); \
384*22ce4affSfengbojiang } \
385*22ce4affSfengbojiang \
386*22ce4affSfengbojiang _ATOMIC_READANDCLEAR_PROTO(t, _lse) \
387*22ce4affSfengbojiang { \
388*22ce4affSfengbojiang return (atomic_swap_##t##_lse(p, 0)); \
389*22ce4affSfengbojiang } \
390*22ce4affSfengbojiang \
391*22ce4affSfengbojiang _ATOMIC_READANDCLEAR_PROTO(t, ) \
392*22ce4affSfengbojiang { \
393*22ce4affSfengbojiang if (_ATOMIC_LSE_SUPPORTED) \
394*22ce4affSfengbojiang return (atomic_readandclear_##t##_lse(p)); \
395*22ce4affSfengbojiang else \
396*22ce4affSfengbojiang return (atomic_readandclear_##t##_llsc(p)); \
397a9643ea8Slogwang }
398a9643ea8Slogwang
399*22ce4affSfengbojiang _ATOMIC_SWAP_IMPL(32, w, wzr)
400*22ce4affSfengbojiang _ATOMIC_SWAP_IMPL(64, , xzr)
401a9643ea8Slogwang
402*22ce4affSfengbojiang #define _ATOMIC_TEST_OP_PROTO(t, op, flav) \
403*22ce4affSfengbojiang static __inline int \
404*22ce4affSfengbojiang atomic_testand##op##_##t##flav(volatile uint##t##_t *p, u_int val)
405a9643ea8Slogwang
406*22ce4affSfengbojiang #define _ATOMIC_TEST_OP_IMPL(t, w, op, llsc_asm_op, lse_asm_op) \
407*22ce4affSfengbojiang _ATOMIC_TEST_OP_PROTO(t, op, _llsc) \
408*22ce4affSfengbojiang { \
409*22ce4affSfengbojiang uint##t##_t mask, old, tmp; \
410*22ce4affSfengbojiang int res; \
411*22ce4affSfengbojiang \
412*22ce4affSfengbojiang mask = ((uint##t##_t)1) << (val & (t - 1)); \
413*22ce4affSfengbojiang __asm __volatile( \
414*22ce4affSfengbojiang "1: ldxr %"#w"2, [%3]\n" \
415*22ce4affSfengbojiang " "#llsc_asm_op" %"#w"0, %"#w"2, %"#w"4\n" \
416*22ce4affSfengbojiang " stxr %w1, %"#w"0, [%3]\n" \
417*22ce4affSfengbojiang " cbnz %w1, 1b\n" \
418*22ce4affSfengbojiang : "=&r" (tmp), "=&r" (res), "=&r" (old) \
419*22ce4affSfengbojiang : "r" (p), "r" (mask) \
420*22ce4affSfengbojiang : "memory" \
421*22ce4affSfengbojiang ); \
422*22ce4affSfengbojiang \
423*22ce4affSfengbojiang return ((old & mask) != 0); \
424*22ce4affSfengbojiang } \
425*22ce4affSfengbojiang \
426*22ce4affSfengbojiang _ATOMIC_TEST_OP_PROTO(t, op, _lse) \
427*22ce4affSfengbojiang { \
428*22ce4affSfengbojiang uint##t##_t mask, old; \
429*22ce4affSfengbojiang \
430*22ce4affSfengbojiang mask = ((uint##t##_t)1) << (val & (t - 1)); \
431*22ce4affSfengbojiang __asm __volatile( \
432*22ce4affSfengbojiang ".arch_extension lse\n" \
433*22ce4affSfengbojiang "ld"#lse_asm_op" %"#w"2, %"#w"0, [%1]\n" \
434*22ce4affSfengbojiang ".arch_extension nolse\n" \
435*22ce4affSfengbojiang : "=r" (old) \
436*22ce4affSfengbojiang : "r" (p), "r" (mask) \
437*22ce4affSfengbojiang : "memory" \
438*22ce4affSfengbojiang ); \
439*22ce4affSfengbojiang \
440*22ce4affSfengbojiang return ((old & mask) != 0); \
441*22ce4affSfengbojiang } \
442*22ce4affSfengbojiang \
443*22ce4affSfengbojiang _ATOMIC_TEST_OP_PROTO(t, op, ) \
444*22ce4affSfengbojiang { \
445*22ce4affSfengbojiang if (_ATOMIC_LSE_SUPPORTED) \
446*22ce4affSfengbojiang return (atomic_testand##op##_##t##_lse(p, val)); \
447*22ce4affSfengbojiang else \
448*22ce4affSfengbojiang return (atomic_testand##op##_##t##_llsc(p, val)); \
449a9643ea8Slogwang }
450a9643ea8Slogwang
451*22ce4affSfengbojiang #define _ATOMIC_TEST_OP(op, llsc_asm_op, lse_asm_op) \
452*22ce4affSfengbojiang _ATOMIC_TEST_OP_IMPL(32, w, op, llsc_asm_op, lse_asm_op) \
453*22ce4affSfengbojiang _ATOMIC_TEST_OP_IMPL(64, , op, llsc_asm_op, lse_asm_op)
454a9643ea8Slogwang
_ATOMIC_TEST_OP(clear,bic,clr)455*22ce4affSfengbojiang _ATOMIC_TEST_OP(clear, bic, clr)
456*22ce4affSfengbojiang _ATOMIC_TEST_OP(set, orr, set)
457a9643ea8Slogwang
458*22ce4affSfengbojiang #define _ATOMIC_LOAD_ACQ_IMPL(t, w, s) \
459*22ce4affSfengbojiang static __inline uint##t##_t \
460*22ce4affSfengbojiang atomic_load_acq_##t(volatile uint##t##_t *p) \
461*22ce4affSfengbojiang { \
462*22ce4affSfengbojiang uint##t##_t ret; \
463*22ce4affSfengbojiang \
464*22ce4affSfengbojiang __asm __volatile( \
465*22ce4affSfengbojiang "ldar"#s" %"#w"0, [%1]\n" \
466*22ce4affSfengbojiang : "=&r" (ret) \
467*22ce4affSfengbojiang : "r" (p) \
468*22ce4affSfengbojiang : "memory"); \
469*22ce4affSfengbojiang \
470*22ce4affSfengbojiang return (ret); \
471a9643ea8Slogwang }
472a9643ea8Slogwang
473*22ce4affSfengbojiang #define atomic_load_acq_8 atomic_load_acq_8
474*22ce4affSfengbojiang #define atomic_load_acq_16 atomic_load_acq_16
475*22ce4affSfengbojiang _ATOMIC_LOAD_ACQ_IMPL(8, w, b)
476*22ce4affSfengbojiang _ATOMIC_LOAD_ACQ_IMPL(16, w, h)
477*22ce4affSfengbojiang _ATOMIC_LOAD_ACQ_IMPL(32, w, )
478*22ce4affSfengbojiang _ATOMIC_LOAD_ACQ_IMPL(64, , )
479a9643ea8Slogwang
480*22ce4affSfengbojiang #define _ATOMIC_STORE_REL_IMPL(t, w, s) \
481*22ce4affSfengbojiang static __inline void \
482*22ce4affSfengbojiang atomic_store_rel_##t(volatile uint##t##_t *p, uint##t##_t val) \
483*22ce4affSfengbojiang { \
484*22ce4affSfengbojiang __asm __volatile( \
485*22ce4affSfengbojiang "stlr"#s" %"#w"0, [%1]\n" \
486*22ce4affSfengbojiang : \
487*22ce4affSfengbojiang : "r" (val), "r" (p) \
488*22ce4affSfengbojiang : "memory"); \
489a9643ea8Slogwang }
490a9643ea8Slogwang
491*22ce4affSfengbojiang _ATOMIC_STORE_REL_IMPL(8, w, b)
492*22ce4affSfengbojiang _ATOMIC_STORE_REL_IMPL(16, w, h)
493*22ce4affSfengbojiang _ATOMIC_STORE_REL_IMPL(32, w, )
494*22ce4affSfengbojiang _ATOMIC_STORE_REL_IMPL(64, , )
495a9643ea8Slogwang
496a9643ea8Slogwang #define atomic_add_int atomic_add_32
497*22ce4affSfengbojiang #define atomic_fcmpset_int atomic_fcmpset_32
498a9643ea8Slogwang #define atomic_clear_int atomic_clear_32
499a9643ea8Slogwang #define atomic_cmpset_int atomic_cmpset_32
500a9643ea8Slogwang #define atomic_fetchadd_int atomic_fetchadd_32
501a9643ea8Slogwang #define atomic_readandclear_int atomic_readandclear_32
502a9643ea8Slogwang #define atomic_set_int atomic_set_32
503a9643ea8Slogwang #define atomic_swap_int atomic_swap_32
504a9643ea8Slogwang #define atomic_subtract_int atomic_subtract_32
505*22ce4affSfengbojiang #define atomic_testandclear_int atomic_testandclear_32
506*22ce4affSfengbojiang #define atomic_testandset_int atomic_testandset_32
507a9643ea8Slogwang
508a9643ea8Slogwang #define atomic_add_acq_int atomic_add_acq_32
509*22ce4affSfengbojiang #define atomic_fcmpset_acq_int atomic_fcmpset_acq_32
510a9643ea8Slogwang #define atomic_clear_acq_int atomic_clear_acq_32
511a9643ea8Slogwang #define atomic_cmpset_acq_int atomic_cmpset_acq_32
512a9643ea8Slogwang #define atomic_load_acq_int atomic_load_acq_32
513a9643ea8Slogwang #define atomic_set_acq_int atomic_set_acq_32
514a9643ea8Slogwang #define atomic_subtract_acq_int atomic_subtract_acq_32
515a9643ea8Slogwang
516a9643ea8Slogwang #define atomic_add_rel_int atomic_add_rel_32
517*22ce4affSfengbojiang #define atomic_fcmpset_rel_int atomic_fcmpset_rel_32
518*22ce4affSfengbojiang #define atomic_clear_rel_int atomic_clear_rel_32
519a9643ea8Slogwang #define atomic_cmpset_rel_int atomic_cmpset_rel_32
520a9643ea8Slogwang #define atomic_set_rel_int atomic_set_rel_32
521a9643ea8Slogwang #define atomic_subtract_rel_int atomic_subtract_rel_32
522a9643ea8Slogwang #define atomic_store_rel_int atomic_store_rel_32
523a9643ea8Slogwang
524a9643ea8Slogwang #define atomic_add_long atomic_add_64
525*22ce4affSfengbojiang #define atomic_fcmpset_long atomic_fcmpset_64
526a9643ea8Slogwang #define atomic_clear_long atomic_clear_64
527a9643ea8Slogwang #define atomic_cmpset_long atomic_cmpset_64
528a9643ea8Slogwang #define atomic_fetchadd_long atomic_fetchadd_64
529a9643ea8Slogwang #define atomic_readandclear_long atomic_readandclear_64
530a9643ea8Slogwang #define atomic_set_long atomic_set_64
531a9643ea8Slogwang #define atomic_swap_long atomic_swap_64
532a9643ea8Slogwang #define atomic_subtract_long atomic_subtract_64
533*22ce4affSfengbojiang #define atomic_testandclear_long atomic_testandclear_64
534*22ce4affSfengbojiang #define atomic_testandset_long atomic_testandset_64
535a9643ea8Slogwang
536a9643ea8Slogwang #define atomic_add_ptr atomic_add_64
537*22ce4affSfengbojiang #define atomic_fcmpset_ptr atomic_fcmpset_64
538a9643ea8Slogwang #define atomic_clear_ptr atomic_clear_64
539a9643ea8Slogwang #define atomic_cmpset_ptr atomic_cmpset_64
540a9643ea8Slogwang #define atomic_fetchadd_ptr atomic_fetchadd_64
541a9643ea8Slogwang #define atomic_readandclear_ptr atomic_readandclear_64
542a9643ea8Slogwang #define atomic_set_ptr atomic_set_64
543a9643ea8Slogwang #define atomic_swap_ptr atomic_swap_64
544a9643ea8Slogwang #define atomic_subtract_ptr atomic_subtract_64
545a9643ea8Slogwang
546a9643ea8Slogwang #define atomic_add_acq_long atomic_add_acq_64
547*22ce4affSfengbojiang #define atomic_fcmpset_acq_long atomic_fcmpset_acq_64
548*22ce4affSfengbojiang #define atomic_clear_acq_long atomic_clear_acq_64
549a9643ea8Slogwang #define atomic_cmpset_acq_long atomic_cmpset_acq_64
550a9643ea8Slogwang #define atomic_load_acq_long atomic_load_acq_64
551a9643ea8Slogwang #define atomic_set_acq_long atomic_set_acq_64
552a9643ea8Slogwang #define atomic_subtract_acq_long atomic_subtract_acq_64
553a9643ea8Slogwang
554a9643ea8Slogwang #define atomic_add_acq_ptr atomic_add_acq_64
555*22ce4affSfengbojiang #define atomic_fcmpset_acq_ptr atomic_fcmpset_acq_64
556*22ce4affSfengbojiang #define atomic_clear_acq_ptr atomic_clear_acq_64
557a9643ea8Slogwang #define atomic_cmpset_acq_ptr atomic_cmpset_acq_64
558a9643ea8Slogwang #define atomic_load_acq_ptr atomic_load_acq_64
559a9643ea8Slogwang #define atomic_set_acq_ptr atomic_set_acq_64
560a9643ea8Slogwang #define atomic_subtract_acq_ptr atomic_subtract_acq_64
561a9643ea8Slogwang
562a9643ea8Slogwang #define atomic_add_rel_long atomic_add_rel_64
563*22ce4affSfengbojiang #define atomic_fcmpset_rel_long atomic_fcmpset_rel_64
564a9643ea8Slogwang #define atomic_clear_rel_long atomic_clear_rel_64
565a9643ea8Slogwang #define atomic_cmpset_rel_long atomic_cmpset_rel_64
566a9643ea8Slogwang #define atomic_set_rel_long atomic_set_rel_64
567a9643ea8Slogwang #define atomic_subtract_rel_long atomic_subtract_rel_64
568a9643ea8Slogwang #define atomic_store_rel_long atomic_store_rel_64
569a9643ea8Slogwang
570a9643ea8Slogwang #define atomic_add_rel_ptr atomic_add_rel_64
571*22ce4affSfengbojiang #define atomic_fcmpset_rel_ptr atomic_fcmpset_rel_64
572a9643ea8Slogwang #define atomic_clear_rel_ptr atomic_clear_rel_64
573a9643ea8Slogwang #define atomic_cmpset_rel_ptr atomic_cmpset_rel_64
574a9643ea8Slogwang #define atomic_set_rel_ptr atomic_set_rel_64
575a9643ea8Slogwang #define atomic_subtract_rel_ptr atomic_subtract_rel_64
576a9643ea8Slogwang #define atomic_store_rel_ptr atomic_store_rel_64
577a9643ea8Slogwang
578a9643ea8Slogwang static __inline void
579a9643ea8Slogwang atomic_thread_fence_acq(void)
580a9643ea8Slogwang {
581a9643ea8Slogwang
582a9643ea8Slogwang dmb(ld);
583a9643ea8Slogwang }
584a9643ea8Slogwang
585a9643ea8Slogwang static __inline void
atomic_thread_fence_rel(void)586a9643ea8Slogwang atomic_thread_fence_rel(void)
587a9643ea8Slogwang {
588a9643ea8Slogwang
589a9643ea8Slogwang dmb(sy);
590a9643ea8Slogwang }
591a9643ea8Slogwang
592a9643ea8Slogwang static __inline void
atomic_thread_fence_acq_rel(void)593a9643ea8Slogwang atomic_thread_fence_acq_rel(void)
594a9643ea8Slogwang {
595a9643ea8Slogwang
596a9643ea8Slogwang dmb(sy);
597a9643ea8Slogwang }
598a9643ea8Slogwang
599a9643ea8Slogwang static __inline void
atomic_thread_fence_seq_cst(void)600a9643ea8Slogwang atomic_thread_fence_seq_cst(void)
601a9643ea8Slogwang {
602a9643ea8Slogwang
603a9643ea8Slogwang dmb(sy);
604a9643ea8Slogwang }
605a9643ea8Slogwang
606*22ce4affSfengbojiang #include <sys/_atomic_subword.h>
607a9643ea8Slogwang
608*22ce4affSfengbojiang #endif /* KCSAN && !KCSAN_RUNTIME */
609*22ce4affSfengbojiang #endif /* _MACHINE_ATOMIC_H_ */
610