2 * Copyright (c) 2013 Andrew Turner <andrew@freebsd.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
29 #ifndef _MACHINE_ATOMIC_H_
30 #define _MACHINE_ATOMIC_H_
32 #define isb() __asm __volatile("isb" : : : "memory")
35 * Options for DMB and DSB:
36 * oshld Outer Shareable, load
37 * oshst Outer Shareable, store
38 * osh Outer Shareable, all
39 * nshld Non-shareable, load
40 * nshst Non-shareable, store
41 * nsh Non-shareable, all
42 * ishld Inner Shareable, load
43 * ishst Inner Shareable, store
44 * ish Inner Shareable, all
45 * ld Full system, load
46 * st Full system, store
49 #define dsb(opt) __asm __volatile("dsb " __STRING(opt) : : : "memory")
50 #define dmb(opt) __asm __volatile("dmb " __STRING(opt) : : : "memory")
52 #define mb() dmb(sy) /* Full system memory barrier all */
53 #define wmb() dmb(st) /* Full system memory barrier store */
54 #define rmb() dmb(ld) /* Full system memory barrier load */
56 #if defined(KCSAN) && !defined(KCSAN_RUNTIME)
57 #include <sys/_cscan_atomic.h>
60 #include <sys/atomic_common.h>
62 #define ATOMIC_OP(op, asm_op, bar, a, l) \
63 static __inline void \
64 atomic_##op##_##bar##8(volatile uint8_t *p, uint8_t val) \
70 "1: ld"#a"xrb %w0, [%2] \n" \
71 " "#asm_op" %w0, %w0, %w3 \n" \
72 " st"#l"xrb %w1, %w0, [%2] \n" \
74 : "=&r"(tmp), "=&r"(res) \
75 : "r" (p), "r" (val) \
80 static __inline void \
81 atomic_##op##_##bar##16(volatile uint16_t *p, uint16_t val) \
87 "1: ld"#a"xrh %w0, [%2] \n" \
88 " "#asm_op" %w0, %w0, %w3 \n" \
89 " st"#l"xrh %w1, %w0, [%2] \n" \
91 : "=&r"(tmp), "=&r"(res) \
92 : "r" (p), "r" (val) \
97 static __inline void \
98 atomic_##op##_##bar##32(volatile uint32_t *p, uint32_t val) \
104 "1: ld"#a"xr %w0, [%2] \n" \
105 " "#asm_op" %w0, %w0, %w3 \n" \
106 " st"#l"xr %w1, %w0, [%2] \n" \
108 : "=&r"(tmp), "=&r"(res) \
109 : "r" (p), "r" (val) \
114 static __inline void \
115 atomic_##op##_##bar##64(volatile uint64_t *p, uint64_t val) \
121 "1: ld"#a"xr %0, [%2] \n" \
122 " "#asm_op" %0, %0, %3 \n" \
123 " st"#l"xr %w1, %0, [%2] \n" \
125 : "=&r"(tmp), "=&r"(res) \
126 : "r" (p), "r" (val) \
131 #define ATOMIC(op, asm_op) \
132 ATOMIC_OP(op, asm_op, , , ) \
133 ATOMIC_OP(op, asm_op, acq_, a, ) \
134 ATOMIC_OP(op, asm_op, rel_, , l) \
139 ATOMIC(subtract, sub)
141 #define ATOMIC_FCMPSET(bar, a, l) \
142 static __inline int \
143 atomic_fcmpset_##bar##8(volatile uint8_t *p, uint8_t *cmpval, \
147 uint8_t _cmpval = *cmpval; \
151 "1: mov %w1, #1 \n" \
152 " ld"#a"xrb %w0, [%2] \n" \
155 " st"#l"xrb %w1, %w4, [%2]\n" \
157 : "=&r"(tmp), "=&r"(res) \
158 : "r" (p), "r" (_cmpval), "r" (newval) \
166 static __inline int \
167 atomic_fcmpset_##bar##16(volatile uint16_t *p, uint16_t *cmpval, \
171 uint16_t _cmpval = *cmpval; \
175 "1: mov %w1, #1 \n" \
176 " ld"#a"xrh %w0, [%2] \n" \
179 " st"#l"xrh %w1, %w4, [%2] \n" \
181 : "=&r"(tmp), "=&r"(res) \
182 : "r" (p), "r" (_cmpval), "r" (newval) \
190 static __inline int \
191 atomic_fcmpset_##bar##32(volatile uint32_t *p, uint32_t *cmpval, \
195 uint32_t _cmpval = *cmpval; \
199 "1: mov %w1, #1 \n" \
200 " ld"#a"xr %w0, [%2] \n" \
203 " st"#l"xr %w1, %w4, [%2] \n" \
205 : "=&r"(tmp), "=&r"(res) \
206 : "r" (p), "r" (_cmpval), "r" (newval) \
214 static __inline int \
215 atomic_fcmpset_##bar##64(volatile uint64_t *p, uint64_t *cmpval, \
219 uint64_t _cmpval = *cmpval; \
223 "1: mov %w1, #1 \n" \
224 " ld"#a"xr %0, [%2] \n" \
227 " st"#l"xr %w1, %4, [%2] \n" \
229 : "=&r"(tmp), "=&r"(res) \
230 : "r" (p), "r" (_cmpval), "r" (newval) \
238 ATOMIC_FCMPSET( , , )
239 ATOMIC_FCMPSET(acq_, a, )
240 ATOMIC_FCMPSET(rel_, ,l)
242 #undef ATOMIC_FCMPSET
244 #define ATOMIC_CMPSET(bar, a, l) \
245 static __inline int \
246 atomic_cmpset_##bar##8(volatile uint8_t *p, uint8_t cmpval, \
253 "1: mov %w1, #1 \n" \
254 " ld"#a"xrb %w0, [%2] \n" \
257 " st"#l"xrb %w1, %w4, [%2] \n" \
260 : "=&r"(tmp), "=&r"(res) \
261 : "r" (p), "r" (cmpval), "r" (newval) \
268 static __inline int \
269 atomic_cmpset_##bar##16(volatile uint16_t *p, uint16_t cmpval, \
276 "1: mov %w1, #1 \n" \
277 " ld"#a"xrh %w0, [%2] \n" \
280 " st"#l"xrh %w1, %w4, [%2] \n" \
283 : "=&r"(tmp), "=&r"(res) \
284 : "r" (p), "r" (cmpval), "r" (newval) \
291 static __inline int \
292 atomic_cmpset_##bar##32(volatile uint32_t *p, uint32_t cmpval, \
299 "1: mov %w1, #1 \n" \
300 " ld"#a"xr %w0, [%2] \n" \
303 " st"#l"xr %w1, %w4, [%2] \n" \
306 : "=&r"(tmp), "=&r"(res) \
307 : "r" (p), "r" (cmpval), "r" (newval) \
314 static __inline int \
315 atomic_cmpset_##bar##64(volatile uint64_t *p, uint64_t cmpval, \
322 "1: mov %w1, #1 \n" \
323 " ld"#a"xr %0, [%2] \n" \
326 " st"#l"xr %w1, %4, [%2] \n" \
329 : "=&r"(tmp), "=&r"(res) \
330 : "r" (p), "r" (cmpval), "r" (newval) \
338 ATOMIC_CMPSET(acq_, a, )
339 ATOMIC_CMPSET(rel_, ,l)
341 static __inline uint32_t
342 atomic_fetchadd_32(volatile uint32_t *p, uint32_t val)
348 "1: ldxr %w2, [%3] \n"
349 " add %w0, %w2, %w4 \n"
350 " stxr %w1, %w0, [%3] \n"
352 : "=&r"(tmp), "=&r"(res), "=&r"(ret)
360 static __inline uint64_t
361 atomic_fetchadd_64(volatile uint64_t *p, uint64_t val)
367 "1: ldxr %2, [%3] \n"
369 " stxr %w1, %0, [%3] \n"
371 : "=&r"(tmp), "=&r"(res), "=&r"(ret)
379 static __inline uint32_t
380 atomic_readandclear_32(volatile uint32_t *p)
386 "1: ldxr %w1, [%2] \n"
387 " stxr %w0, wzr, [%2] \n"
389 : "=&r"(res), "=&r"(ret)
397 static __inline uint64_t
398 atomic_readandclear_64(volatile uint64_t *p)
404 "1: ldxr %1, [%2] \n"
405 " stxr %w0, xzr, [%2] \n"
407 : "=&r"(res), "=&r"(ret)
415 static __inline uint32_t
416 atomic_swap_32(volatile uint32_t *p, uint32_t val)
422 "1: ldxr %w0, [%2] \n"
423 " stxr %w1, %w3, [%2] \n"
425 : "=&r"(ret), "=&r"(res)
433 static __inline uint64_t
434 atomic_swap_64(volatile uint64_t *p, uint64_t val)
440 "1: ldxr %0, [%2] \n"
441 " stxr %w1, %3, [%2] \n"
443 : "=&r"(ret), "=&r"(res)
451 static __inline uint32_t
452 atomic_load_acq_32(volatile uint32_t *p)
465 static __inline uint64_t
466 atomic_load_acq_64(volatile uint64_t *p)
480 atomic_store_rel_32(volatile uint32_t *p, uint32_t val)
491 atomic_store_rel_64(volatile uint64_t *p, uint64_t val)
502 #define atomic_add_int atomic_add_32
503 #define atomic_fcmpset_int atomic_fcmpset_32
504 #define atomic_clear_int atomic_clear_32
505 #define atomic_cmpset_int atomic_cmpset_32
506 #define atomic_fetchadd_int atomic_fetchadd_32
507 #define atomic_readandclear_int atomic_readandclear_32
508 #define atomic_set_int atomic_set_32
509 #define atomic_swap_int atomic_swap_32
510 #define atomic_subtract_int atomic_subtract_32
512 #define atomic_add_acq_int atomic_add_acq_32
513 #define atomic_fcmpset_acq_int atomic_fcmpset_acq_32
514 #define atomic_clear_acq_int atomic_clear_acq_32
515 #define atomic_cmpset_acq_int atomic_cmpset_acq_32
516 #define atomic_load_acq_int atomic_load_acq_32
517 #define atomic_set_acq_int atomic_set_acq_32
518 #define atomic_subtract_acq_int atomic_subtract_acq_32
520 #define atomic_add_rel_int atomic_add_rel_32
521 #define atomic_fcmpset_rel_int atomic_fcmpset_rel_32
522 #define atomic_clear_rel_int atomic_clear_rel_32
523 #define atomic_cmpset_rel_int atomic_cmpset_rel_32
524 #define atomic_set_rel_int atomic_set_rel_32
525 #define atomic_subtract_rel_int atomic_subtract_rel_32
526 #define atomic_store_rel_int atomic_store_rel_32
528 #define atomic_add_long atomic_add_64
529 #define atomic_fcmpset_long atomic_fcmpset_64
530 #define atomic_clear_long atomic_clear_64
531 #define atomic_cmpset_long atomic_cmpset_64
532 #define atomic_fetchadd_long atomic_fetchadd_64
533 #define atomic_readandclear_long atomic_readandclear_64
534 #define atomic_set_long atomic_set_64
535 #define atomic_swap_long atomic_swap_64
536 #define atomic_subtract_long atomic_subtract_64
538 #define atomic_add_ptr atomic_add_64
539 #define atomic_fcmpset_ptr atomic_fcmpset_64
540 #define atomic_clear_ptr atomic_clear_64
541 #define atomic_cmpset_ptr atomic_cmpset_64
542 #define atomic_fetchadd_ptr atomic_fetchadd_64
543 #define atomic_readandclear_ptr atomic_readandclear_64
544 #define atomic_set_ptr atomic_set_64
545 #define atomic_swap_ptr atomic_swap_64
546 #define atomic_subtract_ptr atomic_subtract_64
548 #define atomic_add_acq_long atomic_add_acq_64
549 #define atomic_fcmpset_acq_long atomic_fcmpset_acq_64
550 #define atomic_clear_acq_long atomic_clear_acq_64
551 #define atomic_cmpset_acq_long atomic_cmpset_acq_64
552 #define atomic_load_acq_long atomic_load_acq_64
553 #define atomic_set_acq_long atomic_set_acq_64
554 #define atomic_subtract_acq_long atomic_subtract_acq_64
556 #define atomic_add_acq_ptr atomic_add_acq_64
557 #define atomic_fcmpset_acq_ptr atomic_fcmpset_acq_64
558 #define atomic_clear_acq_ptr atomic_clear_acq_64
559 #define atomic_cmpset_acq_ptr atomic_cmpset_acq_64
560 #define atomic_load_acq_ptr atomic_load_acq_64
561 #define atomic_set_acq_ptr atomic_set_acq_64
562 #define atomic_subtract_acq_ptr atomic_subtract_acq_64
564 #define atomic_add_rel_long atomic_add_rel_64
565 #define atomic_fcmpset_rel_long atomic_fcmpset_rel_64
566 #define atomic_clear_rel_long atomic_clear_rel_64
567 #define atomic_cmpset_rel_long atomic_cmpset_rel_64
568 #define atomic_set_rel_long atomic_set_rel_64
569 #define atomic_subtract_rel_long atomic_subtract_rel_64
570 #define atomic_store_rel_long atomic_store_rel_64
572 #define atomic_add_rel_ptr atomic_add_rel_64
573 #define atomic_fcmpset_rel_ptr atomic_fcmpset_rel_64
574 #define atomic_clear_rel_ptr atomic_clear_rel_64
575 #define atomic_cmpset_rel_ptr atomic_cmpset_rel_64
576 #define atomic_set_rel_ptr atomic_set_rel_64
577 #define atomic_subtract_rel_ptr atomic_subtract_rel_64
578 #define atomic_store_rel_ptr atomic_store_rel_64
581 atomic_thread_fence_acq(void)
588 atomic_thread_fence_rel(void)
595 atomic_thread_fence_acq_rel(void)
602 atomic_thread_fence_seq_cst(void)
608 #endif /* KCSAN && !KCSAN_RUNTIME */
610 #endif /* _MACHINE_ATOMIC_H_ */