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")
33 #define dsb() __asm __volatile("dsb sy" : : : "memory")
34 #define dmb() __asm __volatile("dmb sy" : : : "memory")
41 atomic_add_32(volatile uint32_t *p, uint32_t val)
47 "1: ldxr %w0, [%2] \n"
48 " add %w0, %w0, %w3 \n"
49 " stxr %w1, %w0, [%2] \n"
51 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc"
56 atomic_clear_32(volatile uint32_t *p, uint32_t val)
62 "1: ldxr %w0, [%2] \n"
63 " bic %w0, %w0, %w3 \n"
64 " stxr %w1, %w0, [%2] \n"
66 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc"
71 atomic_cmpset_32(volatile uint32_t *p, uint32_t cmpval, uint32_t newval)
81 " stxr %w1, %w4, [%2] \n"
84 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (cmpval), "+r" (newval)
91 static __inline uint32_t
92 atomic_fetchadd_32(volatile uint32_t *p, uint32_t val)
98 "1: ldxr %w4, [%2] \n"
99 " add %w0, %w4, %w3 \n"
100 " stxr %w1, %w0, [%2] \n"
102 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val), "=&r"(ret) : : "cc"
108 static __inline uint32_t
109 atomic_readandclear_32(volatile uint32_t *p)
116 "1: ldxr %w3, [%2] \n"
117 " stxr %w1, %w0, [%2] \n"
119 : "=&r"(tmp), "=&r"(res), "+r" (p), "=&r"(ret) : : "cc"
126 atomic_set_32(volatile uint32_t *p, uint32_t val)
132 "1: ldxr %w0, [%2] \n"
133 " orr %w0, %w0, %w3 \n"
134 " stxr %w1, %w0, [%2] \n"
136 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc"
141 atomic_subtract_32(volatile uint32_t *p, uint32_t val)
147 "1: ldxr %w0, [%2] \n"
148 " sub %w0, %w0, %w3 \n"
149 " stxr %w1, %w0, [%2] \n"
151 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc"
155 #define atomic_add_int atomic_add_32
156 #define atomic_clear_int atomic_clear_32
157 #define atomic_cmpset_int atomic_cmpset_32
158 #define atomic_fetchadd_int atomic_fetchadd_32
159 #define atomic_readandclear_int atomic_readandclear_32
160 #define atomic_set_int atomic_set_32
161 #define atomic_subtract_int atomic_subtract_32
164 atomic_add_acq_32(volatile uint32_t *p, uint32_t val)
170 "1: ldaxr %w0, [%2] \n"
171 " add %w0, %w0, %w3 \n"
172 " stxr %w1, %w0, [%2] \n"
175 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
180 atomic_clear_acq_32(volatile uint32_t *p, uint32_t val)
186 "1: ldaxr %w0, [%2] \n"
187 " bic %w0, %w0, %w3 \n"
188 " stxr %w1, %w0, [%2] \n"
190 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
195 atomic_cmpset_acq_32(volatile uint32_t *p, uint32_t cmpval, uint32_t newval)
202 " ldaxr %w0, [%2] \n"
205 " stxr %w1, %w4, [%2] \n"
208 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (cmpval), "+r" (newval)
215 static __inline uint32_t
216 atomic_load_acq_32(volatile uint32_t *p)
222 : "=&r" (ret) : "r" (p) : "memory");
228 atomic_set_acq_32(volatile uint32_t *p, uint32_t val)
234 "1: ldaxr %w0, [%2] \n"
235 " orr %w0, %w0, %w3 \n"
236 " stxr %w1, %w0, [%2] \n"
238 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
243 atomic_subtract_acq_32(volatile uint32_t *p, uint32_t val)
249 "1: ldaxr %w0, [%2] \n"
250 " sub %w0, %w0, %w3 \n"
251 " stxr %w1, %w0, [%2] \n"
253 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
257 #define atomic_add_acq_int atomic_add_acq_32
258 #define atomic_clear_acq_int atomic_clear_acq_32
259 #define atomic_cmpset_acq_int atomic_cmpset_acq_32
260 #define atomic_load_acq_int atomic_load_acq_32
261 #define atomic_set_acq_int atomic_set_acq_32
262 #define atomic_subtract_acq_int atomic_subtract_acq_32
264 /* The atomic functions currently are both acq and rel, we should fix this. */
267 atomic_add_rel_32(volatile uint32_t *p, uint32_t val)
273 "1: ldxr %w0, [%2] \n"
274 " add %w0, %w0, %w3 \n"
275 " stlxr %w1, %w0, [%2] \n"
278 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
283 atomic_clear_rel_32(volatile uint32_t *p, uint32_t val)
289 "1: ldxr %w0, [%2] \n"
290 " bic %w0, %w0, %w3 \n"
291 " stlxr %w1, %w0, [%2] \n"
293 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
298 atomic_cmpset_rel_32(volatile uint32_t *p, uint32_t cmpval, uint32_t newval)
308 " stlxr %w1, %w4, [%2] \n"
311 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (cmpval), "+r" (newval)
319 atomic_set_rel_32(volatile uint32_t *p, uint32_t val)
325 "1: ldxr %w0, [%2] \n"
326 " orr %w0, %w0, %w3 \n"
327 " stlxr %w1, %w0, [%2] \n"
329 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
334 atomic_store_rel_32(volatile uint32_t *p, uint32_t val)
339 : : "r" (val), "r" (p) : "memory");
343 atomic_subtract_rel_32(volatile uint32_t *p, uint32_t val)
349 "1: ldxr %w0, [%2] \n"
350 " sub %w0, %w0, %w3 \n"
351 " stlxr %w1, %w0, [%2] \n"
353 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
357 #define atomic_add_rel_int atomic_add_rel_32
358 #define atomic_clear_rel_int atomic_add_rel_32
359 #define atomic_cmpset_rel_int atomic_cmpset_rel_32
360 #define atomic_set_rel_int atomic_set_rel_32
361 #define atomic_subtract_rel_int atomic_subtract_rel_32
362 #define atomic_store_rel_int atomic_store_rel_32
366 atomic_add_64(volatile uint64_t *p, uint64_t val)
372 "1: ldxr %0, [%2] \n"
374 " stxr %w1, %0, [%2] \n"
376 : "=&r" (tmp), "=&r" (res), "+r" (p), "+r" (val) : : "cc"
381 atomic_clear_64(volatile uint64_t *p, uint64_t val)
387 "1: ldxr %0, [%2] \n"
389 " stxr %w1, %0, [%2] \n"
391 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc"
396 atomic_cmpset_64(volatile uint64_t *p, uint64_t cmpval, uint64_t newval)
406 " stxr %w1, %4, [%2] \n"
409 : "=&r" (tmp), "=&r"(res), "+r" (p), "+r" (cmpval), "+r" (newval)
416 static __inline uint64_t
417 atomic_fetchadd_64(volatile uint64_t *p, uint64_t val)
423 "1: ldxr %4, [%2] \n"
425 " stxr %w1, %0, [%2] \n"
427 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val), "=&r"(ret) : : "cc"
433 static __inline uint64_t
434 atomic_readandclear_64(volatile uint64_t *p)
441 "1: ldxr %3, [%2] \n"
442 " stxr %w1, %0, [%2] \n"
444 : "=&r"(tmp), "=&r"(res), "+r" (p), "=&r"(ret) : : "cc"
451 atomic_set_64(volatile uint64_t *p, uint64_t val)
457 "1: ldxr %0, [%2] \n"
459 " stxr %w1, %0, [%2] \n"
461 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc"
466 atomic_subtract_64(volatile uint64_t *p, uint64_t val)
472 "1: ldxr %0, [%2] \n"
474 " stxr %w1, %0, [%2] \n"
476 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc"
480 static __inline uint64_t
481 atomic_swap_64(volatile uint64_t *p, uint64_t val)
487 "1: ldxr %0, [%2] \n"
488 " stxr %w1, %3, [%2] \n"
490 : "=&r"(old), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
496 #define atomic_add_long atomic_add_64
497 #define atomic_clear_long atomic_clear_64
498 #define atomic_cmpset_long atomic_cmpset_64
499 #define atomic_fetchadd_long atomic_fetchadd_64
500 #define atomic_readandclear_long atomic_readandclear_64
501 #define atomic_set_long atomic_set_64
502 #define atomic_subtract_long atomic_subtract_64
504 #define atomic_add_ptr atomic_add_64
505 #define atomic_clear_ptr atomic_clear_64
506 #define atomic_cmpset_ptr atomic_cmpset_64
507 #define atomic_fetchadd_ptr atomic_fetchadd_64
508 #define atomic_readandclear_ptr atomic_readandclear_64
509 #define atomic_set_ptr atomic_set_64
510 #define atomic_subtract_ptr atomic_subtract_64
513 atomic_add_acq_64(volatile uint64_t *p, uint64_t val)
519 "1: ldaxr %0, [%2] \n"
521 " stxr %w1, %0, [%2] \n"
524 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
529 atomic_clear_acq_64(volatile uint64_t *p, uint64_t val)
535 "1: ldaxr %0, [%2] \n"
537 " stxr %w1, %0, [%2] \n"
539 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
544 atomic_cmpset_acq_64(volatile uint64_t *p, uint64_t cmpval, uint64_t newval)
554 " stxr %w1, %4, [%2] \n"
557 : "=&r" (tmp), "=&r" (res), "+r" (p), "+r" (cmpval), "+r" (newval)
564 static __inline uint64_t
565 atomic_load_acq_64(volatile uint64_t *p)
571 : "=&r" (ret) : "r" (p) : "memory");
577 atomic_set_acq_64(volatile uint64_t *p, uint64_t val)
583 "1: ldaxr %0, [%2] \n"
585 " stxr %w1, %0, [%2] \n"
587 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
592 atomic_subtract_acq_64(volatile uint64_t *p, uint64_t val)
598 "1: ldaxr %0, [%2] \n"
600 " stxr %w1, %0, [%2] \n"
602 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
606 #define atomic_add_acq_long atomic_add_acq_64
607 #define atomic_clear_acq_long atomic_add_acq_64
608 #define atomic_cmpset_acq_long atomic_cmpset_acq_64
609 #define atomic_load_acq_long atomic_load_acq_64
610 #define atomic_set_acq_long atomic_set_acq_64
611 #define atomic_subtract_acq_long atomic_subtract_acq_64
613 #define atomic_add_acq_ptr atomic_add_acq_64
614 #define atomic_clear_acq_ptr atomic_add_acq_64
615 #define atomic_cmpset_acq_ptr atomic_cmpset_acq_64
616 #define atomic_load_acq_ptr atomic_load_acq_64
617 #define atomic_set_acq_ptr atomic_set_acq_64
618 #define atomic_subtract_acq_ptr atomic_subtract_acq_64
621 * TODO: The atomic functions currently are both acq and rel, we should fix
625 atomic_add_rel_64(volatile uint64_t *p, uint64_t val)
631 "1: ldxr %0, [%2] \n"
633 " stlxr %w1, %0, [%2] \n"
636 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
641 atomic_clear_rel_64(volatile uint64_t *p, uint64_t val)
647 "1: ldxr %0, [%2] \n"
649 " stlxr %w1, %0, [%2] \n"
651 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
656 atomic_cmpset_rel_64(volatile uint64_t *p, uint64_t cmpval, uint64_t newval)
666 " stlxr %w1, %4, [%2] \n"
669 : "=&r" (tmp), "=&r" (res), "+r" (p), "+r" (cmpval), "+r" (newval)
677 atomic_set_rel_64(volatile uint64_t *p, uint64_t val)
683 "1: ldxr %0, [%2] \n"
685 " stlxr %w1, %0, [%2] \n"
687 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
692 atomic_store_rel_64(volatile uint64_t *p, uint64_t val)
697 : : "r" (val), "r" (p) : "memory");
701 atomic_subtract_rel_64(volatile uint64_t *p, uint64_t val)
707 "1: ldxr %0, [%2] \n"
709 " stlxr %w1, %0, [%2] \n"
711 : "=&r"(tmp), "=&r"(res), "+r" (p), "+r" (val) : : "cc", "memory"
715 #define atomic_add_rel_long atomic_add_rel_64
716 #define atomic_clear_rel_long atomic_clear_rel_64
717 #define atomic_cmpset_rel_long atomic_cmpset_rel_64
718 #define atomic_set_rel_long atomic_set_rel_64
719 #define atomic_subtract_rel_long atomic_subtract_rel_64
720 #define atomic_store_rel_long atomic_store_rel_64
722 #define atomic_add_rel_ptr atomic_add_rel_64
723 #define atomic_clear_rel_ptr atomic_clear_rel_64
724 #define atomic_cmpset_rel_ptr atomic_cmpset_rel_64
725 #define atomic_set_rel_ptr atomic_set_rel_64
726 #define atomic_subtract_rel_ptr atomic_subtract_rel_64
727 #define atomic_store_rel_ptr atomic_store_rel_64
729 #endif /* _MACHINE_ATOMIC_H_ */