1*8c1f099fSmpi /* $OpenBSD: atomic.h,v 1.15 2017/07/04 09:00:12 mpi Exp $ */
29d2a4093Sart /*
39d2a4093Sart * Copyright (c) 2007 Artur Grabowski <art@openbsd.org>
49d2a4093Sart *
59d2a4093Sart * Permission to use, copy, modify, and distribute this software for any
69d2a4093Sart * purpose with or without fee is hereby granted, provided that the above
79d2a4093Sart * copyright notice and this permission notice appear in all copies.
89d2a4093Sart *
99d2a4093Sart * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
109d2a4093Sart * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
119d2a4093Sart * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
129d2a4093Sart * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
139d2a4093Sart * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
149d2a4093Sart * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
159d2a4093Sart * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
169d2a4093Sart */
17f57756c9Sart
182fa72412Spirofti #ifndef _MACHINE_ATOMIC_H_
192fa72412Spirofti #define _MACHINE_ATOMIC_H_
20f57756c9Sart
215edb0f83Sdlg static inline unsigned int
_atomic_cas_uint(volatile unsigned int * p,unsigned int e,unsigned int n)225edb0f83Sdlg _atomic_cas_uint(volatile unsigned int *p, unsigned int e, unsigned int n)
23f57756c9Sart {
242df76cc2Sguenther __asm volatile("cas [%2], %3, %0"
255edb0f83Sdlg : "+r" (n), "=m" (*p)
265edb0f83Sdlg : "r" (p), "r" (e), "m" (*p));
279d2a4093Sart
285edb0f83Sdlg return (n);
29f57756c9Sart }
305edb0f83Sdlg #define atomic_cas_uint(_p, _e, _n) _atomic_cas_uint((_p), (_e), (_n))
31f57756c9Sart
325edb0f83Sdlg static inline unsigned long
_atomic_cas_ulong(volatile unsigned long * p,unsigned long e,unsigned long n)335edb0f83Sdlg _atomic_cas_ulong(volatile unsigned long *p, unsigned long e, unsigned long n)
34d40386ccSkettenis {
352df76cc2Sguenther __asm volatile("casx [%2], %3, %0"
365edb0f83Sdlg : "+r" (n), "=m" (*p)
375edb0f83Sdlg : "r" (p), "r" (e), "m" (*p));
38d40386ccSkettenis
395edb0f83Sdlg return (n);
40d40386ccSkettenis }
415edb0f83Sdlg #define atomic_cas_ulong(_p, _e, _n) _atomic_cas_ulong((_p), (_e), (_n))
425edb0f83Sdlg
435edb0f83Sdlg static inline void *
_atomic_cas_ptr(volatile void * p,void * e,void * n)44b6a8cdecSdlg _atomic_cas_ptr(volatile void *p, void *e, void *n)
455edb0f83Sdlg {
462df76cc2Sguenther __asm volatile("casx [%2], %3, %0"
47b6a8cdecSdlg : "+r" (n), "=m" (*(volatile unsigned long *)p)
48b6a8cdecSdlg : "r" (p), "r" (e), "m" (*(volatile unsigned long *)p));
495edb0f83Sdlg
505edb0f83Sdlg return (n);
515edb0f83Sdlg }
525edb0f83Sdlg #define atomic_cas_ptr(_p, _e, _n) _atomic_cas_ptr((_p), (_e), (_n))
535edb0f83Sdlg
54*8c1f099fSmpi #define _def_atomic_swap(_f, _t, _c) \
555edb0f83Sdlg static inline _t \
565edb0f83Sdlg _f(volatile _t *p, _t v) \
575edb0f83Sdlg { \
585edb0f83Sdlg _t e; \
595edb0f83Sdlg _t r; \
605edb0f83Sdlg \
615edb0f83Sdlg r = (_t)*p; \
625edb0f83Sdlg do { \
635edb0f83Sdlg e = r; \
645edb0f83Sdlg r = _c(p, e, v); \
655edb0f83Sdlg } while (r != e); \
665edb0f83Sdlg \
675edb0f83Sdlg return (r); \
685edb0f83Sdlg }
695edb0f83Sdlg
_def_atomic_swap(_atomic_swap_uint,unsigned int,atomic_cas_uint)70*8c1f099fSmpi _def_atomic_swap(_atomic_swap_uint, unsigned int, atomic_cas_uint)
71*8c1f099fSmpi _def_atomic_swap(_atomic_swap_ulong, unsigned long, atomic_cas_ulong)
72*8c1f099fSmpi #undef _def_atomic_swap
735edb0f83Sdlg
747be48f09Sdlg static inline void *
757be48f09Sdlg _atomic_swap_ptr(volatile void *p, void *v)
767be48f09Sdlg {
777be48f09Sdlg void *e, *r;
787be48f09Sdlg
797be48f09Sdlg r = *(void **)p;
807be48f09Sdlg do {
817be48f09Sdlg e = r;
827be48f09Sdlg r = atomic_cas_ptr(p, e, v);
837be48f09Sdlg } while (r != e);
847be48f09Sdlg
857be48f09Sdlg return (r);
867be48f09Sdlg }
877be48f09Sdlg
885edb0f83Sdlg #define atomic_swap_uint(_p, _v) _atomic_swap_uint(_p, _v)
895edb0f83Sdlg #define atomic_swap_ulong(_p, _v) _atomic_swap_ulong(_p, _v)
905edb0f83Sdlg #define atomic_swap_ptr(_p, _v) _atomic_swap_ptr(_p, _v)
915edb0f83Sdlg
92*8c1f099fSmpi #define _def_atomic_op_nv(_f, _t, _c, _op) \
935edb0f83Sdlg static inline _t \
945edb0f83Sdlg _f(volatile _t *p, _t v) \
955edb0f83Sdlg { \
965edb0f83Sdlg _t e, r, f; \
975edb0f83Sdlg \
985edb0f83Sdlg r = *p; \
995edb0f83Sdlg do { \
1005edb0f83Sdlg e = r; \
1015edb0f83Sdlg f = e _op v; \
1025edb0f83Sdlg r = _c(p, e, f); \
1035edb0f83Sdlg } while (r != e); \
1045edb0f83Sdlg \
1055edb0f83Sdlg return (f); \
1065edb0f83Sdlg }
1075edb0f83Sdlg
108*8c1f099fSmpi _def_atomic_op_nv(_atomic_add_int_nv, unsigned int, atomic_cas_uint, +)
109*8c1f099fSmpi _def_atomic_op_nv(_atomic_add_long_nv, unsigned long, atomic_cas_ulong, +)
110*8c1f099fSmpi _def_atomic_op_nv(_atomic_sub_int_nv, unsigned int, atomic_cas_uint, -)
111*8c1f099fSmpi _def_atomic_op_nv(_atomic_sub_long_nv, unsigned long, atomic_cas_ulong, -)
112*8c1f099fSmpi #undef _def_atomic_op_nv
1135edb0f83Sdlg
1145edb0f83Sdlg #define atomic_add_int_nv(_p, _v) _atomic_add_int_nv(_p, _v)
1155edb0f83Sdlg #define atomic_add_long_nv(_p, _v) _atomic_add_long_nv(_p, _v)
1165edb0f83Sdlg #define atomic_sub_int_nv(_p, _v) _atomic_sub_int_nv(_p, _v)
1175edb0f83Sdlg #define atomic_sub_long_nv(_p, _v) _atomic_sub_long_nv(_p, _v)
118d40386ccSkettenis
119*8c1f099fSmpi #define __membar(_m) __asm volatile("membar " _m ::: "memory")
120*8c1f099fSmpi
121*8c1f099fSmpi #define membar_enter() __membar("#StoreLoad|#StoreStore")
122*8c1f099fSmpi #define membar_exit() __membar("#LoadStore|#StoreStore")
123*8c1f099fSmpi #define membar_producer() __membar("#StoreStore")
124*8c1f099fSmpi #define membar_consumer() __membar("#LoadLoad")
125*8c1f099fSmpi #define membar_sync() __membar("#Sync")
126*8c1f099fSmpi
127*8c1f099fSmpi #if defined(_KERNEL)
128*8c1f099fSmpi
129f57756c9Sart static __inline void
atomic_setbits_int(volatile unsigned int * uip,unsigned int v)1309d2a4093Sart atomic_setbits_int(volatile unsigned int *uip, unsigned int v)
131f57756c9Sart {
1325edb0f83Sdlg unsigned int e, r;
1339d2a4093Sart
1349d2a4093Sart r = *uip;
1359d2a4093Sart do {
1369d2a4093Sart e = r;
1375edb0f83Sdlg r = atomic_cas_uint(uip, e, e | v);
1389d2a4093Sart } while (r != e);
1399d2a4093Sart }
1409d2a4093Sart
1419d2a4093Sart static __inline void
atomic_clearbits_int(volatile unsigned int * uip,unsigned int v)1429d2a4093Sart atomic_clearbits_int(volatile unsigned int *uip, unsigned int v)
1439d2a4093Sart {
1445edb0f83Sdlg unsigned int e, r;
1459d2a4093Sart
1469d2a4093Sart r = *uip;
1479d2a4093Sart do {
1489d2a4093Sart e = r;
1495edb0f83Sdlg r = atomic_cas_uint(uip, e, e & ~v);
1509d2a4093Sart } while (r != e);
151f57756c9Sart }
152f57756c9Sart
1538aa3ef09Sderaadt #endif /* defined(_KERNEL) */
1542fa72412Spirofti #endif /* _MACHINE_ATOMIC_H_ */
155