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 */
57 atomic_add_32(volatile uint32_t *p, uint32_t val)
63 "1: ldxr %w0, [%2] \n"
64 " add %w0, %w0, %w3 \n"
65 " stxr %w1, %w0, [%2] \n"
67 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc"
72 atomic_clear_32(volatile uint32_t *p, uint32_t val)
78 "1: ldxr %w0, [%2] \n"
79 " bic %w0, %w0, %w3 \n"
80 " stxr %w1, %w0, [%2] \n"
82 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc"
87 atomic_cmpset_32(volatile uint32_t *p, uint32_t cmpval, uint32_t newval)
97 " stxr %w1, %w4, [%2] \n"
100 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (cmpval), "+r" (newval)
107 static __inline uint32_t
108 atomic_fetchadd_32(volatile uint32_t *p, uint32_t val)
114 "1: ldxr %w4, [%2] \n"
115 " add %w0, %w4, %w3 \n"
116 " stxr %w1, %w0, [%2] \n"
118 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val), "=&r"(ret) : : "cc"
124 static __inline uint32_t
125 atomic_readandclear_32(volatile uint32_t *p)
132 "1: ldxr %w3, [%2] \n"
133 " stxr %w1, %w0, [%2] \n"
135 : "=&r"(tmp), "=&r"(res), "+r" (p), "=&r"(ret) : : "cc"
142 atomic_set_32(volatile uint32_t *p, uint32_t val)
148 "1: ldxr %w0, [%2] \n"
149 " orr %w0, %w0, %w3 \n"
150 " stxr %w1, %w0, [%2] \n"
152 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc"
157 atomic_subtract_32(volatile uint32_t *p, uint32_t val)
163 "1: ldxr %w0, [%2] \n"
164 " sub %w0, %w0, %w3 \n"
165 " stxr %w1, %w0, [%2] \n"
167 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc"
171 #define atomic_add_int atomic_add_32
172 #define atomic_clear_int atomic_clear_32
173 #define atomic_cmpset_int atomic_cmpset_32
174 #define atomic_fetchadd_int atomic_fetchadd_32
175 #define atomic_readandclear_int atomic_readandclear_32
176 #define atomic_set_int atomic_set_32
177 #define atomic_subtract_int atomic_subtract_32
180 atomic_add_acq_32(volatile uint32_t *p, uint32_t val)
186 "1: ldaxr %w0, [%2] \n"
187 " add %w0, %w0, %w3 \n"
188 " stxr %w1, %w0, [%2] \n"
191 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
196 atomic_clear_acq_32(volatile uint32_t *p, uint32_t val)
202 "1: ldaxr %w0, [%2] \n"
203 " bic %w0, %w0, %w3 \n"
204 " stxr %w1, %w0, [%2] \n"
206 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
211 atomic_cmpset_acq_32(volatile uint32_t *p, uint32_t cmpval, uint32_t newval)
218 " ldaxr %w0, [%2] \n"
221 " stxr %w1, %w4, [%2] \n"
224 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (cmpval), "+r" (newval)
231 static __inline uint32_t
232 atomic_load_acq_32(volatile uint32_t *p)
238 : "=&r" (ret) : "r" (p) : "memory");
244 atomic_set_acq_32(volatile uint32_t *p, uint32_t val)
250 "1: ldaxr %w0, [%2] \n"
251 " orr %w0, %w0, %w3 \n"
252 " stxr %w1, %w0, [%2] \n"
254 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
259 atomic_subtract_acq_32(volatile uint32_t *p, uint32_t val)
265 "1: ldaxr %w0, [%2] \n"
266 " sub %w0, %w0, %w3 \n"
267 " stxr %w1, %w0, [%2] \n"
269 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
273 #define atomic_add_acq_int atomic_add_acq_32
274 #define atomic_clear_acq_int atomic_clear_acq_32
275 #define atomic_cmpset_acq_int atomic_cmpset_acq_32
276 #define atomic_load_acq_int atomic_load_acq_32
277 #define atomic_set_acq_int atomic_set_acq_32
278 #define atomic_subtract_acq_int atomic_subtract_acq_32
280 /* The atomic functions currently are both acq and rel, we should fix this. */
283 atomic_add_rel_32(volatile uint32_t *p, uint32_t val)
289 "1: ldxr %w0, [%2] \n"
290 " add %w0, %w0, %w3 \n"
291 " stlxr %w1, %w0, [%2] \n"
294 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
299 atomic_clear_rel_32(volatile uint32_t *p, uint32_t val)
305 "1: ldxr %w0, [%2] \n"
306 " bic %w0, %w0, %w3 \n"
307 " stlxr %w1, %w0, [%2] \n"
309 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
314 atomic_cmpset_rel_32(volatile uint32_t *p, uint32_t cmpval, uint32_t newval)
324 " stlxr %w1, %w4, [%2] \n"
327 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (cmpval), "+r" (newval)
335 atomic_set_rel_32(volatile uint32_t *p, uint32_t val)
341 "1: ldxr %w0, [%2] \n"
342 " orr %w0, %w0, %w3 \n"
343 " stlxr %w1, %w0, [%2] \n"
345 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
350 atomic_store_rel_32(volatile uint32_t *p, uint32_t val)
355 : : "r" (val), "r" (p) : "memory");
359 atomic_subtract_rel_32(volatile uint32_t *p, uint32_t val)
365 "1: ldxr %w0, [%2] \n"
366 " sub %w0, %w0, %w3 \n"
367 " stlxr %w1, %w0, [%2] \n"
369 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
373 #define atomic_add_rel_int atomic_add_rel_32
374 #define atomic_clear_rel_int atomic_add_rel_32
375 #define atomic_cmpset_rel_int atomic_cmpset_rel_32
376 #define atomic_set_rel_int atomic_set_rel_32
377 #define atomic_subtract_rel_int atomic_subtract_rel_32
378 #define atomic_store_rel_int atomic_store_rel_32
382 atomic_add_64(volatile uint64_t *p, uint64_t val)
388 "1: ldxr %0, [%2] \n"
390 " stxr %w1, %0, [%2] \n"
392 : "=&r" (tmp), "=&r" (res), "+r" (p), "+r" (val) : : "cc"
397 atomic_clear_64(volatile uint64_t *p, uint64_t val)
403 "1: ldxr %0, [%2] \n"
405 " stxr %w1, %0, [%2] \n"
407 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc"
412 atomic_cmpset_64(volatile uint64_t *p, uint64_t cmpval, uint64_t newval)
422 " stxr %w1, %4, [%2] \n"
425 : "=&r" (tmp), "=&r"(res), "+r" (p), "+r" (cmpval), "+r" (newval)
432 static __inline uint64_t
433 atomic_fetchadd_64(volatile uint64_t *p, uint64_t val)
439 "1: ldxr %4, [%2] \n"
441 " stxr %w1, %0, [%2] \n"
443 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val), "=&r"(ret) : : "cc"
449 static __inline uint64_t
450 atomic_readandclear_64(volatile uint64_t *p)
457 "1: ldxr %3, [%2] \n"
458 " stxr %w1, %0, [%2] \n"
460 : "=&r"(tmp), "=&r"(res), "+r" (p), "=&r"(ret) : : "cc"
467 atomic_set_64(volatile uint64_t *p, uint64_t val)
473 "1: ldxr %0, [%2] \n"
475 " stxr %w1, %0, [%2] \n"
477 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc"
482 atomic_subtract_64(volatile uint64_t *p, uint64_t val)
488 "1: ldxr %0, [%2] \n"
490 " stxr %w1, %0, [%2] \n"
492 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc"
496 static __inline uint64_t
497 atomic_swap_64(volatile uint64_t *p, uint64_t val)
503 "1: ldxr %0, [%2] \n"
504 " stxr %w1, %3, [%2] \n"
506 : "=&r"(old), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
512 #define atomic_add_long atomic_add_64
513 #define atomic_clear_long atomic_clear_64
514 #define atomic_cmpset_long atomic_cmpset_64
515 #define atomic_fetchadd_long atomic_fetchadd_64
516 #define atomic_readandclear_long atomic_readandclear_64
517 #define atomic_set_long atomic_set_64
518 #define atomic_subtract_long atomic_subtract_64
520 #define atomic_add_ptr atomic_add_64
521 #define atomic_clear_ptr atomic_clear_64
522 #define atomic_cmpset_ptr atomic_cmpset_64
523 #define atomic_fetchadd_ptr atomic_fetchadd_64
524 #define atomic_readandclear_ptr atomic_readandclear_64
525 #define atomic_set_ptr atomic_set_64
526 #define atomic_subtract_ptr atomic_subtract_64
529 atomic_add_acq_64(volatile uint64_t *p, uint64_t val)
535 "1: ldaxr %0, [%2] \n"
537 " stxr %w1, %0, [%2] \n"
540 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
545 atomic_clear_acq_64(volatile uint64_t *p, uint64_t val)
551 "1: ldaxr %0, [%2] \n"
553 " stxr %w1, %0, [%2] \n"
555 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
560 atomic_cmpset_acq_64(volatile uint64_t *p, uint64_t cmpval, uint64_t newval)
570 " stxr %w1, %4, [%2] \n"
573 : "=&r" (tmp), "=&r" (res), "+r" (p), "+r" (cmpval), "+r" (newval)
580 static __inline uint64_t
581 atomic_load_acq_64(volatile uint64_t *p)
587 : "=&r" (ret) : "r" (p) : "memory");
593 atomic_set_acq_64(volatile uint64_t *p, uint64_t val)
599 "1: ldaxr %0, [%2] \n"
601 " stxr %w1, %0, [%2] \n"
603 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
608 atomic_subtract_acq_64(volatile uint64_t *p, uint64_t val)
614 "1: ldaxr %0, [%2] \n"
616 " stxr %w1, %0, [%2] \n"
618 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
622 #define atomic_add_acq_long atomic_add_acq_64
623 #define atomic_clear_acq_long atomic_add_acq_64
624 #define atomic_cmpset_acq_long atomic_cmpset_acq_64
625 #define atomic_load_acq_long atomic_load_acq_64
626 #define atomic_set_acq_long atomic_set_acq_64
627 #define atomic_subtract_acq_long atomic_subtract_acq_64
629 #define atomic_add_acq_ptr atomic_add_acq_64
630 #define atomic_clear_acq_ptr atomic_add_acq_64
631 #define atomic_cmpset_acq_ptr atomic_cmpset_acq_64
632 #define atomic_load_acq_ptr atomic_load_acq_64
633 #define atomic_set_acq_ptr atomic_set_acq_64
634 #define atomic_subtract_acq_ptr atomic_subtract_acq_64
637 * TODO: The atomic functions currently are both acq and rel, we should fix
641 atomic_add_rel_64(volatile uint64_t *p, uint64_t val)
647 "1: ldxr %0, [%2] \n"
649 " stlxr %w1, %0, [%2] \n"
652 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
657 atomic_clear_rel_64(volatile uint64_t *p, uint64_t val)
663 "1: ldxr %0, [%2] \n"
665 " stlxr %w1, %0, [%2] \n"
667 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
672 atomic_cmpset_rel_64(volatile uint64_t *p, uint64_t cmpval, uint64_t newval)
682 " stlxr %w1, %4, [%2] \n"
685 : "=&r" (tmp), "=&r" (res), "+r" (p), "+r" (cmpval), "+r" (newval)
693 atomic_set_rel_64(volatile uint64_t *p, uint64_t val)
699 "1: ldxr %0, [%2] \n"
701 " stlxr %w1, %0, [%2] \n"
703 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
708 atomic_store_rel_64(volatile uint64_t *p, uint64_t val)
713 : : "r" (val), "r" (p) : "memory");
717 atomic_subtract_rel_64(volatile uint64_t *p, uint64_t val)
723 "1: ldxr %0, [%2] \n"
725 " stlxr %w1, %0, [%2] \n"
727 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
732 atomic_thread_fence_acq(void)
739 atomic_thread_fence_rel(void)
746 atomic_thread_fence_acq_rel(void)
753 atomic_thread_fence_seq_cst(void)
759 #define atomic_add_rel_long atomic_add_rel_64
760 #define atomic_clear_rel_long atomic_clear_rel_64
761 #define atomic_cmpset_rel_long atomic_cmpset_rel_64
762 #define atomic_set_rel_long atomic_set_rel_64
763 #define atomic_subtract_rel_long atomic_subtract_rel_64
764 #define atomic_store_rel_long atomic_store_rel_64
766 #define atomic_add_rel_ptr atomic_add_rel_64
767 #define atomic_clear_rel_ptr atomic_clear_rel_64
768 #define atomic_cmpset_rel_ptr atomic_cmpset_rel_64
769 #define atomic_set_rel_ptr atomic_set_rel_64
770 #define atomic_subtract_rel_ptr atomic_subtract_rel_64
771 #define atomic_store_rel_ptr atomic_store_rel_64
773 #endif /* _MACHINE_ATOMIC_H_ */