]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/arm64/include/atomic.h
Partial MFV r329753:
[FreeBSD/FreeBSD.git] / sys / arm64 / include / atomic.h
1 /*-
2  * Copyright (c) 2013 Andrew Turner <andrew@freebsd.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28
29 #ifndef _MACHINE_ATOMIC_H_
30 #define _MACHINE_ATOMIC_H_
31
32 #include <sys/atomic_common.h>
33
34 #define isb()           __asm __volatile("isb" : : : "memory")
35
36 /*
37  * Options for DMB and DSB:
38  *      oshld   Outer Shareable, load
39  *      oshst   Outer Shareable, store
40  *      osh     Outer Shareable, all
41  *      nshld   Non-shareable, load
42  *      nshst   Non-shareable, store
43  *      nsh     Non-shareable, all
44  *      ishld   Inner Shareable, load
45  *      ishst   Inner Shareable, store
46  *      ish     Inner Shareable, all
47  *      ld      Full system, load
48  *      st      Full system, store
49  *      sy      Full system, all
50  */
51 #define dsb(opt)        __asm __volatile("dsb " __STRING(opt) : : : "memory")
52 #define dmb(opt)        __asm __volatile("dmb " __STRING(opt) : : : "memory")
53
54 #define mb()    dmb(sy) /* Full system memory barrier all */
55 #define wmb()   dmb(st) /* Full system memory barrier store */
56 #define rmb()   dmb(ld) /* Full system memory barrier load */
57
58 #define ATOMIC_OP(op, asm_op, bar, a, l)                                \
59 static __inline void                                                    \
60 atomic_##op##_##bar##32(volatile uint32_t *p, uint32_t val)             \
61 {                                                                       \
62         uint32_t tmp;                                                   \
63         int res;                                                        \
64                                                                         \
65         __asm __volatile(                                               \
66             "1: ld"#a"xr   %w0, [%2]      \n"                           \
67             "   "#asm_op"  %w0, %w0, %w3  \n"                           \
68             "   st"#l"xr   %w1, %w0, [%2] \n"                           \
69             "   cbnz       %w1, 1b        \n"                           \
70             : "=&r"(tmp), "=&r"(res)                                    \
71             : "r" (p), "r" (val)                                        \
72             : "memory"                                                  \
73         );                                                              \
74 }                                                                       \
75                                                                         \
76 static __inline void                                                    \
77 atomic_##op##_##bar##64(volatile uint64_t *p, uint64_t val)             \
78 {                                                                       \
79         uint64_t tmp;                                                   \
80         int res;                                                        \
81                                                                         \
82         __asm __volatile(                                               \
83             "1: ld"#a"xr   %0, [%2]      \n"                            \
84             "   "#asm_op"  %0, %0, %3    \n"                            \
85             "   st"#l"xr   %w1, %0, [%2] \n"                            \
86             "   cbnz       %w1, 1b       \n"                            \
87             : "=&r"(tmp), "=&r"(res)                                    \
88             : "r" (p), "r" (val)                                        \
89             : "memory"                                                  \
90         );                                                              \
91 }
92
93 #define ATOMIC(op, asm_op)                                              \
94     ATOMIC_OP(op, asm_op,     ,  ,  )                                   \
95     ATOMIC_OP(op, asm_op, acq_, a,  )                                   \
96     ATOMIC_OP(op, asm_op, rel_,  , l)                                   \
97
98 ATOMIC(add,      add)
99 ATOMIC(clear,    bic)
100 ATOMIC(set,      orr)
101 ATOMIC(subtract, sub)
102
103 #define ATOMIC_FCMPSET(bar, a, l)                                       \
104 static __inline int                                                     \
105 atomic_fcmpset_##bar##32(volatile uint32_t *p, uint32_t *cmpval,        \
106     uint32_t newval)                                                    \
107 {                                                                       \
108         uint32_t tmp;                                                   \
109         uint32_t _cmpval = *cmpval;                                     \
110         int res;                                                        \
111                                                                         \
112         __asm __volatile(                                               \
113             "1: mov      %w1, #1        \n"                             \
114             "   ld"#a"xr %w0, [%2]      \n"                             \
115             "   cmp      %w0, %w3       \n"                             \
116             "   b.ne     2f             \n"                             \
117             "   st"#l"xr %w1, %w4, [%2] \n"                             \
118             "2:"                                                        \
119             : "=&r"(tmp), "=&r"(res)                                    \
120             : "r" (p), "r" (_cmpval), "r" (newval)                      \
121             : "cc", "memory"                                            \
122         );                                                              \
123         *cmpval = tmp;                                                  \
124                                                                         \
125         return (!res);                                                  \
126 }                                                                       \
127                                                                         \
128 static __inline int                                                     \
129 atomic_fcmpset_##bar##64(volatile uint64_t *p, uint64_t *cmpval,        \
130     uint64_t newval)                                                    \
131 {                                                                       \
132         uint64_t tmp;                                                   \
133         uint64_t _cmpval = *cmpval;                                     \
134         int res;                                                        \
135                                                                         \
136         __asm __volatile(                                               \
137             "1: mov      %w1, #1       \n"                              \
138             "   ld"#a"xr %0, [%2]      \n"                              \
139             "   cmp      %0, %3        \n"                              \
140             "   b.ne     2f            \n"                              \
141             "   st"#l"xr %w1, %4, [%2] \n"                              \
142             "2:"                                                        \
143             : "=&r"(tmp), "=&r"(res)                                    \
144             : "r" (p), "r" (_cmpval), "r" (newval)                      \
145             : "cc", "memory"                                            \
146         );                                                              \
147         *cmpval = tmp;                                                  \
148                                                                         \
149         return (!res);                                                  \
150 }
151
152 ATOMIC_FCMPSET(    ,  , )
153 ATOMIC_FCMPSET(acq_, a, )
154 ATOMIC_FCMPSET(rel_,  ,l)
155
156 #undef ATOMIC_FCMPSET
157
158 #define ATOMIC_CMPSET(bar, a, l)                                        \
159 static __inline int                                                     \
160 atomic_cmpset_##bar##32(volatile uint32_t *p, uint32_t cmpval,          \
161     uint32_t newval)                                                    \
162 {                                                                       \
163         uint32_t tmp;                                                   \
164         int res;                                                        \
165                                                                         \
166         __asm __volatile(                                               \
167             "1: mov      %w1, #1        \n"                             \
168             "   ld"#a"xr %w0, [%2]      \n"                             \
169             "   cmp      %w0, %w3       \n"                             \
170             "   b.ne     2f             \n"                             \
171             "   st"#l"xr %w1, %w4, [%2] \n"                             \
172             "   cbnz     %w1, 1b        \n"                             \
173             "2:"                                                        \
174             : "=&r"(tmp), "=&r"(res)                                    \
175             : "r" (p), "r" (cmpval), "r" (newval)                       \
176             : "cc", "memory"                                                    \
177         );                                                              \
178                                                                         \
179         return (!res);                                                  \
180 }                                                                       \
181                                                                         \
182 static __inline int                                                     \
183 atomic_cmpset_##bar##64(volatile uint64_t *p, uint64_t cmpval,          \
184     uint64_t newval)                                                    \
185 {                                                                       \
186         uint64_t tmp;                                                   \
187         int res;                                                        \
188                                                                         \
189         __asm __volatile(                                               \
190             "1: mov      %w1, #1       \n"                              \
191             "   ld"#a"xr %0, [%2]      \n"                              \
192             "   cmp      %0, %3        \n"                              \
193             "   b.ne     2f            \n"                              \
194             "   st"#l"xr %w1, %4, [%2] \n"                              \
195             "   cbnz     %w1, 1b       \n"                              \
196             "2:"                                                        \
197             : "=&r"(tmp), "=&r"(res)                                    \
198             : "r" (p), "r" (cmpval), "r" (newval)                       \
199             : "cc", "memory"                                                    \
200         );                                                              \
201                                                                         \
202         return (!res);                                                  \
203 }
204
205 ATOMIC_CMPSET(    ,  , )
206 ATOMIC_CMPSET(acq_, a, )
207 ATOMIC_CMPSET(rel_,  ,l)
208
209 static __inline uint32_t
210 atomic_fetchadd_32(volatile uint32_t *p, uint32_t val)
211 {
212         uint32_t tmp, ret;
213         int res;
214
215         __asm __volatile(
216             "1: ldxr    %w2, [%3]      \n"
217             "   add     %w0, %w2, %w4  \n"
218             "   stxr    %w1, %w0, [%3] \n"
219             "   cbnz    %w1, 1b        \n"
220             : "=&r"(tmp), "=&r"(res), "=&r"(ret)
221             : "r" (p), "r" (val)
222             : "memory"
223         );
224
225         return (ret);
226 }
227
228 static __inline uint64_t
229 atomic_fetchadd_64(volatile uint64_t *p, uint64_t val)
230 {
231         uint64_t tmp, ret;
232         int res;
233
234         __asm __volatile(
235             "1: ldxr    %2, [%3]      \n"
236             "   add     %0, %2, %4    \n"
237             "   stxr    %w1, %0, [%3] \n"
238             "   cbnz    %w1, 1b       \n"
239             : "=&r"(tmp), "=&r"(res), "=&r"(ret)
240             : "r" (p), "r" (val)
241             : "memory"
242         );
243
244         return (ret);
245 }
246
247 static __inline uint32_t
248 atomic_readandclear_32(volatile uint32_t *p)
249 {
250         uint32_t ret;
251         int res;
252
253         __asm __volatile(
254             "1: ldxr    %w1, [%2]      \n"
255             "   stxr    %w0, wzr, [%2] \n"
256             "   cbnz    %w0, 1b        \n"
257             : "=&r"(res), "=&r"(ret)
258             : "r" (p)
259             : "memory"
260         );
261
262         return (ret);
263 }
264
265 static __inline uint64_t
266 atomic_readandclear_64(volatile uint64_t *p)
267 {
268         uint64_t ret;
269         int res;
270
271         __asm __volatile(
272             "1: ldxr    %1, [%2]      \n"
273             "   stxr    %w0, xzr, [%2] \n"
274             "   cbnz    %w0, 1b        \n"
275             : "=&r"(res), "=&r"(ret)
276             : "r" (p)
277             : "memory"
278         );
279
280         return (ret);
281 }
282
283 static __inline uint32_t
284 atomic_swap_32(volatile uint32_t *p, uint32_t val)
285 {
286         uint32_t ret;
287         int res;
288
289         __asm __volatile(
290             "1: ldxr    %w0, [%2]      \n"
291             "   stxr    %w1, %w3, [%2] \n"
292             "   cbnz    %w1, 1b        \n"
293             : "=&r"(ret), "=&r"(res)
294             : "r" (p), "r" (val)
295             : "memory"
296         );
297
298         return (ret);
299 }
300
301 static __inline uint64_t
302 atomic_swap_64(volatile uint64_t *p, uint64_t val)
303 {
304         uint64_t ret;
305         int res;
306
307         __asm __volatile(
308             "1: ldxr    %0, [%2]      \n"
309             "   stxr    %w1, %3, [%2] \n"
310             "   cbnz    %w1, 1b       \n"
311             : "=&r"(ret), "=&r"(res)
312             : "r" (p), "r" (val)
313             : "memory"
314         );
315
316         return (ret);
317 }
318
319 static __inline uint32_t
320 atomic_load_acq_32(volatile uint32_t *p)
321 {
322         uint32_t ret;
323
324         __asm __volatile(
325             "ldar       %w0, [%1] \n"
326             : "=&r" (ret)
327             : "r" (p)
328             : "memory");
329
330         return (ret);
331 }
332
333 static __inline uint64_t
334 atomic_load_acq_64(volatile uint64_t *p)
335 {
336         uint64_t ret;
337
338         __asm __volatile(
339             "ldar       %0, [%1] \n"
340             : "=&r" (ret)
341             : "r" (p)
342             : "memory");
343
344         return (ret);
345 }
346
347 static __inline void
348 atomic_store_rel_32(volatile uint32_t *p, uint32_t val)
349 {
350
351         __asm __volatile(
352             "stlr       %w0, [%1] \n"
353             :
354             : "r" (val), "r" (p)
355             : "memory");
356 }
357
358 static __inline void
359 atomic_store_rel_64(volatile uint64_t *p, uint64_t val)
360 {
361
362         __asm __volatile(
363             "stlr       %0, [%1] \n"
364             :
365             : "r" (val), "r" (p)
366             : "memory");
367 }
368
369
370 #define atomic_add_int                  atomic_add_32
371 #define atomic_fcmpset_int              atomic_fcmpset_32
372 #define atomic_clear_int                atomic_clear_32
373 #define atomic_cmpset_int               atomic_cmpset_32
374 #define atomic_fetchadd_int             atomic_fetchadd_32
375 #define atomic_readandclear_int         atomic_readandclear_32
376 #define atomic_set_int                  atomic_set_32
377 #define atomic_swap_int                 atomic_swap_32
378 #define atomic_subtract_int             atomic_subtract_32
379
380 #define atomic_add_acq_int              atomic_add_acq_32
381 #define atomic_fcmpset_acq_int          atomic_fcmpset_acq_32
382 #define atomic_clear_acq_int            atomic_clear_acq_32
383 #define atomic_cmpset_acq_int           atomic_cmpset_acq_32
384 #define atomic_load_acq_int             atomic_load_acq_32
385 #define atomic_set_acq_int              atomic_set_acq_32
386 #define atomic_subtract_acq_int         atomic_subtract_acq_32
387
388 #define atomic_add_rel_int              atomic_add_rel_32
389 #define atomic_fcmpset_rel_int          atomic_fcmpset_rel_32
390 #define atomic_clear_rel_int            atomic_clear_rel_32
391 #define atomic_cmpset_rel_int           atomic_cmpset_rel_32
392 #define atomic_set_rel_int              atomic_set_rel_32
393 #define atomic_subtract_rel_int         atomic_subtract_rel_32
394 #define atomic_store_rel_int            atomic_store_rel_32
395
396 #define atomic_add_long                 atomic_add_64
397 #define atomic_fcmpset_long             atomic_fcmpset_64
398 #define atomic_clear_long               atomic_clear_64
399 #define atomic_cmpset_long              atomic_cmpset_64
400 #define atomic_fetchadd_long            atomic_fetchadd_64
401 #define atomic_readandclear_long        atomic_readandclear_64
402 #define atomic_set_long                 atomic_set_64
403 #define atomic_swap_long                atomic_swap_64
404 #define atomic_subtract_long            atomic_subtract_64
405
406 #define atomic_add_ptr                  atomic_add_64
407 #define atomic_fcmpset_ptr              atomic_fcmpset_64
408 #define atomic_clear_ptr                atomic_clear_64
409 #define atomic_cmpset_ptr               atomic_cmpset_64
410 #define atomic_fetchadd_ptr             atomic_fetchadd_64
411 #define atomic_readandclear_ptr         atomic_readandclear_64
412 #define atomic_set_ptr                  atomic_set_64
413 #define atomic_swap_ptr                 atomic_swap_64
414 #define atomic_subtract_ptr             atomic_subtract_64
415
416 #define atomic_add_acq_long             atomic_add_acq_64
417 #define atomic_fcmpset_acq_long         atomic_fcmpset_acq_64
418 #define atomic_clear_acq_long           atomic_clear_acq_64
419 #define atomic_cmpset_acq_long          atomic_cmpset_acq_64
420 #define atomic_load_acq_long            atomic_load_acq_64
421 #define atomic_set_acq_long             atomic_set_acq_64
422 #define atomic_subtract_acq_long        atomic_subtract_acq_64
423
424 #define atomic_add_acq_ptr              atomic_add_acq_64
425 #define atomic_fcmpset_acq_ptr          atomic_fcmpset_acq_64
426 #define atomic_clear_acq_ptr            atomic_clear_acq_64
427 #define atomic_cmpset_acq_ptr           atomic_cmpset_acq_64
428 #define atomic_load_acq_ptr             atomic_load_acq_64
429 #define atomic_set_acq_ptr              atomic_set_acq_64
430 #define atomic_subtract_acq_ptr         atomic_subtract_acq_64
431
432 #define atomic_add_rel_long             atomic_add_rel_64
433 #define atomic_fcmpset_rel_long         atomic_fcmpset_rel_64
434 #define atomic_clear_rel_long           atomic_clear_rel_64
435 #define atomic_cmpset_rel_long          atomic_cmpset_rel_64
436 #define atomic_set_rel_long             atomic_set_rel_64
437 #define atomic_subtract_rel_long        atomic_subtract_rel_64
438 #define atomic_store_rel_long           atomic_store_rel_64
439
440 #define atomic_add_rel_ptr              atomic_add_rel_64
441 #define atomic_fcmpset_rel_ptr          atomic_fcmpset_rel_64
442 #define atomic_clear_rel_ptr            atomic_clear_rel_64
443 #define atomic_cmpset_rel_ptr           atomic_cmpset_rel_64
444 #define atomic_set_rel_ptr              atomic_set_rel_64
445 #define atomic_subtract_rel_ptr         atomic_subtract_rel_64
446 #define atomic_store_rel_ptr            atomic_store_rel_64
447
448 static __inline void
449 atomic_thread_fence_acq(void)
450 {
451
452         dmb(ld);
453 }
454
455 static __inline void
456 atomic_thread_fence_rel(void)
457 {
458
459         dmb(sy);
460 }
461
462 static __inline void
463 atomic_thread_fence_acq_rel(void)
464 {
465
466         dmb(sy);
467 }
468
469 static __inline void
470 atomic_thread_fence_seq_cst(void)
471 {
472
473         dmb(sy);
474 }
475
476 #endif /* _MACHINE_ATOMIC_H_ */
477