xref: /freebsd-src/sys/compat/linuxkpi/common/include/asm/atomic.h (revision 95ee2897e98f5d444f26ed2334cc7c439f9c16c6)
18d59ecb2SHans Petter Selasky /*-
28d59ecb2SHans Petter Selasky  * Copyright (c) 2010 Isilon Systems, Inc.
38d59ecb2SHans Petter Selasky  * Copyright (c) 2010 iX Systems, Inc.
48d59ecb2SHans Petter Selasky  * Copyright (c) 2010 Panasas, Inc.
5a76c73aaSHans Petter Selasky  * Copyright (c) 2013-2018 Mellanox Technologies, Ltd.
68d59ecb2SHans Petter Selasky  * All rights reserved.
78d59ecb2SHans Petter Selasky  *
88d59ecb2SHans Petter Selasky  * Redistribution and use in source and binary forms, with or without
98d59ecb2SHans Petter Selasky  * modification, are permitted provided that the following conditions
108d59ecb2SHans Petter Selasky  * are met:
118d59ecb2SHans Petter Selasky  * 1. Redistributions of source code must retain the above copyright
128d59ecb2SHans Petter Selasky  *    notice unmodified, this list of conditions, and the following
138d59ecb2SHans Petter Selasky  *    disclaimer.
148d59ecb2SHans Petter Selasky  * 2. Redistributions in binary form must reproduce the above copyright
158d59ecb2SHans Petter Selasky  *    notice, this list of conditions and the following disclaimer in the
168d59ecb2SHans Petter Selasky  *    documentation and/or other materials provided with the distribution.
178d59ecb2SHans Petter Selasky  *
188d59ecb2SHans Petter Selasky  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
198d59ecb2SHans Petter Selasky  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
208d59ecb2SHans Petter Selasky  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
218d59ecb2SHans Petter Selasky  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
228d59ecb2SHans Petter Selasky  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
238d59ecb2SHans Petter Selasky  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
248d59ecb2SHans Petter Selasky  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
258d59ecb2SHans Petter Selasky  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
268d59ecb2SHans Petter Selasky  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
278d59ecb2SHans Petter Selasky  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
288d59ecb2SHans Petter Selasky  */
29e5fe3ae2SMark Johnston 
30307f78f3SVladimir Kondratyev #ifndef _LINUXKPI_ASM_ATOMIC_H_
31307f78f3SVladimir Kondratyev #define	_LINUXKPI_ASM_ATOMIC_H_
328d59ecb2SHans Petter Selasky 
3362bae5d4SHans Petter Selasky #include <linux/compiler.h>
348d59ecb2SHans Petter Selasky #include <sys/types.h>
358d59ecb2SHans Petter Selasky #include <machine/atomic.h>
36fe68f570SHans Petter Selasky #define	ATOMIC_INIT(x)	{ .counter = (x) }
37fe68f570SHans Petter Selasky 
388d59ecb2SHans Petter Selasky typedef struct {
3929cbb3beSHans Petter Selasky 	volatile int counter;
408d59ecb2SHans Petter Selasky } atomic_t;
418d59ecb2SHans Petter Selasky 
4229cbb3beSHans Petter Selasky /*------------------------------------------------------------------------*
4329cbb3beSHans Petter Selasky  *	32-bit atomic operations
4429cbb3beSHans Petter Selasky  *------------------------------------------------------------------------*/
4529cbb3beSHans Petter Selasky 
468d59ecb2SHans Petter Selasky #define	atomic_add(i, v)		atomic_add_return((i), (v))
478d59ecb2SHans Petter Selasky #define	atomic_sub(i, v)		atomic_sub_return((i), (v))
488d59ecb2SHans Petter Selasky #define	atomic_inc_return(v)		atomic_add_return(1, (v))
498d59ecb2SHans Petter Selasky #define	atomic_add_negative(i, v)	(atomic_add_return((i), (v)) < 0)
5084577195SHans Petter Selasky #define	atomic_add_and_test(i, v)	(atomic_add_return((i), (v)) == 0)
518d59ecb2SHans Petter Selasky #define	atomic_sub_and_test(i, v)	(atomic_sub_return((i), (v)) == 0)
528d59ecb2SHans Petter Selasky #define	atomic_dec_and_test(v)		(atomic_sub_return(1, (v)) == 0)
538d59ecb2SHans Petter Selasky #define	atomic_inc_and_test(v)		(atomic_add_return(1, (v)) == 0)
548d59ecb2SHans Petter Selasky #define	atomic_dec_return(v)		atomic_sub_return(1, (v))
5529cbb3beSHans Petter Selasky #define	atomic_inc_not_zero(v)		atomic_add_unless((v), 1, 0)
568d59ecb2SHans Petter Selasky 
578d59ecb2SHans Petter Selasky static inline int
atomic_add_return(int i,atomic_t * v)588d59ecb2SHans Petter Selasky atomic_add_return(int i, atomic_t *v)
598d59ecb2SHans Petter Selasky {
608d59ecb2SHans Petter Selasky 	return i + atomic_fetchadd_int(&v->counter, i);
618d59ecb2SHans Petter Selasky }
628d59ecb2SHans Petter Selasky 
638d59ecb2SHans Petter Selasky static inline int
atomic_sub_return(int i,atomic_t * v)648d59ecb2SHans Petter Selasky atomic_sub_return(int i, atomic_t *v)
658d59ecb2SHans Petter Selasky {
668d59ecb2SHans Petter Selasky 	return atomic_fetchadd_int(&v->counter, -i) - i;
678d59ecb2SHans Petter Selasky }
688d59ecb2SHans Petter Selasky 
698d59ecb2SHans Petter Selasky static inline void
atomic_set(atomic_t * v,int i)708d59ecb2SHans Petter Selasky atomic_set(atomic_t *v, int i)
718d59ecb2SHans Petter Selasky {
7262bae5d4SHans Petter Selasky 	WRITE_ONCE(v->counter, i);
738d59ecb2SHans Petter Selasky }
748d59ecb2SHans Petter Selasky 
7584577195SHans Petter Selasky static inline void
atomic_set_release(atomic_t * v,int i)76622f2291SHans Petter Selasky atomic_set_release(atomic_t *v, int i)
77622f2291SHans Petter Selasky {
78622f2291SHans Petter Selasky 	atomic_store_rel_int(&v->counter, i);
79622f2291SHans Petter Selasky }
80622f2291SHans Petter Selasky 
81622f2291SHans Petter Selasky static inline void
atomic_set_mask(unsigned int mask,atomic_t * v)8284577195SHans Petter Selasky atomic_set_mask(unsigned int mask, atomic_t *v)
8384577195SHans Petter Selasky {
8484577195SHans Petter Selasky 	atomic_set_int(&v->counter, mask);
8584577195SHans Petter Selasky }
8684577195SHans Petter Selasky 
878d59ecb2SHans Petter Selasky static inline int
atomic_read(const atomic_t * v)8828a04a26SHans Petter Selasky atomic_read(const atomic_t *v)
898d59ecb2SHans Petter Selasky {
9062bae5d4SHans Petter Selasky 	return READ_ONCE(v->counter);
918d59ecb2SHans Petter Selasky }
928d59ecb2SHans Petter Selasky 
938d59ecb2SHans Petter Selasky static inline int
atomic_inc(atomic_t * v)948d59ecb2SHans Petter Selasky atomic_inc(atomic_t *v)
958d59ecb2SHans Petter Selasky {
968d59ecb2SHans Petter Selasky 	return atomic_fetchadd_int(&v->counter, 1) + 1;
978d59ecb2SHans Petter Selasky }
988d59ecb2SHans Petter Selasky 
998d59ecb2SHans Petter Selasky static inline int
atomic_dec(atomic_t * v)1008d59ecb2SHans Petter Selasky atomic_dec(atomic_t *v)
1018d59ecb2SHans Petter Selasky {
1028d59ecb2SHans Petter Selasky 	return atomic_fetchadd_int(&v->counter, -1) - 1;
1038d59ecb2SHans Petter Selasky }
1048d59ecb2SHans Petter Selasky 
10529cbb3beSHans Petter Selasky static inline int
atomic_add_unless(atomic_t * v,int a,int u)10629cbb3beSHans Petter Selasky atomic_add_unless(atomic_t *v, int a, int u)
1078d59ecb2SHans Petter Selasky {
1086402bc3dSHans Petter Selasky 	int c = atomic_read(v);
10929cbb3beSHans Petter Selasky 
1108d59ecb2SHans Petter Selasky 	for (;;) {
11129cbb3beSHans Petter Selasky 		if (unlikely(c == u))
1128d59ecb2SHans Petter Selasky 			break;
1136402bc3dSHans Petter Selasky 		if (likely(atomic_fcmpset_int(&v->counter, &c, c + a)))
1148d59ecb2SHans Petter Selasky 			break;
1158d59ecb2SHans Petter Selasky 	}
11629cbb3beSHans Petter Selasky 	return (c != u);
1178d59ecb2SHans Petter Selasky }
1188d59ecb2SHans Petter Selasky 
119b9bf16adSHans Petter Selasky static inline int
atomic_fetch_add_unless(atomic_t * v,int a,int u)120b9bf16adSHans Petter Selasky atomic_fetch_add_unless(atomic_t *v, int a, int u)
121b9bf16adSHans Petter Selasky {
122b9bf16adSHans Petter Selasky 	int c = atomic_read(v);
123b9bf16adSHans Petter Selasky 
124b9bf16adSHans Petter Selasky 	for (;;) {
125b9bf16adSHans Petter Selasky 		if (unlikely(c == u))
126b9bf16adSHans Petter Selasky 			break;
127b9bf16adSHans Petter Selasky 		if (likely(atomic_fcmpset_int(&v->counter, &c, c + a)))
128b9bf16adSHans Petter Selasky 			break;
129b9bf16adSHans Petter Selasky 	}
130b9bf16adSHans Petter Selasky 	return (c);
131b9bf16adSHans Petter Selasky }
132b9bf16adSHans Petter Selasky 
13384577195SHans Petter Selasky static inline void
atomic_clear_mask(unsigned int mask,atomic_t * v)13484577195SHans Petter Selasky atomic_clear_mask(unsigned int mask, atomic_t *v)
13584577195SHans Petter Selasky {
13684577195SHans Petter Selasky 	atomic_clear_int(&v->counter, mask);
13784577195SHans Petter Selasky }
13884577195SHans Petter Selasky 
13984577195SHans Petter Selasky static inline int
atomic_xchg(atomic_t * v,int i)14084577195SHans Petter Selasky atomic_xchg(atomic_t *v, int i)
14184577195SHans Petter Selasky {
14284577195SHans Petter Selasky 	return (atomic_swap_int(&v->counter, i));
14384577195SHans Petter Selasky }
14484577195SHans Petter Selasky 
14584577195SHans Petter Selasky static inline int
atomic_cmpxchg(atomic_t * v,int old,int new)14684577195SHans Petter Selasky atomic_cmpxchg(atomic_t *v, int old, int new)
14784577195SHans Petter Selasky {
14884577195SHans Petter Selasky 	int ret = old;
14984577195SHans Petter Selasky 
15084577195SHans Petter Selasky 	for (;;) {
1516402bc3dSHans Petter Selasky 		if (atomic_fcmpset_int(&v->counter, &ret, new))
15284577195SHans Petter Selasky 			break;
15384577195SHans Petter Selasky 		if (ret != old)
15484577195SHans Petter Selasky 			break;
15584577195SHans Petter Selasky 	}
15684577195SHans Petter Selasky 	return (ret);
15784577195SHans Petter Selasky }
15884577195SHans Petter Selasky 
159e545f5a8SMarius Strobl #if defined(__amd64__) || defined(__arm64__) || defined(__i386__)
160a76c73aaSHans Petter Selasky #define	LINUXKPI_ATOMIC_8(...) __VA_ARGS__
161a76c73aaSHans Petter Selasky #define	LINUXKPI_ATOMIC_16(...) __VA_ARGS__
162a76c73aaSHans Petter Selasky #else
163a76c73aaSHans Petter Selasky #define	LINUXKPI_ATOMIC_8(...)
164a76c73aaSHans Petter Selasky #define	LINUXKPI_ATOMIC_16(...)
165a76c73aaSHans Petter Selasky #endif
166a76c73aaSHans Petter Selasky 
1679f6097d6SEd Maste #if !(defined(i386) || (defined(__powerpc__) && !defined(__powerpc64__)))
168a76c73aaSHans Petter Selasky #define	LINUXKPI_ATOMIC_64(...) __VA_ARGS__
169a76c73aaSHans Petter Selasky #else
170a76c73aaSHans Petter Selasky #define	LINUXKPI_ATOMIC_64(...)
171a76c73aaSHans Petter Selasky #endif
172a76c73aaSHans Petter Selasky 
17384577195SHans Petter Selasky #define	cmpxchg(ptr, old, new) ({					\
1742a7c2b91SHans Petter Selasky 	union {								\
1752a7c2b91SHans Petter Selasky 		__typeof(*(ptr)) val;					\
176af4010beSHans Petter Selasky 		u8 u8[0];						\
177af4010beSHans Petter Selasky 		u16 u16[0];						\
178af4010beSHans Petter Selasky 		u32 u32[0];						\
179af4010beSHans Petter Selasky 		u64 u64[0];						\
1802a7c2b91SHans Petter Selasky 	} __ret = { .val = (old) }, __new = { .val = (new) };		\
181e5fe3ae2SMark Johnston 									\
182a76c73aaSHans Petter Selasky 	CTASSERT(							\
183a76c73aaSHans Petter Selasky 	    LINUXKPI_ATOMIC_8(sizeof(__ret.val) == 1 ||)		\
184a76c73aaSHans Petter Selasky 	    LINUXKPI_ATOMIC_16(sizeof(__ret.val) == 2 ||)		\
185a76c73aaSHans Petter Selasky 	    LINUXKPI_ATOMIC_64(sizeof(__ret.val) == 8 ||)		\
186a76c73aaSHans Petter Selasky 	    sizeof(__ret.val) == 4);					\
187e5fe3ae2SMark Johnston 									\
1882a7c2b91SHans Petter Selasky 	switch (sizeof(__ret.val)) {					\
189a76c73aaSHans Petter Selasky 	LINUXKPI_ATOMIC_8(						\
190e5fe3ae2SMark Johnston 	case 1:								\
1912a7c2b91SHans Petter Selasky 		while (!atomic_fcmpset_8((volatile u8 *)(ptr),		\
1922a7c2b91SHans Petter Selasky 		    __ret.u8, __new.u8[0]) && __ret.val == (old))	\
193e5fe3ae2SMark Johnston 			;						\
19484577195SHans Petter Selasky 		break;							\
195a76c73aaSHans Petter Selasky 	)								\
196a76c73aaSHans Petter Selasky 	LINUXKPI_ATOMIC_16(						\
197e5fe3ae2SMark Johnston 	case 2:								\
1982a7c2b91SHans Petter Selasky 		while (!atomic_fcmpset_16((volatile u16 *)(ptr),	\
1992a7c2b91SHans Petter Selasky 		    __ret.u16, __new.u16[0]) && __ret.val == (old))	\
200e5fe3ae2SMark Johnston 			;						\
20184577195SHans Petter Selasky 		break;							\
202a76c73aaSHans Petter Selasky 	)								\
203e5fe3ae2SMark Johnston 	case 4:								\
2042a7c2b91SHans Petter Selasky 		while (!atomic_fcmpset_32((volatile u32 *)(ptr),	\
2052a7c2b91SHans Petter Selasky 		    __ret.u32, __new.u32[0]) && __ret.val == (old))	\
206e5fe3ae2SMark Johnston 			;						\
20784577195SHans Petter Selasky 		break;							\
208a76c73aaSHans Petter Selasky 	LINUXKPI_ATOMIC_64(						\
209e5fe3ae2SMark Johnston 	case 8:								\
2102a7c2b91SHans Petter Selasky 		while (!atomic_fcmpset_64((volatile u64 *)(ptr),	\
2112a7c2b91SHans Petter Selasky 		    __ret.u64, __new.u64[0]) && __ret.val == (old))	\
212e5fe3ae2SMark Johnston 			;						\
21384577195SHans Petter Selasky 		break;							\
214a76c73aaSHans Petter Selasky 	)								\
21584577195SHans Petter Selasky 	}								\
2162a7c2b91SHans Petter Selasky 	__ret.val;							\
217e5fe3ae2SMark Johnston })
218e5fe3ae2SMark Johnston 
219*e79a57d4SJean-Sébastien Pédron #define	cmpxchg64(...)		cmpxchg(__VA_ARGS__)
2208293738eSHans Petter Selasky #define	cmpxchg_relaxed(...)	cmpxchg(__VA_ARGS__)
221e5fe3ae2SMark Johnston 
22264468049SHans Petter Selasky #define	xchg(ptr, new) ({						\
22364468049SHans Petter Selasky 	union {								\
22464468049SHans Petter Selasky 		__typeof(*(ptr)) val;					\
22564468049SHans Petter Selasky 		u8 u8[0];						\
22664468049SHans Petter Selasky 		u16 u16[0];						\
22764468049SHans Petter Selasky 		u32 u32[0];						\
22864468049SHans Petter Selasky 		u64 u64[0];						\
2298f294983SHans Petter Selasky 	} __ret, __new = { .val = (new) };				\
230e5fe3ae2SMark Johnston 									\
231a76c73aaSHans Petter Selasky 	CTASSERT(							\
232a76c73aaSHans Petter Selasky 	    LINUXKPI_ATOMIC_8(sizeof(__ret.val) == 1 ||)		\
233a76c73aaSHans Petter Selasky 	    LINUXKPI_ATOMIC_16(sizeof(__ret.val) == 2 ||)		\
234a76c73aaSHans Petter Selasky 	    LINUXKPI_ATOMIC_64(sizeof(__ret.val) == 8 ||)		\
235a76c73aaSHans Petter Selasky 	    sizeof(__ret.val) == 4);					\
23664468049SHans Petter Selasky 									\
23764468049SHans Petter Selasky 	switch (sizeof(__ret.val)) {					\
238a76c73aaSHans Petter Selasky 	LINUXKPI_ATOMIC_8(						\
23964468049SHans Petter Selasky 	case 1:								\
2408f294983SHans Petter Selasky 		__ret.val = READ_ONCE(*ptr);				\
24164468049SHans Petter Selasky 		while (!atomic_fcmpset_8((volatile u8 *)(ptr),		\
24264468049SHans Petter Selasky 	            __ret.u8, __new.u8[0]))				\
24364468049SHans Petter Selasky 			;						\
24464468049SHans Petter Selasky 		break;							\
245a76c73aaSHans Petter Selasky 	)								\
246a76c73aaSHans Petter Selasky 	LINUXKPI_ATOMIC_16(						\
24764468049SHans Petter Selasky 	case 2:								\
2488f294983SHans Petter Selasky 		__ret.val = READ_ONCE(*ptr);				\
24964468049SHans Petter Selasky 		while (!atomic_fcmpset_16((volatile u16 *)(ptr),	\
25064468049SHans Petter Selasky 	            __ret.u16, __new.u16[0]))				\
25164468049SHans Petter Selasky 			;						\
25264468049SHans Petter Selasky 		break;							\
253a76c73aaSHans Petter Selasky 	)								\
25464468049SHans Petter Selasky 	case 4:								\
2558f294983SHans Petter Selasky 		__ret.u32[0] = atomic_swap_32((volatile u32 *)(ptr),	\
2568f294983SHans Petter Selasky 		    __new.u32[0]);					\
25764468049SHans Petter Selasky 		break;							\
258a76c73aaSHans Petter Selasky 	LINUXKPI_ATOMIC_64(						\
25964468049SHans Petter Selasky 	case 8:								\
2608f294983SHans Petter Selasky 		__ret.u64[0] = atomic_swap_64((volatile u64 *)(ptr),	\
2618f294983SHans Petter Selasky 		    __new.u64[0]);					\
26264468049SHans Petter Selasky 		break;							\
263a76c73aaSHans Petter Selasky 	)								\
26464468049SHans Petter Selasky 	}								\
26564468049SHans Petter Selasky 	__ret.val;							\
26684577195SHans Petter Selasky })
26784577195SHans Petter Selasky 
26839da3678SEmmanuel Vadot #define try_cmpxchg(p, op, n)							\
26939da3678SEmmanuel Vadot ({										\
27039da3678SEmmanuel Vadot 	__typeof(p) __op = (__typeof((p)))(op);					\
27139da3678SEmmanuel Vadot 	__typeof(*(p)) __o = *__op;						\
27239da3678SEmmanuel Vadot 	__typeof(*(p)) __p = __sync_val_compare_and_swap((p), (__o), (n));	\
27339da3678SEmmanuel Vadot 	if (__p != __o)								\
27439da3678SEmmanuel Vadot 		*__op = __p;							\
27539da3678SEmmanuel Vadot 	(__p == __o);								\
27639da3678SEmmanuel Vadot })
27739da3678SEmmanuel Vadot 
27839da3678SEmmanuel Vadot #define __atomic_try_cmpxchg(type, _p, _po, _n)		\
27939da3678SEmmanuel Vadot ({							\
28039da3678SEmmanuel Vadot 	__typeof(_po) __po = (_po);			\
28139da3678SEmmanuel Vadot 	__typeof(*(_po)) __r, __o = *__po;		\
28239da3678SEmmanuel Vadot 	__r = atomic_cmpxchg##type((_p), __o, (_n));	\
28339da3678SEmmanuel Vadot 	if (unlikely(__r != __o))			\
28439da3678SEmmanuel Vadot 		*__po = __r;				\
28539da3678SEmmanuel Vadot 	likely(__r == __o);				\
28639da3678SEmmanuel Vadot })
28739da3678SEmmanuel Vadot 
28839da3678SEmmanuel Vadot #define	atomic_try_cmpxchg(_p, _po, _n)	__atomic_try_cmpxchg(, _p, _po, _n)
28939da3678SEmmanuel Vadot 
29023dcf435SHans Petter Selasky static inline int
atomic_dec_if_positive(atomic_t * v)29123dcf435SHans Petter Selasky atomic_dec_if_positive(atomic_t *v)
29223dcf435SHans Petter Selasky {
29323dcf435SHans Petter Selasky 	int retval;
29417e2a84eSHans Petter Selasky 	int old;
29523dcf435SHans Petter Selasky 
29617e2a84eSHans Petter Selasky 	old = atomic_read(v);
29717e2a84eSHans Petter Selasky 	for (;;) {
29817e2a84eSHans Petter Selasky 		retval = old - 1;
29923dcf435SHans Petter Selasky 		if (unlikely(retval < 0))
30023dcf435SHans Petter Selasky 			break;
30117e2a84eSHans Petter Selasky 		if (likely(atomic_fcmpset_int(&v->counter, &old, retval)))
30217e2a84eSHans Petter Selasky 			break;
30317e2a84eSHans Petter Selasky 	}
30423dcf435SHans Petter Selasky 	return (retval);
30523dcf435SHans Petter Selasky }
30623dcf435SHans Petter Selasky 
30784577195SHans Petter Selasky #define	LINUX_ATOMIC_OP(op, c_op)				\
30884577195SHans Petter Selasky static inline void atomic_##op(int i, atomic_t *v)		\
30984577195SHans Petter Selasky {								\
31084577195SHans Petter Selasky 	int c, old;						\
31184577195SHans Petter Selasky 								\
31284577195SHans Petter Selasky 	c = v->counter;						\
31384577195SHans Petter Selasky 	while ((old = atomic_cmpxchg(v, c, c c_op i)) != c)	\
31484577195SHans Petter Selasky 		c = old;					\
31584577195SHans Petter Selasky }
31684577195SHans Petter Selasky 
317622f2291SHans Petter Selasky #define	LINUX_ATOMIC_FETCH_OP(op, c_op)				\
318622f2291SHans Petter Selasky static inline int atomic_fetch_##op(int i, atomic_t *v)		\
319622f2291SHans Petter Selasky {								\
320622f2291SHans Petter Selasky 	int c, old;						\
321622f2291SHans Petter Selasky 								\
322622f2291SHans Petter Selasky 	c = v->counter;						\
323622f2291SHans Petter Selasky 	while ((old = atomic_cmpxchg(v, c, c c_op i)) != c)	\
324622f2291SHans Petter Selasky 		c = old;					\
325622f2291SHans Petter Selasky 								\
326622f2291SHans Petter Selasky 	return (c);						\
327622f2291SHans Petter Selasky }
328622f2291SHans Petter Selasky 
3296be89cc8SEmmanuel Vadot static inline int
atomic_fetch_inc(atomic_t * v)3306be89cc8SEmmanuel Vadot atomic_fetch_inc(atomic_t *v)
3316be89cc8SEmmanuel Vadot {
3326be89cc8SEmmanuel Vadot 
3336be89cc8SEmmanuel Vadot 	return ((atomic_inc_return(v) - 1));
3346be89cc8SEmmanuel Vadot }
3356be89cc8SEmmanuel Vadot 
33684577195SHans Petter Selasky LINUX_ATOMIC_OP(or, |)
33784577195SHans Petter Selasky LINUX_ATOMIC_OP(and, &)
338622f2291SHans Petter Selasky LINUX_ATOMIC_OP(andnot, &~)
33984577195SHans Petter Selasky LINUX_ATOMIC_OP(xor, ^)
34084577195SHans Petter Selasky 
341622f2291SHans Petter Selasky LINUX_ATOMIC_FETCH_OP(or, |)
342622f2291SHans Petter Selasky LINUX_ATOMIC_FETCH_OP(and, &)
343622f2291SHans Petter Selasky LINUX_ATOMIC_FETCH_OP(andnot, &~)
344622f2291SHans Petter Selasky LINUX_ATOMIC_FETCH_OP(xor, ^)
345622f2291SHans Petter Selasky 
346307f78f3SVladimir Kondratyev #endif					/* _LINUXKPI_ASM_ATOMIC_H_ */
347