xref: /freebsd/sys/i386/include/atomic.h (revision 43bb1274d0e5c516a69a0b9c03d7273d7c9536c5)
1069e9bc1SDoug Rabson /*-
283ef78beSPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
383ef78beSPedro F. Giffuni  *
4069e9bc1SDoug Rabson  * Copyright (c) 1998 Doug Rabson
5069e9bc1SDoug Rabson  * All rights reserved.
6069e9bc1SDoug Rabson  *
7069e9bc1SDoug Rabson  * Redistribution and use in source and binary forms, with or without
8069e9bc1SDoug Rabson  * modification, are permitted provided that the following conditions
9069e9bc1SDoug Rabson  * are met:
10069e9bc1SDoug Rabson  * 1. Redistributions of source code must retain the above copyright
11069e9bc1SDoug Rabson  *    notice, this list of conditions and the following disclaimer.
12069e9bc1SDoug Rabson  * 2. Redistributions in binary form must reproduce the above copyright
13069e9bc1SDoug Rabson  *    notice, this list of conditions and the following disclaimer in the
14069e9bc1SDoug Rabson  *    documentation and/or other materials provided with the distribution.
15069e9bc1SDoug Rabson  *
16069e9bc1SDoug Rabson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17069e9bc1SDoug Rabson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18069e9bc1SDoug Rabson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19069e9bc1SDoug Rabson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20069e9bc1SDoug Rabson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21069e9bc1SDoug Rabson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22069e9bc1SDoug Rabson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23069e9bc1SDoug Rabson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24069e9bc1SDoug Rabson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25069e9bc1SDoug Rabson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26069e9bc1SDoug Rabson  * SUCH DAMAGE.
27069e9bc1SDoug Rabson  *
28c3aac50fSPeter Wemm  * $FreeBSD$
29069e9bc1SDoug Rabson  */
30069e9bc1SDoug Rabson #ifndef _MACHINE_ATOMIC_H_
31069e9bc1SDoug Rabson #define	_MACHINE_ATOMIC_H_
32069e9bc1SDoug Rabson 
33a5f50ef9SJoerg Wunsch #ifndef _SYS_CDEFS_H_
34a5f50ef9SJoerg Wunsch #error this file needs sys/cdefs.h as a prerequisite
35a5f50ef9SJoerg Wunsch #endif
36a5f50ef9SJoerg Wunsch 
3730d4f9e8SKonstantin Belousov #include <sys/atomic_common.h>
3830d4f9e8SKonstantin Belousov 
393264fd70SJung-uk Kim #ifdef _KERNEL
403264fd70SJung-uk Kim #include <machine/md_var.h>
413264fd70SJung-uk Kim #include <machine/specialreg.h>
423264fd70SJung-uk Kim #endif
433264fd70SJung-uk Kim 
4448cae112SKonstantin Belousov #ifndef __OFFSETOF_MONITORBUF
4548cae112SKonstantin Belousov /*
4648cae112SKonstantin Belousov  * __OFFSETOF_MONITORBUF == __pcpu_offset(pc_monitorbuf).
4748cae112SKonstantin Belousov  *
4848cae112SKonstantin Belousov  * The open-coded number is used instead of the symbolic expression to
4948cae112SKonstantin Belousov  * avoid a dependency on sys/pcpu.h in machine/atomic.h consumers.
5048cae112SKonstantin Belousov  * An assertion in i386/vm_machdep.c ensures that the value is correct.
5148cae112SKonstantin Belousov  */
5283c9dea1SGleb Smirnoff #define	__OFFSETOF_MONITORBUF	0x80
5348cae112SKonstantin Belousov 
5448cae112SKonstantin Belousov static __inline void
5548cae112SKonstantin Belousov __mbk(void)
5648cae112SKonstantin Belousov {
5748cae112SKonstantin Belousov 
5848cae112SKonstantin Belousov 	__asm __volatile("lock; addl $0,%%fs:%0"
5948cae112SKonstantin Belousov 	    : "+m" (*(u_int *)__OFFSETOF_MONITORBUF) : : "memory", "cc");
6048cae112SKonstantin Belousov }
6148cae112SKonstantin Belousov 
6248cae112SKonstantin Belousov static __inline void
6348cae112SKonstantin Belousov __mbu(void)
6448cae112SKonstantin Belousov {
6548cae112SKonstantin Belousov 
6648cae112SKonstantin Belousov 	__asm __volatile("lock; addl $0,(%%esp)" : : : "memory", "cc");
6748cae112SKonstantin Belousov }
6848cae112SKonstantin Belousov #endif
69db7f0b97SKip Macy 
70069e9bc1SDoug Rabson /*
71f28e1c8fSBruce Evans  * Various simple operations on memory, each of which is atomic in the
72f28e1c8fSBruce Evans  * presence of interrupts and multiple processors.
73069e9bc1SDoug Rabson  *
7447b8bc92SAlan Cox  * atomic_set_char(P, V)	(*(u_char *)(P) |= (V))
7547b8bc92SAlan Cox  * atomic_clear_char(P, V)	(*(u_char *)(P) &= ~(V))
7647b8bc92SAlan Cox  * atomic_add_char(P, V)	(*(u_char *)(P) += (V))
7747b8bc92SAlan Cox  * atomic_subtract_char(P, V)	(*(u_char *)(P) -= (V))
7847b8bc92SAlan Cox  *
7947b8bc92SAlan Cox  * atomic_set_short(P, V)	(*(u_short *)(P) |= (V))
8047b8bc92SAlan Cox  * atomic_clear_short(P, V)	(*(u_short *)(P) &= ~(V))
8147b8bc92SAlan Cox  * atomic_add_short(P, V)	(*(u_short *)(P) += (V))
8247b8bc92SAlan Cox  * atomic_subtract_short(P, V)	(*(u_short *)(P) -= (V))
8347b8bc92SAlan Cox  *
8447b8bc92SAlan Cox  * atomic_set_int(P, V)		(*(u_int *)(P) |= (V))
8547b8bc92SAlan Cox  * atomic_clear_int(P, V)	(*(u_int *)(P) &= ~(V))
8647b8bc92SAlan Cox  * atomic_add_int(P, V)		(*(u_int *)(P) += (V))
8747b8bc92SAlan Cox  * atomic_subtract_int(P, V)	(*(u_int *)(P) -= (V))
888a1ee2d3SJung-uk Kim  * atomic_swap_int(P, V)	(return (*(u_int *)(P)); *(u_int *)(P) = (V);)
89f28e1c8fSBruce Evans  * atomic_readandclear_int(P)	(return (*(u_int *)(P)); *(u_int *)(P) = 0;)
9047b8bc92SAlan Cox  *
9147b8bc92SAlan Cox  * atomic_set_long(P, V)	(*(u_long *)(P) |= (V))
9247b8bc92SAlan Cox  * atomic_clear_long(P, V)	(*(u_long *)(P) &= ~(V))
9347b8bc92SAlan Cox  * atomic_add_long(P, V)	(*(u_long *)(P) += (V))
9447b8bc92SAlan Cox  * atomic_subtract_long(P, V)	(*(u_long *)(P) -= (V))
958a1ee2d3SJung-uk Kim  * atomic_swap_long(P, V)	(return (*(u_long *)(P)); *(u_long *)(P) = (V);)
96f28e1c8fSBruce Evans  * atomic_readandclear_long(P)	(return (*(u_long *)(P)); *(u_long *)(P) = 0;)
97069e9bc1SDoug Rabson  */
98069e9bc1SDoug Rabson 
9947b8bc92SAlan Cox /*
10008c40841SAlan Cox  * The above functions are expanded inline in the statically-linked
10108c40841SAlan Cox  * kernel.  Lock prefixes are generated if an SMP kernel is being
10208c40841SAlan Cox  * built.
10308c40841SAlan Cox  *
10408c40841SAlan Cox  * Kernel modules call real functions which are built into the kernel.
10508c40841SAlan Cox  * This allows kernel modules to be portable between UP and SMP systems.
10647b8bc92SAlan Cox  */
10748281036SJohn Baldwin #if defined(KLD_MODULE) || !defined(__GNUCLIKE_ASM)
108e4e991e1SJohn Baldwin #define	ATOMIC_ASM(NAME, TYPE, OP, CONS, V)			\
10986d2e48cSAttilio Rao void atomic_##NAME##_##TYPE(volatile u_##TYPE *p, u_##TYPE v);	\
11086d2e48cSAttilio Rao void atomic_##NAME##_barr_##TYPE(volatile u_##TYPE *p, u_##TYPE v)
11108c40841SAlan Cox 
1123d673254SMark Johnston int	atomic_cmpset_char(volatile u_char *dst, u_char expect, u_char src);
1133d673254SMark Johnston int	atomic_cmpset_short(volatile u_short *dst, u_short expect, u_short src);
114065b12a7SPoul-Henning Kamp int	atomic_cmpset_int(volatile u_int *dst, u_int expect, u_int src);
1153d673254SMark Johnston int	atomic_fcmpset_char(volatile u_char *dst, u_char *expect, u_char src);
1163d673254SMark Johnston int	atomic_fcmpset_short(volatile u_short *dst, u_short *expect,
1173d673254SMark Johnston 	    u_short src);
118e7a98aefSMateusz Guzik int	atomic_fcmpset_int(volatile u_int *dst, u_int *expect, u_int src);
1193c2bc2bfSJohn Baldwin u_int	atomic_fetchadd_int(volatile u_int *p, u_int v);
1208a1ee2d3SJung-uk Kim int	atomic_testandset_int(volatile u_int *p, u_int v);
121dfdc9a05SSepherosa Ziehau int	atomic_testandclear_int(volatile u_int *p, u_int v);
1228954a9a4SKonstantin Belousov void	atomic_thread_fence_acq(void);
1238954a9a4SKonstantin Belousov void	atomic_thread_fence_acq_rel(void);
1248954a9a4SKonstantin Belousov void	atomic_thread_fence_rel(void);
1258954a9a4SKonstantin Belousov void	atomic_thread_fence_seq_cst(void);
126819e370cSPoul-Henning Kamp 
1277626d062SKonstantin Belousov #define	ATOMIC_LOAD(TYPE)					\
128fa9f322dSKonstantin Belousov u_##TYPE	atomic_load_acq_##TYPE(volatile u_##TYPE *p)
129fa9f322dSKonstantin Belousov #define	ATOMIC_STORE(TYPE)					\
1308306a37bSMark Murray void		atomic_store_rel_##TYPE(volatile u_##TYPE *p, u_##TYPE v)
1318a6b1c8fSJohn Baldwin 
1325188b5f3SJung-uk Kim int		atomic_cmpset_64(volatile uint64_t *, uint64_t, uint64_t);
1333264fd70SJung-uk Kim uint64_t	atomic_load_acq_64(volatile uint64_t *);
1343264fd70SJung-uk Kim void		atomic_store_rel_64(volatile uint64_t *, uint64_t);
1355188b5f3SJung-uk Kim uint64_t	atomic_swap_64(volatile uint64_t *, uint64_t);
136322f006eSHans Petter Selasky uint64_t	atomic_fetchadd_64(volatile uint64_t *, uint64_t);
137*43bb1274SHans Petter Selasky void		atomic_add_64(volatile uint64_t *, uint64_t);
138*43bb1274SHans Petter Selasky void		atomic_subtract_64(volatile uint64_t *, uint64_t);
1393264fd70SJung-uk Kim 
14048281036SJohn Baldwin #else /* !KLD_MODULE && __GNUCLIKE_ASM */
1414c5aee92SMark Murray 
1422a89a48fSJohn Baldwin /*
143f28e1c8fSBruce Evans  * For userland, always use lock prefixes so that the binaries will run
144f28e1c8fSBruce Evans  * on both SMP and !SMP systems.
1452a89a48fSJohn Baldwin  */
1462a89a48fSJohn Baldwin #if defined(SMP) || !defined(_KERNEL)
1477e4277e5SBruce Evans #define	MPLOCKED	"lock ; "
148d2f22d70SBruce Evans #else
14947b8bc92SAlan Cox #define	MPLOCKED
150d2f22d70SBruce Evans #endif
151069e9bc1SDoug Rabson 
15247b8bc92SAlan Cox /*
15386d2e48cSAttilio Rao  * The assembly is volatilized to avoid code chunk removal by the compiler.
15486d2e48cSAttilio Rao  * GCC aggressively reorders operations and memory clobbering is necessary
15586d2e48cSAttilio Rao  * in order to avoid that for memory barriers.
15647b8bc92SAlan Cox  */
157e4e991e1SJohn Baldwin #define	ATOMIC_ASM(NAME, TYPE, OP, CONS, V)		\
15847b8bc92SAlan Cox static __inline void					\
15903e3bc8eSAlan Cox atomic_##NAME##_##TYPE(volatile u_##TYPE *p, u_##TYPE v)\
16047b8bc92SAlan Cox {							\
1617e4277e5SBruce Evans 	__asm __volatile(MPLOCKED OP			\
162fe94be3dSJung-uk Kim 	: "+m" (*p)					\
163fe94be3dSJung-uk Kim 	: CONS (V)					\
1647222d2fbSKonstantin Belousov 	: "cc");					\
1656d800f89SBruce Evans }							\
16686d2e48cSAttilio Rao 							\
16786d2e48cSAttilio Rao static __inline void					\
16886d2e48cSAttilio Rao atomic_##NAME##_barr_##TYPE(volatile u_##TYPE *p, u_##TYPE v)\
16986d2e48cSAttilio Rao {							\
17086d2e48cSAttilio Rao 	__asm __volatile(MPLOCKED OP			\
171fe94be3dSJung-uk Kim 	: "+m" (*p)					\
172fe94be3dSJung-uk Kim 	: CONS (V)					\
1737222d2fbSKonstantin Belousov 	: "memory", "cc");				\
17486d2e48cSAttilio Rao }							\
1756d800f89SBruce Evans struct __hack
1764c5aee92SMark Murray 
177819e370cSPoul-Henning Kamp /*
1783d673254SMark Johnston  * Atomic compare and set, used by the mutex functions.
179819e370cSPoul-Henning Kamp  *
1803d673254SMark Johnston  * cmpset:
1813d673254SMark Johnston  *	if (*dst == expect)
1823d673254SMark Johnston  *		*dst = src
183819e370cSPoul-Henning Kamp  *
1843d673254SMark Johnston  * fcmpset:
1853d673254SMark Johnston  *	if (*dst == *expect)
1863d673254SMark Johnston  *		*dst = src
1873d673254SMark Johnston  *	else
1883d673254SMark Johnston  *		*expect = *dst
1893d673254SMark Johnston  *
1903d673254SMark Johnston  * Returns 0 on failure, non-zero on success.
191819e370cSPoul-Henning Kamp  */
1925788c2bdSMark Johnston #define	ATOMIC_CMPSET(TYPE, CONS)			\
1933d673254SMark Johnston static __inline int					\
1943d673254SMark Johnston atomic_cmpset_##TYPE(volatile u_##TYPE *dst, u_##TYPE expect, u_##TYPE src) \
1953d673254SMark Johnston {							\
1963d673254SMark Johnston 	u_char res;					\
1973d673254SMark Johnston 							\
1983d673254SMark Johnston 	__asm __volatile(				\
1993d673254SMark Johnston 	"	" MPLOCKED "		"		\
2003d673254SMark Johnston 	"	cmpxchg	%3,%1 ;		"		\
2013d673254SMark Johnston 	"	sete	%0 ;		"		\
2023d673254SMark Johnston 	"# atomic_cmpset_" #TYPE "	"		\
2033d673254SMark Johnston 	: "=q" (res),			/* 0 */		\
2043d673254SMark Johnston 	  "+m" (*dst),			/* 1 */		\
2053d673254SMark Johnston 	  "+a" (expect)			/* 2 */		\
2065788c2bdSMark Johnston 	: CONS (src)			/* 3 */		\
2073d673254SMark Johnston 	: "memory", "cc");				\
2083d673254SMark Johnston 	return (res);					\
2093d673254SMark Johnston }							\
2103d673254SMark Johnston 							\
2113d673254SMark Johnston static __inline int					\
2123d673254SMark Johnston atomic_fcmpset_##TYPE(volatile u_##TYPE *dst, u_##TYPE *expect, u_##TYPE src) \
2133d673254SMark Johnston {							\
2143d673254SMark Johnston 	u_char res;					\
2153d673254SMark Johnston 							\
2163d673254SMark Johnston 	__asm __volatile(				\
2173d673254SMark Johnston 	"	" MPLOCKED "		"		\
2183d673254SMark Johnston 	"	cmpxchg	%3,%1 ;		"		\
2193d673254SMark Johnston 	"	sete	%0 ;		"		\
2203d673254SMark Johnston 	"# atomic_fcmpset_" #TYPE "	"		\
2213d673254SMark Johnston 	: "=q" (res),			/* 0 */		\
2223d673254SMark Johnston 	  "+m" (*dst),			/* 1 */		\
2233d673254SMark Johnston 	  "+a" (*expect)		/* 2 */		\
2245788c2bdSMark Johnston 	: CONS (src)			/* 3 */		\
2253d673254SMark Johnston 	: "memory", "cc");				\
2263d673254SMark Johnston 	return (res);					\
2278448afceSAttilio Rao }
2284c5aee92SMark Murray 
2295788c2bdSMark Johnston ATOMIC_CMPSET(char, "q");
2305788c2bdSMark Johnston ATOMIC_CMPSET(short, "r");
2315788c2bdSMark Johnston ATOMIC_CMPSET(int, "r");
232e7a98aefSMateusz Guzik 
2333c2bc2bfSJohn Baldwin /*
2343c2bc2bfSJohn Baldwin  * Atomically add the value of v to the integer pointed to by p and return
2353c2bc2bfSJohn Baldwin  * the previous value of *p.
2363c2bc2bfSJohn Baldwin  */
2373c2bc2bfSJohn Baldwin static __inline u_int
2383c2bc2bfSJohn Baldwin atomic_fetchadd_int(volatile u_int *p, u_int v)
2393c2bc2bfSJohn Baldwin {
2403c2bc2bfSJohn Baldwin 
2413c2bc2bfSJohn Baldwin 	__asm __volatile(
2427e4277e5SBruce Evans 	"	" MPLOCKED "		"
2433c2bc2bfSJohn Baldwin 	"	xaddl	%0,%1 ;		"
2443c2bc2bfSJohn Baldwin 	"# atomic_fetchadd_int"
245ee93d117SJung-uk Kim 	: "+r" (v),			/* 0 */
246fe94be3dSJung-uk Kim 	  "+m" (*p)			/* 1 */
247fe94be3dSJung-uk Kim 	: : "cc");
2483c2bc2bfSJohn Baldwin 	return (v);
2493c2bc2bfSJohn Baldwin }
2503c2bc2bfSJohn Baldwin 
2518a1ee2d3SJung-uk Kim static __inline int
2528a1ee2d3SJung-uk Kim atomic_testandset_int(volatile u_int *p, u_int v)
2538a1ee2d3SJung-uk Kim {
2548a1ee2d3SJung-uk Kim 	u_char res;
2558a1ee2d3SJung-uk Kim 
2568a1ee2d3SJung-uk Kim 	__asm __volatile(
2578a1ee2d3SJung-uk Kim 	"	" MPLOCKED "		"
2588a1ee2d3SJung-uk Kim 	"	btsl	%2,%1 ;		"
2598a1ee2d3SJung-uk Kim 	"	setc	%0 ;		"
2608a1ee2d3SJung-uk Kim 	"# atomic_testandset_int"
2618a1ee2d3SJung-uk Kim 	: "=q" (res),			/* 0 */
2628a1ee2d3SJung-uk Kim 	  "+m" (*p)			/* 1 */
2638a1ee2d3SJung-uk Kim 	: "Ir" (v & 0x1f)		/* 2 */
2648a1ee2d3SJung-uk Kim 	: "cc");
2658a1ee2d3SJung-uk Kim 	return (res);
2668a1ee2d3SJung-uk Kim }
2678a1ee2d3SJung-uk Kim 
268dfdc9a05SSepherosa Ziehau static __inline int
269dfdc9a05SSepherosa Ziehau atomic_testandclear_int(volatile u_int *p, u_int v)
270dfdc9a05SSepherosa Ziehau {
271dfdc9a05SSepherosa Ziehau 	u_char res;
272dfdc9a05SSepherosa Ziehau 
273dfdc9a05SSepherosa Ziehau 	__asm __volatile(
274dfdc9a05SSepherosa Ziehau 	"	" MPLOCKED "		"
275dfdc9a05SSepherosa Ziehau 	"	btrl	%2,%1 ;		"
276dfdc9a05SSepherosa Ziehau 	"	setc	%0 ;		"
277dfdc9a05SSepherosa Ziehau 	"# atomic_testandclear_int"
278dfdc9a05SSepherosa Ziehau 	: "=q" (res),			/* 0 */
279dfdc9a05SSepherosa Ziehau 	  "+m" (*p)			/* 1 */
280dfdc9a05SSepherosa Ziehau 	: "Ir" (v & 0x1f)		/* 2 */
281dfdc9a05SSepherosa Ziehau 	: "cc");
282dfdc9a05SSepherosa Ziehau 	return (res);
283dfdc9a05SSepherosa Ziehau }
284dfdc9a05SSepherosa Ziehau 
285fa9f322dSKonstantin Belousov /*
286fa9f322dSKonstantin Belousov  * We assume that a = b will do atomic loads and stores.  Due to the
287fa9f322dSKonstantin Belousov  * IA32 memory model, a simple store guarantees release semantics.
288fa9f322dSKonstantin Belousov  *
2897626d062SKonstantin Belousov  * However, a load may pass a store if they are performed on distinct
290dd5b6425SKonstantin Belousov  * addresses, so we need Store/Load barrier for sequentially
291dd5b6425SKonstantin Belousov  * consistent fences in SMP kernels.  We use "lock addl $0,mem" for a
292dd5b6425SKonstantin Belousov  * Store/Load barrier, as recommended by the AMD Software Optimization
293dd5b6425SKonstantin Belousov  * Guide, and not mfence.  In the kernel, we use a private per-cpu
2940b6476ecSKonstantin Belousov  * cache line for "mem", to avoid introducing false data
2950b6476ecSKonstantin Belousov  * dependencies.  In user space, we use the word at the top of the
2960b6476ecSKonstantin Belousov  * stack.
2977626d062SKonstantin Belousov  *
2987626d062SKonstantin Belousov  * For UP kernels, however, the memory of the single processor is
2997626d062SKonstantin Belousov  * always consistent, so we only need to stop the compiler from
3007626d062SKonstantin Belousov  * reordering accesses in a way that violates the semantics of acquire
3017626d062SKonstantin Belousov  * and release.
302fa9f322dSKonstantin Belousov  */
30348cae112SKonstantin Belousov 
3047626d062SKonstantin Belousov #if defined(_KERNEL)
3057626d062SKonstantin Belousov #if defined(SMP)
30648cae112SKonstantin Belousov #define	__storeload_barrier()	__mbk()
3077626d062SKonstantin Belousov #else /* _KERNEL && UP */
30848cae112SKonstantin Belousov #define	__storeload_barrier()	__compiler_membar()
3097626d062SKonstantin Belousov #endif /* SMP */
3107626d062SKonstantin Belousov #else /* !_KERNEL */
31148cae112SKonstantin Belousov #define	__storeload_barrier()	__mbu()
3127626d062SKonstantin Belousov #endif /* _KERNEL*/
3137626d062SKonstantin Belousov 
3147626d062SKonstantin Belousov #define	ATOMIC_LOAD(TYPE)					\
3159d979d89SJohn Baldwin static __inline u_##TYPE					\
3169d979d89SJohn Baldwin atomic_load_acq_##TYPE(volatile u_##TYPE *p)			\
3179d979d89SJohn Baldwin {								\
3189d979d89SJohn Baldwin 	u_##TYPE res;						\
3199d979d89SJohn Baldwin 								\
3207626d062SKonstantin Belousov 	res = *p;						\
3217626d062SKonstantin Belousov 	__compiler_membar();					\
3229d979d89SJohn Baldwin 	return (res);						\
3239d979d89SJohn Baldwin }								\
3246d800f89SBruce Evans struct __hack
3254c5aee92SMark Murray 
3267626d062SKonstantin Belousov #define	ATOMIC_STORE(TYPE)					\
3277626d062SKonstantin Belousov static __inline void						\
3287626d062SKonstantin Belousov atomic_store_rel_##TYPE(volatile u_##TYPE *p, u_##TYPE v)	\
3297626d062SKonstantin Belousov {								\
3307626d062SKonstantin Belousov 								\
3317626d062SKonstantin Belousov 	__compiler_membar();					\
3327626d062SKonstantin Belousov 	*p = v;							\
3337626d062SKonstantin Belousov }								\
3347626d062SKonstantin Belousov struct __hack
3354c5aee92SMark Murray 
3368954a9a4SKonstantin Belousov static __inline void
3378954a9a4SKonstantin Belousov atomic_thread_fence_acq(void)
3388954a9a4SKonstantin Belousov {
3398954a9a4SKonstantin Belousov 
3408954a9a4SKonstantin Belousov 	__compiler_membar();
3418954a9a4SKonstantin Belousov }
3428954a9a4SKonstantin Belousov 
3438954a9a4SKonstantin Belousov static __inline void
3448954a9a4SKonstantin Belousov atomic_thread_fence_rel(void)
3458954a9a4SKonstantin Belousov {
3468954a9a4SKonstantin Belousov 
3478954a9a4SKonstantin Belousov 	__compiler_membar();
3488954a9a4SKonstantin Belousov }
3498954a9a4SKonstantin Belousov 
3508954a9a4SKonstantin Belousov static __inline void
3518954a9a4SKonstantin Belousov atomic_thread_fence_acq_rel(void)
3528954a9a4SKonstantin Belousov {
3538954a9a4SKonstantin Belousov 
3548954a9a4SKonstantin Belousov 	__compiler_membar();
3558954a9a4SKonstantin Belousov }
3568954a9a4SKonstantin Belousov 
3578954a9a4SKonstantin Belousov static __inline void
3588954a9a4SKonstantin Belousov atomic_thread_fence_seq_cst(void)
3598954a9a4SKonstantin Belousov {
3608954a9a4SKonstantin Belousov 
3618954a9a4SKonstantin Belousov 	__storeload_barrier();
3628954a9a4SKonstantin Belousov }
3638954a9a4SKonstantin Belousov 
3643264fd70SJung-uk Kim #ifdef _KERNEL
3653264fd70SJung-uk Kim 
3663264fd70SJung-uk Kim #ifdef WANT_FUNCTIONS
3675188b5f3SJung-uk Kim int		atomic_cmpset_64_i386(volatile uint64_t *, uint64_t, uint64_t);
3685188b5f3SJung-uk Kim int		atomic_cmpset_64_i586(volatile uint64_t *, uint64_t, uint64_t);
3693264fd70SJung-uk Kim uint64_t	atomic_load_acq_64_i386(volatile uint64_t *);
3703264fd70SJung-uk Kim uint64_t	atomic_load_acq_64_i586(volatile uint64_t *);
3713264fd70SJung-uk Kim void		atomic_store_rel_64_i386(volatile uint64_t *, uint64_t);
3723264fd70SJung-uk Kim void		atomic_store_rel_64_i586(volatile uint64_t *, uint64_t);
3735188b5f3SJung-uk Kim uint64_t	atomic_swap_64_i386(volatile uint64_t *, uint64_t);
3745188b5f3SJung-uk Kim uint64_t	atomic_swap_64_i586(volatile uint64_t *, uint64_t);
3753264fd70SJung-uk Kim #endif
3763264fd70SJung-uk Kim 
3773264fd70SJung-uk Kim /* I486 does not support SMP or CMPXCHG8B. */
3785188b5f3SJung-uk Kim static __inline int
3795188b5f3SJung-uk Kim atomic_cmpset_64_i386(volatile uint64_t *dst, uint64_t expect, uint64_t src)
3805188b5f3SJung-uk Kim {
3815188b5f3SJung-uk Kim 	volatile uint32_t *p;
3825188b5f3SJung-uk Kim 	u_char res;
3835188b5f3SJung-uk Kim 
3845188b5f3SJung-uk Kim 	p = (volatile uint32_t *)dst;
3855188b5f3SJung-uk Kim 	__asm __volatile(
3865188b5f3SJung-uk Kim 	"	pushfl ;		"
3875188b5f3SJung-uk Kim 	"	cli ;			"
3885188b5f3SJung-uk Kim 	"	xorl	%1,%%eax ;	"
3895188b5f3SJung-uk Kim 	"	xorl	%2,%%edx ;	"
3905188b5f3SJung-uk Kim 	"	orl	%%edx,%%eax ;	"
3915188b5f3SJung-uk Kim 	"	jne	1f ;		"
3925188b5f3SJung-uk Kim 	"	movl	%4,%1 ;		"
3935188b5f3SJung-uk Kim 	"	movl	%5,%2 ;		"
3945188b5f3SJung-uk Kim 	"1:				"
3955188b5f3SJung-uk Kim 	"	sete	%3 ;		"
3965188b5f3SJung-uk Kim 	"	popfl"
3975188b5f3SJung-uk Kim 	: "+A" (expect),		/* 0 */
3985188b5f3SJung-uk Kim 	  "+m" (*p),			/* 1 */
3995188b5f3SJung-uk Kim 	  "+m" (*(p + 1)),		/* 2 */
4005188b5f3SJung-uk Kim 	  "=q" (res)			/* 3 */
4015188b5f3SJung-uk Kim 	: "r" ((uint32_t)src),		/* 4 */
4025188b5f3SJung-uk Kim 	  "r" ((uint32_t)(src >> 32))	/* 5 */
4035188b5f3SJung-uk Kim 	: "memory", "cc");
4045188b5f3SJung-uk Kim 	return (res);
4055188b5f3SJung-uk Kim }
4065188b5f3SJung-uk Kim 
4073264fd70SJung-uk Kim static __inline uint64_t
4083264fd70SJung-uk Kim atomic_load_acq_64_i386(volatile uint64_t *p)
4093264fd70SJung-uk Kim {
4103264fd70SJung-uk Kim 	volatile uint32_t *q;
4113264fd70SJung-uk Kim 	uint64_t res;
4123264fd70SJung-uk Kim 
4133264fd70SJung-uk Kim 	q = (volatile uint32_t *)p;
4143264fd70SJung-uk Kim 	__asm __volatile(
4153264fd70SJung-uk Kim 	"	pushfl ;		"
4163264fd70SJung-uk Kim 	"	cli ;			"
4173264fd70SJung-uk Kim 	"	movl	%1,%%eax ;	"
4183264fd70SJung-uk Kim 	"	movl	%2,%%edx ;	"
4193264fd70SJung-uk Kim 	"	popfl"
4203264fd70SJung-uk Kim 	: "=&A" (res)			/* 0 */
4213264fd70SJung-uk Kim 	: "m" (*q),			/* 1 */
4223264fd70SJung-uk Kim 	  "m" (*(q + 1))		/* 2 */
4233264fd70SJung-uk Kim 	: "memory");
4243264fd70SJung-uk Kim 	return (res);
4253264fd70SJung-uk Kim }
4263264fd70SJung-uk Kim 
4273264fd70SJung-uk Kim static __inline void
4283264fd70SJung-uk Kim atomic_store_rel_64_i386(volatile uint64_t *p, uint64_t v)
4293264fd70SJung-uk Kim {
4303264fd70SJung-uk Kim 	volatile uint32_t *q;
4313264fd70SJung-uk Kim 
4323264fd70SJung-uk Kim 	q = (volatile uint32_t *)p;
4333264fd70SJung-uk Kim 	__asm __volatile(
4343264fd70SJung-uk Kim 	"	pushfl ;		"
4353264fd70SJung-uk Kim 	"	cli ;			"
4363264fd70SJung-uk Kim 	"	movl	%%eax,%0 ;	"
4373264fd70SJung-uk Kim 	"	movl	%%edx,%1 ;	"
4383264fd70SJung-uk Kim 	"	popfl"
4393264fd70SJung-uk Kim 	: "=m" (*q),			/* 0 */
4403264fd70SJung-uk Kim 	  "=m" (*(q + 1))		/* 1 */
4413264fd70SJung-uk Kim 	: "A" (v)			/* 2 */
4423264fd70SJung-uk Kim 	: "memory");
4433264fd70SJung-uk Kim }
4443264fd70SJung-uk Kim 
4453264fd70SJung-uk Kim static __inline uint64_t
4465188b5f3SJung-uk Kim atomic_swap_64_i386(volatile uint64_t *p, uint64_t v)
4475188b5f3SJung-uk Kim {
4485188b5f3SJung-uk Kim 	volatile uint32_t *q;
4495188b5f3SJung-uk Kim 	uint64_t res;
4505188b5f3SJung-uk Kim 
4515188b5f3SJung-uk Kim 	q = (volatile uint32_t *)p;
4525188b5f3SJung-uk Kim 	__asm __volatile(
4535188b5f3SJung-uk Kim 	"	pushfl ;		"
4545188b5f3SJung-uk Kim 	"	cli ;			"
4555188b5f3SJung-uk Kim 	"	movl	%1,%%eax ;	"
4565188b5f3SJung-uk Kim 	"	movl	%2,%%edx ;	"
4575188b5f3SJung-uk Kim 	"	movl	%4,%2 ;		"
4585188b5f3SJung-uk Kim 	"	movl	%3,%1 ;		"
4595188b5f3SJung-uk Kim 	"	popfl"
4605188b5f3SJung-uk Kim 	: "=&A" (res),			/* 0 */
4615188b5f3SJung-uk Kim 	  "+m" (*q),			/* 1 */
4625188b5f3SJung-uk Kim 	  "+m" (*(q + 1))		/* 2 */
4635188b5f3SJung-uk Kim 	: "r" ((uint32_t)v),		/* 3 */
4645188b5f3SJung-uk Kim 	  "r" ((uint32_t)(v >> 32)));	/* 4 */
4655188b5f3SJung-uk Kim 	return (res);
4665188b5f3SJung-uk Kim }
4675188b5f3SJung-uk Kim 
4685188b5f3SJung-uk Kim static __inline int
4695188b5f3SJung-uk Kim atomic_cmpset_64_i586(volatile uint64_t *dst, uint64_t expect, uint64_t src)
4705188b5f3SJung-uk Kim {
4715188b5f3SJung-uk Kim 	u_char res;
4725188b5f3SJung-uk Kim 
4735188b5f3SJung-uk Kim 	__asm __volatile(
4745188b5f3SJung-uk Kim 	"	" MPLOCKED "		"
4755188b5f3SJung-uk Kim 	"	cmpxchg8b %1 ;		"
4765188b5f3SJung-uk Kim 	"	sete	%0"
4775188b5f3SJung-uk Kim 	: "=q" (res),			/* 0 */
4785188b5f3SJung-uk Kim 	  "+m" (*dst),			/* 1 */
4795188b5f3SJung-uk Kim 	  "+A" (expect)			/* 2 */
4805188b5f3SJung-uk Kim 	: "b" ((uint32_t)src),		/* 3 */
4815188b5f3SJung-uk Kim 	  "c" ((uint32_t)(src >> 32))	/* 4 */
4825188b5f3SJung-uk Kim 	: "memory", "cc");
4835188b5f3SJung-uk Kim 	return (res);
4845188b5f3SJung-uk Kim }
4855188b5f3SJung-uk Kim 
4865188b5f3SJung-uk Kim static __inline uint64_t
4873264fd70SJung-uk Kim atomic_load_acq_64_i586(volatile uint64_t *p)
4883264fd70SJung-uk Kim {
4893264fd70SJung-uk Kim 	uint64_t res;
4903264fd70SJung-uk Kim 
4913264fd70SJung-uk Kim 	__asm __volatile(
4923264fd70SJung-uk Kim 	"	movl	%%ebx,%%eax ;	"
4933264fd70SJung-uk Kim 	"	movl	%%ecx,%%edx ;	"
4943264fd70SJung-uk Kim 	"	" MPLOCKED "		"
4953264fd70SJung-uk Kim 	"	cmpxchg8b %1"
4963264fd70SJung-uk Kim 	: "=&A" (res),			/* 0 */
4973264fd70SJung-uk Kim 	  "+m" (*p)			/* 1 */
4983264fd70SJung-uk Kim 	: : "memory", "cc");
4993264fd70SJung-uk Kim 	return (res);
5003264fd70SJung-uk Kim }
5013264fd70SJung-uk Kim 
5023264fd70SJung-uk Kim static __inline void
5033264fd70SJung-uk Kim atomic_store_rel_64_i586(volatile uint64_t *p, uint64_t v)
5043264fd70SJung-uk Kim {
5053264fd70SJung-uk Kim 
5063264fd70SJung-uk Kim 	__asm __volatile(
5073264fd70SJung-uk Kim 	"	movl	%%eax,%%ebx ;	"
5083264fd70SJung-uk Kim 	"	movl	%%edx,%%ecx ;	"
5093264fd70SJung-uk Kim 	"1:				"
5103264fd70SJung-uk Kim 	"	" MPLOCKED "		"
5113264fd70SJung-uk Kim 	"	cmpxchg8b %0 ;		"
5123264fd70SJung-uk Kim 	"	jne	1b"
5133264fd70SJung-uk Kim 	: "+m" (*p),			/* 0 */
5143264fd70SJung-uk Kim 	  "+A" (v)			/* 1 */
5153264fd70SJung-uk Kim 	: : "ebx", "ecx", "memory", "cc");
5163264fd70SJung-uk Kim }
5173264fd70SJung-uk Kim 
5183264fd70SJung-uk Kim static __inline uint64_t
5195188b5f3SJung-uk Kim atomic_swap_64_i586(volatile uint64_t *p, uint64_t v)
5205188b5f3SJung-uk Kim {
5215188b5f3SJung-uk Kim 
5225188b5f3SJung-uk Kim 	__asm __volatile(
5235188b5f3SJung-uk Kim 	"	movl	%%eax,%%ebx ;	"
5245188b5f3SJung-uk Kim 	"	movl	%%edx,%%ecx ;	"
5255188b5f3SJung-uk Kim 	"1:				"
5265188b5f3SJung-uk Kim 	"	" MPLOCKED "		"
5275188b5f3SJung-uk Kim 	"	cmpxchg8b %0 ;		"
5285188b5f3SJung-uk Kim 	"	jne	1b"
5295188b5f3SJung-uk Kim 	: "+m" (*p),			/* 0 */
5305188b5f3SJung-uk Kim 	  "+A" (v)			/* 1 */
5315188b5f3SJung-uk Kim 	: : "ebx", "ecx", "memory", "cc");
5325188b5f3SJung-uk Kim 	return (v);
5335188b5f3SJung-uk Kim }
5345188b5f3SJung-uk Kim 
5355188b5f3SJung-uk Kim static __inline int
5365188b5f3SJung-uk Kim atomic_cmpset_64(volatile uint64_t *dst, uint64_t expect, uint64_t src)
5375188b5f3SJung-uk Kim {
5385188b5f3SJung-uk Kim 
5395188b5f3SJung-uk Kim 	if ((cpu_feature & CPUID_CX8) == 0)
5405188b5f3SJung-uk Kim 		return (atomic_cmpset_64_i386(dst, expect, src));
5415188b5f3SJung-uk Kim 	else
5425188b5f3SJung-uk Kim 		return (atomic_cmpset_64_i586(dst, expect, src));
5435188b5f3SJung-uk Kim }
5445188b5f3SJung-uk Kim 
5455188b5f3SJung-uk Kim static __inline uint64_t
5463264fd70SJung-uk Kim atomic_load_acq_64(volatile uint64_t *p)
5473264fd70SJung-uk Kim {
5483264fd70SJung-uk Kim 
5493264fd70SJung-uk Kim 	if ((cpu_feature & CPUID_CX8) == 0)
5503264fd70SJung-uk Kim 		return (atomic_load_acq_64_i386(p));
5513264fd70SJung-uk Kim 	else
5523264fd70SJung-uk Kim 		return (atomic_load_acq_64_i586(p));
5533264fd70SJung-uk Kim }
5543264fd70SJung-uk Kim 
5553264fd70SJung-uk Kim static __inline void
5563264fd70SJung-uk Kim atomic_store_rel_64(volatile uint64_t *p, uint64_t v)
5573264fd70SJung-uk Kim {
5583264fd70SJung-uk Kim 
5593264fd70SJung-uk Kim 	if ((cpu_feature & CPUID_CX8) == 0)
5603264fd70SJung-uk Kim 		atomic_store_rel_64_i386(p, v);
5613264fd70SJung-uk Kim 	else
5623264fd70SJung-uk Kim 		atomic_store_rel_64_i586(p, v);
5633264fd70SJung-uk Kim }
5643264fd70SJung-uk Kim 
5655188b5f3SJung-uk Kim static __inline uint64_t
5665188b5f3SJung-uk Kim atomic_swap_64(volatile uint64_t *p, uint64_t v)
5675188b5f3SJung-uk Kim {
5685188b5f3SJung-uk Kim 
5695188b5f3SJung-uk Kim 	if ((cpu_feature & CPUID_CX8) == 0)
5705188b5f3SJung-uk Kim 		return (atomic_swap_64_i386(p, v));
5715188b5f3SJung-uk Kim 	else
5725188b5f3SJung-uk Kim 		return (atomic_swap_64_i586(p, v));
5735188b5f3SJung-uk Kim }
5745188b5f3SJung-uk Kim 
575322f006eSHans Petter Selasky static __inline uint64_t
576322f006eSHans Petter Selasky atomic_fetchadd_64(volatile uint64_t *p, uint64_t v)
577322f006eSHans Petter Selasky {
578322f006eSHans Petter Selasky 
579322f006eSHans Petter Selasky 	for (;;) {
580322f006eSHans Petter Selasky 		uint64_t t = *p;
581322f006eSHans Petter Selasky 		if (atomic_cmpset_64(p, t, t + v))
582322f006eSHans Petter Selasky 			return (t);
583322f006eSHans Petter Selasky 	}
584322f006eSHans Petter Selasky }
585322f006eSHans Petter Selasky 
586*43bb1274SHans Petter Selasky static __inline void
587*43bb1274SHans Petter Selasky atomic_add_64(volatile uint64_t *p, uint64_t v)
588*43bb1274SHans Petter Selasky {
589*43bb1274SHans Petter Selasky 	uint64_t t;
590*43bb1274SHans Petter Selasky 
591*43bb1274SHans Petter Selasky 	for (;;) {
592*43bb1274SHans Petter Selasky 		t = *p;
593*43bb1274SHans Petter Selasky 		if (atomic_cmpset_64(p, t, t + v))
594*43bb1274SHans Petter Selasky 			break;
595*43bb1274SHans Petter Selasky 	}
596*43bb1274SHans Petter Selasky }
597*43bb1274SHans Petter Selasky 
598*43bb1274SHans Petter Selasky static __inline void
599*43bb1274SHans Petter Selasky atomic_subtract_64(volatile uint64_t *p, uint64_t v)
600*43bb1274SHans Petter Selasky {
601*43bb1274SHans Petter Selasky 	uint64_t t;
602*43bb1274SHans Petter Selasky 
603*43bb1274SHans Petter Selasky 	for (;;) {
604*43bb1274SHans Petter Selasky 		t = *p;
605*43bb1274SHans Petter Selasky 		if (atomic_cmpset_64(p, t, t - v))
606*43bb1274SHans Petter Selasky 			break;
607*43bb1274SHans Petter Selasky 	}
608*43bb1274SHans Petter Selasky }
609*43bb1274SHans Petter Selasky 
6103264fd70SJung-uk Kim #endif /* _KERNEL */
6113264fd70SJung-uk Kim 
61248281036SJohn Baldwin #endif /* KLD_MODULE || !__GNUCLIKE_ASM */
6138a6b1c8fSJohn Baldwin 
6148306a37bSMark Murray ATOMIC_ASM(set,	     char,  "orb %b1,%0",  "iq",  v);
6158306a37bSMark Murray ATOMIC_ASM(clear,    char,  "andb %b1,%0", "iq", ~v);
6168306a37bSMark Murray ATOMIC_ASM(add,	     char,  "addb %b1,%0", "iq",  v);
6178306a37bSMark Murray ATOMIC_ASM(subtract, char,  "subb %b1,%0", "iq",  v);
6188a6b1c8fSJohn Baldwin 
6198306a37bSMark Murray ATOMIC_ASM(set,	     short, "orw %w1,%0",  "ir",  v);
6208306a37bSMark Murray ATOMIC_ASM(clear,    short, "andw %w1,%0", "ir", ~v);
6218306a37bSMark Murray ATOMIC_ASM(add,	     short, "addw %w1,%0", "ir",  v);
6228306a37bSMark Murray ATOMIC_ASM(subtract, short, "subw %w1,%0", "ir",  v);
6238a6b1c8fSJohn Baldwin 
6248306a37bSMark Murray ATOMIC_ASM(set,	     int,   "orl %1,%0",   "ir",  v);
6258306a37bSMark Murray ATOMIC_ASM(clear,    int,   "andl %1,%0",  "ir", ~v);
6268306a37bSMark Murray ATOMIC_ASM(add,	     int,   "addl %1,%0",  "ir",  v);
6278306a37bSMark Murray ATOMIC_ASM(subtract, int,   "subl %1,%0",  "ir",  v);
6288a6b1c8fSJohn Baldwin 
6298306a37bSMark Murray ATOMIC_ASM(set,	     long,  "orl %1,%0",   "ir",  v);
6308306a37bSMark Murray ATOMIC_ASM(clear,    long,  "andl %1,%0",  "ir", ~v);
6318306a37bSMark Murray ATOMIC_ASM(add,	     long,  "addl %1,%0",  "ir",  v);
6328306a37bSMark Murray ATOMIC_ASM(subtract, long,  "subl %1,%0",  "ir",  v);
6339d979d89SJohn Baldwin 
6347626d062SKonstantin Belousov #define	ATOMIC_LOADSTORE(TYPE)				\
6357626d062SKonstantin Belousov 	ATOMIC_LOAD(TYPE);				\
6367626d062SKonstantin Belousov 	ATOMIC_STORE(TYPE)
637fa9f322dSKonstantin Belousov 
6387626d062SKonstantin Belousov ATOMIC_LOADSTORE(char);
6397626d062SKonstantin Belousov ATOMIC_LOADSTORE(short);
6407626d062SKonstantin Belousov ATOMIC_LOADSTORE(int);
6417626d062SKonstantin Belousov ATOMIC_LOADSTORE(long);
642ccbdd9eeSJohn Baldwin 
6438a6b1c8fSJohn Baldwin #undef ATOMIC_ASM
644fa9f322dSKonstantin Belousov #undef ATOMIC_LOAD
645fa9f322dSKonstantin Belousov #undef ATOMIC_STORE
6467626d062SKonstantin Belousov #undef ATOMIC_LOADSTORE
647ccbdd9eeSJohn Baldwin 
648f28e1c8fSBruce Evans #ifndef WANT_FUNCTIONS
64948281036SJohn Baldwin 
65048281036SJohn Baldwin static __inline int
651065b12a7SPoul-Henning Kamp atomic_cmpset_long(volatile u_long *dst, u_long expect, u_long src)
65248281036SJohn Baldwin {
65348281036SJohn Baldwin 
654065b12a7SPoul-Henning Kamp 	return (atomic_cmpset_int((volatile u_int *)dst, (u_int)expect,
65548281036SJohn Baldwin 	    (u_int)src));
65648281036SJohn Baldwin }
65748281036SJohn Baldwin 
6586eb4157fSPawel Jakub Dawidek static __inline u_long
6596eb4157fSPawel Jakub Dawidek atomic_fetchadd_long(volatile u_long *p, u_long v)
6606eb4157fSPawel Jakub Dawidek {
6616eb4157fSPawel Jakub Dawidek 
6626eb4157fSPawel Jakub Dawidek 	return (atomic_fetchadd_int((volatile u_int *)p, (u_int)v));
6636eb4157fSPawel Jakub Dawidek }
6646eb4157fSPawel Jakub Dawidek 
6658a1ee2d3SJung-uk Kim static __inline int
6668a1ee2d3SJung-uk Kim atomic_testandset_long(volatile u_long *p, u_int v)
6678a1ee2d3SJung-uk Kim {
6688a1ee2d3SJung-uk Kim 
6698a1ee2d3SJung-uk Kim 	return (atomic_testandset_int((volatile u_int *)p, v));
6708a1ee2d3SJung-uk Kim }
6718a1ee2d3SJung-uk Kim 
672dfdc9a05SSepherosa Ziehau static __inline int
673dfdc9a05SSepherosa Ziehau atomic_testandclear_long(volatile u_long *p, u_int v)
674dfdc9a05SSepherosa Ziehau {
675dfdc9a05SSepherosa Ziehau 
676dfdc9a05SSepherosa Ziehau 	return (atomic_testandclear_int((volatile u_int *)p, v));
677dfdc9a05SSepherosa Ziehau }
678dfdc9a05SSepherosa Ziehau 
6798a1ee2d3SJung-uk Kim /* Read the current value and store a new value in the destination. */
68048281036SJohn Baldwin #ifdef __GNUCLIKE_ASM
68148281036SJohn Baldwin 
68248281036SJohn Baldwin static __inline u_int
6838a1ee2d3SJung-uk Kim atomic_swap_int(volatile u_int *p, u_int v)
68448281036SJohn Baldwin {
68548281036SJohn Baldwin 
68648281036SJohn Baldwin 	__asm __volatile(
68748281036SJohn Baldwin 	"	xchgl	%1,%0 ;		"
6888a1ee2d3SJung-uk Kim 	"# atomic_swap_int"
6898a1ee2d3SJung-uk Kim 	: "+r" (v),			/* 0 */
690fe94be3dSJung-uk Kim 	  "+m" (*p));			/* 1 */
6918a1ee2d3SJung-uk Kim 	return (v);
69248281036SJohn Baldwin }
69348281036SJohn Baldwin 
69448281036SJohn Baldwin static __inline u_long
6958a1ee2d3SJung-uk Kim atomic_swap_long(volatile u_long *p, u_long v)
69648281036SJohn Baldwin {
69748281036SJohn Baldwin 
6988a1ee2d3SJung-uk Kim 	return (atomic_swap_int((volatile u_int *)p, (u_int)v));
69948281036SJohn Baldwin }
70048281036SJohn Baldwin 
70148281036SJohn Baldwin #else /* !__GNUCLIKE_ASM */
70248281036SJohn Baldwin 
7038a1ee2d3SJung-uk Kim u_int	atomic_swap_int(volatile u_int *p, u_int v);
7048a1ee2d3SJung-uk Kim u_long	atomic_swap_long(volatile u_long *p, u_long v);
70548281036SJohn Baldwin 
70648281036SJohn Baldwin #endif /* __GNUCLIKE_ASM */
70748281036SJohn Baldwin 
70886d2e48cSAttilio Rao #define	atomic_set_acq_char		atomic_set_barr_char
70986d2e48cSAttilio Rao #define	atomic_set_rel_char		atomic_set_barr_char
71086d2e48cSAttilio Rao #define	atomic_clear_acq_char		atomic_clear_barr_char
71186d2e48cSAttilio Rao #define	atomic_clear_rel_char		atomic_clear_barr_char
71286d2e48cSAttilio Rao #define	atomic_add_acq_char		atomic_add_barr_char
71386d2e48cSAttilio Rao #define	atomic_add_rel_char		atomic_add_barr_char
71486d2e48cSAttilio Rao #define	atomic_subtract_acq_char	atomic_subtract_barr_char
71586d2e48cSAttilio Rao #define	atomic_subtract_rel_char	atomic_subtract_barr_char
7163d673254SMark Johnston #define	atomic_cmpset_acq_char		atomic_cmpset_char
7173d673254SMark Johnston #define	atomic_cmpset_rel_char		atomic_cmpset_char
7183d673254SMark Johnston #define	atomic_fcmpset_acq_char		atomic_fcmpset_char
7193d673254SMark Johnston #define	atomic_fcmpset_rel_char		atomic_fcmpset_char
7208a6b1c8fSJohn Baldwin 
72186d2e48cSAttilio Rao #define	atomic_set_acq_short		atomic_set_barr_short
72286d2e48cSAttilio Rao #define	atomic_set_rel_short		atomic_set_barr_short
72386d2e48cSAttilio Rao #define	atomic_clear_acq_short		atomic_clear_barr_short
72486d2e48cSAttilio Rao #define	atomic_clear_rel_short		atomic_clear_barr_short
72586d2e48cSAttilio Rao #define	atomic_add_acq_short		atomic_add_barr_short
72686d2e48cSAttilio Rao #define	atomic_add_rel_short		atomic_add_barr_short
72786d2e48cSAttilio Rao #define	atomic_subtract_acq_short	atomic_subtract_barr_short
72886d2e48cSAttilio Rao #define	atomic_subtract_rel_short	atomic_subtract_barr_short
7293d673254SMark Johnston #define	atomic_cmpset_acq_short		atomic_cmpset_short
7303d673254SMark Johnston #define	atomic_cmpset_rel_short		atomic_cmpset_short
7313d673254SMark Johnston #define	atomic_fcmpset_acq_short	atomic_fcmpset_short
7323d673254SMark Johnston #define	atomic_fcmpset_rel_short	atomic_fcmpset_short
7338a6b1c8fSJohn Baldwin 
73486d2e48cSAttilio Rao #define	atomic_set_acq_int		atomic_set_barr_int
73586d2e48cSAttilio Rao #define	atomic_set_rel_int		atomic_set_barr_int
73686d2e48cSAttilio Rao #define	atomic_clear_acq_int		atomic_clear_barr_int
73786d2e48cSAttilio Rao #define	atomic_clear_rel_int		atomic_clear_barr_int
73886d2e48cSAttilio Rao #define	atomic_add_acq_int		atomic_add_barr_int
73986d2e48cSAttilio Rao #define	atomic_add_rel_int		atomic_add_barr_int
74086d2e48cSAttilio Rao #define	atomic_subtract_acq_int		atomic_subtract_barr_int
74186d2e48cSAttilio Rao #define	atomic_subtract_rel_int		atomic_subtract_barr_int
7428448afceSAttilio Rao #define	atomic_cmpset_acq_int		atomic_cmpset_int
7438448afceSAttilio Rao #define	atomic_cmpset_rel_int		atomic_cmpset_int
744e7a98aefSMateusz Guzik #define	atomic_fcmpset_acq_int		atomic_fcmpset_int
745e7a98aefSMateusz Guzik #define	atomic_fcmpset_rel_int		atomic_fcmpset_int
7468a6b1c8fSJohn Baldwin 
74786d2e48cSAttilio Rao #define	atomic_set_acq_long		atomic_set_barr_long
74886d2e48cSAttilio Rao #define	atomic_set_rel_long		atomic_set_barr_long
74986d2e48cSAttilio Rao #define	atomic_clear_acq_long		atomic_clear_barr_long
75086d2e48cSAttilio Rao #define	atomic_clear_rel_long		atomic_clear_barr_long
75186d2e48cSAttilio Rao #define	atomic_add_acq_long		atomic_add_barr_long
75286d2e48cSAttilio Rao #define	atomic_add_rel_long		atomic_add_barr_long
75386d2e48cSAttilio Rao #define	atomic_subtract_acq_long	atomic_subtract_barr_long
75486d2e48cSAttilio Rao #define	atomic_subtract_rel_long	atomic_subtract_barr_long
7558448afceSAttilio Rao #define	atomic_cmpset_acq_long		atomic_cmpset_long
7568448afceSAttilio Rao #define	atomic_cmpset_rel_long		atomic_cmpset_long
757e7a98aefSMateusz Guzik #define	atomic_fcmpset_acq_long		atomic_fcmpset_long
758e7a98aefSMateusz Guzik #define	atomic_fcmpset_rel_long		atomic_fcmpset_long
7598a6b1c8fSJohn Baldwin 
7608a1ee2d3SJung-uk Kim #define	atomic_readandclear_int(p)	atomic_swap_int(p, 0)
7618a1ee2d3SJung-uk Kim #define	atomic_readandclear_long(p)	atomic_swap_long(p, 0)
7628a1ee2d3SJung-uk Kim 
76348281036SJohn Baldwin /* Operations on 8-bit bytes. */
7648a6b1c8fSJohn Baldwin #define	atomic_set_8		atomic_set_char
7658a6b1c8fSJohn Baldwin #define	atomic_set_acq_8	atomic_set_acq_char
7668a6b1c8fSJohn Baldwin #define	atomic_set_rel_8	atomic_set_rel_char
7678a6b1c8fSJohn Baldwin #define	atomic_clear_8		atomic_clear_char
7688a6b1c8fSJohn Baldwin #define	atomic_clear_acq_8	atomic_clear_acq_char
7698a6b1c8fSJohn Baldwin #define	atomic_clear_rel_8	atomic_clear_rel_char
7708a6b1c8fSJohn Baldwin #define	atomic_add_8		atomic_add_char
7718a6b1c8fSJohn Baldwin #define	atomic_add_acq_8	atomic_add_acq_char
7728a6b1c8fSJohn Baldwin #define	atomic_add_rel_8	atomic_add_rel_char
7738a6b1c8fSJohn Baldwin #define	atomic_subtract_8	atomic_subtract_char
7748a6b1c8fSJohn Baldwin #define	atomic_subtract_acq_8	atomic_subtract_acq_char
7758a6b1c8fSJohn Baldwin #define	atomic_subtract_rel_8	atomic_subtract_rel_char
7768a6b1c8fSJohn Baldwin #define	atomic_load_acq_8	atomic_load_acq_char
7778a6b1c8fSJohn Baldwin #define	atomic_store_rel_8	atomic_store_rel_char
7783d673254SMark Johnston #define	atomic_cmpset_8		atomic_cmpset_char
7793d673254SMark Johnston #define	atomic_cmpset_acq_8	atomic_cmpset_acq_char
7803d673254SMark Johnston #define	atomic_cmpset_rel_8	atomic_cmpset_rel_char
7813d673254SMark Johnston #define	atomic_fcmpset_8	atomic_fcmpset_char
7823d673254SMark Johnston #define	atomic_fcmpset_acq_8	atomic_fcmpset_acq_char
7833d673254SMark Johnston #define	atomic_fcmpset_rel_8	atomic_fcmpset_rel_char
7848a6b1c8fSJohn Baldwin 
78548281036SJohn Baldwin /* Operations on 16-bit words. */
7868a6b1c8fSJohn Baldwin #define	atomic_set_16		atomic_set_short
7878a6b1c8fSJohn Baldwin #define	atomic_set_acq_16	atomic_set_acq_short
7888a6b1c8fSJohn Baldwin #define	atomic_set_rel_16	atomic_set_rel_short
7898a6b1c8fSJohn Baldwin #define	atomic_clear_16		atomic_clear_short
7908a6b1c8fSJohn Baldwin #define	atomic_clear_acq_16	atomic_clear_acq_short
7918a6b1c8fSJohn Baldwin #define	atomic_clear_rel_16	atomic_clear_rel_short
7928a6b1c8fSJohn Baldwin #define	atomic_add_16		atomic_add_short
7938a6b1c8fSJohn Baldwin #define	atomic_add_acq_16	atomic_add_acq_short
7948a6b1c8fSJohn Baldwin #define	atomic_add_rel_16	atomic_add_rel_short
7958a6b1c8fSJohn Baldwin #define	atomic_subtract_16	atomic_subtract_short
7968a6b1c8fSJohn Baldwin #define	atomic_subtract_acq_16	atomic_subtract_acq_short
7978a6b1c8fSJohn Baldwin #define	atomic_subtract_rel_16	atomic_subtract_rel_short
7988a6b1c8fSJohn Baldwin #define	atomic_load_acq_16	atomic_load_acq_short
7998a6b1c8fSJohn Baldwin #define	atomic_store_rel_16	atomic_store_rel_short
8003d673254SMark Johnston #define	atomic_cmpset_16	atomic_cmpset_short
8013d673254SMark Johnston #define	atomic_cmpset_acq_16	atomic_cmpset_acq_short
8023d673254SMark Johnston #define	atomic_cmpset_rel_16	atomic_cmpset_rel_short
8033d673254SMark Johnston #define	atomic_fcmpset_16	atomic_fcmpset_short
8043d673254SMark Johnston #define	atomic_fcmpset_acq_16	atomic_fcmpset_acq_short
8053d673254SMark Johnston #define	atomic_fcmpset_rel_16	atomic_fcmpset_rel_short
8068a6b1c8fSJohn Baldwin 
80748281036SJohn Baldwin /* Operations on 32-bit double words. */
8088a6b1c8fSJohn Baldwin #define	atomic_set_32		atomic_set_int
8098a6b1c8fSJohn Baldwin #define	atomic_set_acq_32	atomic_set_acq_int
8108a6b1c8fSJohn Baldwin #define	atomic_set_rel_32	atomic_set_rel_int
8118a6b1c8fSJohn Baldwin #define	atomic_clear_32		atomic_clear_int
8128a6b1c8fSJohn Baldwin #define	atomic_clear_acq_32	atomic_clear_acq_int
8138a6b1c8fSJohn Baldwin #define	atomic_clear_rel_32	atomic_clear_rel_int
8148a6b1c8fSJohn Baldwin #define	atomic_add_32		atomic_add_int
8158a6b1c8fSJohn Baldwin #define	atomic_add_acq_32	atomic_add_acq_int
8168a6b1c8fSJohn Baldwin #define	atomic_add_rel_32	atomic_add_rel_int
8178a6b1c8fSJohn Baldwin #define	atomic_subtract_32	atomic_subtract_int
8188a6b1c8fSJohn Baldwin #define	atomic_subtract_acq_32	atomic_subtract_acq_int
8198a6b1c8fSJohn Baldwin #define	atomic_subtract_rel_32	atomic_subtract_rel_int
8208a6b1c8fSJohn Baldwin #define	atomic_load_acq_32	atomic_load_acq_int
8218a6b1c8fSJohn Baldwin #define	atomic_store_rel_32	atomic_store_rel_int
8228a6b1c8fSJohn Baldwin #define	atomic_cmpset_32	atomic_cmpset_int
8238a6b1c8fSJohn Baldwin #define	atomic_cmpset_acq_32	atomic_cmpset_acq_int
8248a6b1c8fSJohn Baldwin #define	atomic_cmpset_rel_32	atomic_cmpset_rel_int
825e7a98aefSMateusz Guzik #define	atomic_fcmpset_32	atomic_fcmpset_int
826e7a98aefSMateusz Guzik #define	atomic_fcmpset_acq_32	atomic_fcmpset_acq_int
827e7a98aefSMateusz Guzik #define	atomic_fcmpset_rel_32	atomic_fcmpset_rel_int
8288a1ee2d3SJung-uk Kim #define	atomic_swap_32		atomic_swap_int
8298a6b1c8fSJohn Baldwin #define	atomic_readandclear_32	atomic_readandclear_int
8303c2bc2bfSJohn Baldwin #define	atomic_fetchadd_32	atomic_fetchadd_int
8318a1ee2d3SJung-uk Kim #define	atomic_testandset_32	atomic_testandset_int
832dfdc9a05SSepherosa Ziehau #define	atomic_testandclear_32	atomic_testandclear_int
8338a6b1c8fSJohn Baldwin 
834*43bb1274SHans Petter Selasky /* Operations on 64-bit quad words. */
835*43bb1274SHans Petter Selasky #define	atomic_cmpset_acq_64 atomic_cmpset_64
836*43bb1274SHans Petter Selasky #define	atomic_cmpset_rel_64 atomic_cmpset_64
837*43bb1274SHans Petter Selasky #define	atomic_fetchadd_acq_64	atomic_fetchadd_64
838*43bb1274SHans Petter Selasky #define	atomic_fetchadd_rel_64	atomic_fetchadd_64
839*43bb1274SHans Petter Selasky #define	atomic_add_acq_64 atomic_add_64
840*43bb1274SHans Petter Selasky #define	atomic_add_rel_64 atomic_add_64
841*43bb1274SHans Petter Selasky #define	atomic_subtract_acq_64 atomic_subtract_64
842*43bb1274SHans Petter Selasky #define	atomic_subtract_rel_64 atomic_subtract_64
843*43bb1274SHans Petter Selasky 
84448281036SJohn Baldwin /* Operations on pointers. */
8456f0f8ccaSDag-Erling Smørgrav #define	atomic_set_ptr(p, v) \
8466f0f8ccaSDag-Erling Smørgrav 	atomic_set_int((volatile u_int *)(p), (u_int)(v))
8476f0f8ccaSDag-Erling Smørgrav #define	atomic_set_acq_ptr(p, v) \
8486f0f8ccaSDag-Erling Smørgrav 	atomic_set_acq_int((volatile u_int *)(p), (u_int)(v))
8496f0f8ccaSDag-Erling Smørgrav #define	atomic_set_rel_ptr(p, v) \
8506f0f8ccaSDag-Erling Smørgrav 	atomic_set_rel_int((volatile u_int *)(p), (u_int)(v))
8516f0f8ccaSDag-Erling Smørgrav #define	atomic_clear_ptr(p, v) \
8526f0f8ccaSDag-Erling Smørgrav 	atomic_clear_int((volatile u_int *)(p), (u_int)(v))
8536f0f8ccaSDag-Erling Smørgrav #define	atomic_clear_acq_ptr(p, v) \
8546f0f8ccaSDag-Erling Smørgrav 	atomic_clear_acq_int((volatile u_int *)(p), (u_int)(v))
8556f0f8ccaSDag-Erling Smørgrav #define	atomic_clear_rel_ptr(p, v) \
8566f0f8ccaSDag-Erling Smørgrav 	atomic_clear_rel_int((volatile u_int *)(p), (u_int)(v))
8576f0f8ccaSDag-Erling Smørgrav #define	atomic_add_ptr(p, v) \
8586f0f8ccaSDag-Erling Smørgrav 	atomic_add_int((volatile u_int *)(p), (u_int)(v))
8596f0f8ccaSDag-Erling Smørgrav #define	atomic_add_acq_ptr(p, v) \
8606f0f8ccaSDag-Erling Smørgrav 	atomic_add_acq_int((volatile u_int *)(p), (u_int)(v))
8616f0f8ccaSDag-Erling Smørgrav #define	atomic_add_rel_ptr(p, v) \
8626f0f8ccaSDag-Erling Smørgrav 	atomic_add_rel_int((volatile u_int *)(p), (u_int)(v))
8636f0f8ccaSDag-Erling Smørgrav #define	atomic_subtract_ptr(p, v) \
8646f0f8ccaSDag-Erling Smørgrav 	atomic_subtract_int((volatile u_int *)(p), (u_int)(v))
8656f0f8ccaSDag-Erling Smørgrav #define	atomic_subtract_acq_ptr(p, v) \
8666f0f8ccaSDag-Erling Smørgrav 	atomic_subtract_acq_int((volatile u_int *)(p), (u_int)(v))
8676f0f8ccaSDag-Erling Smørgrav #define	atomic_subtract_rel_ptr(p, v) \
8686f0f8ccaSDag-Erling Smørgrav 	atomic_subtract_rel_int((volatile u_int *)(p), (u_int)(v))
8696f0f8ccaSDag-Erling Smørgrav #define	atomic_load_acq_ptr(p) \
8706f0f8ccaSDag-Erling Smørgrav 	atomic_load_acq_int((volatile u_int *)(p))
8716f0f8ccaSDag-Erling Smørgrav #define	atomic_store_rel_ptr(p, v) \
8726f0f8ccaSDag-Erling Smørgrav 	atomic_store_rel_int((volatile u_int *)(p), (v))
8736f0f8ccaSDag-Erling Smørgrav #define	atomic_cmpset_ptr(dst, old, new) \
8746f0f8ccaSDag-Erling Smørgrav 	atomic_cmpset_int((volatile u_int *)(dst), (u_int)(old), (u_int)(new))
8756f0f8ccaSDag-Erling Smørgrav #define	atomic_cmpset_acq_ptr(dst, old, new) \
8766c296ffaSBruce Evans 	atomic_cmpset_acq_int((volatile u_int *)(dst), (u_int)(old), \
8776c296ffaSBruce Evans 	    (u_int)(new))
8786f0f8ccaSDag-Erling Smørgrav #define	atomic_cmpset_rel_ptr(dst, old, new) \
8796c296ffaSBruce Evans 	atomic_cmpset_rel_int((volatile u_int *)(dst), (u_int)(old), \
8806c296ffaSBruce Evans 	    (u_int)(new))
881e7a98aefSMateusz Guzik #define	atomic_fcmpset_ptr(dst, old, new) \
882e7a98aefSMateusz Guzik 	atomic_fcmpset_int((volatile u_int *)(dst), (u_int *)(old), (u_int)(new))
883e7a98aefSMateusz Guzik #define	atomic_fcmpset_acq_ptr(dst, old, new) \
884e7a98aefSMateusz Guzik 	atomic_fcmpset_acq_int((volatile u_int *)(dst), (u_int *)(old), \
885e7a98aefSMateusz Guzik 	    (u_int)(new))
886e7a98aefSMateusz Guzik #define	atomic_fcmpset_rel_ptr(dst, old, new) \
887e7a98aefSMateusz Guzik 	atomic_fcmpset_rel_int((volatile u_int *)(dst), (u_int *)(old), \
888e7a98aefSMateusz Guzik 	    (u_int)(new))
8898a1ee2d3SJung-uk Kim #define	atomic_swap_ptr(p, v) \
8908a1ee2d3SJung-uk Kim 	atomic_swap_int((volatile u_int *)(p), (u_int)(v))
8916f0f8ccaSDag-Erling Smørgrav #define	atomic_readandclear_ptr(p) \
8926f0f8ccaSDag-Erling Smørgrav 	atomic_readandclear_int((volatile u_int *)(p))
893ccbdd9eeSJohn Baldwin 
894f28e1c8fSBruce Evans #endif /* !WANT_FUNCTIONS */
8956c296ffaSBruce Evans 
89648cae112SKonstantin Belousov #if defined(_KERNEL)
89748cae112SKonstantin Belousov #define	mb()	__mbk()
89848cae112SKonstantin Belousov #define	wmb()	__mbk()
89948cae112SKonstantin Belousov #define	rmb()	__mbk()
90048cae112SKonstantin Belousov #else
90148cae112SKonstantin Belousov #define	mb()	__mbu()
90248cae112SKonstantin Belousov #define	wmb()	__mbu()
90348cae112SKonstantin Belousov #define	rmb()	__mbu()
90448cae112SKonstantin Belousov #endif
90548cae112SKonstantin Belousov 
906069e9bc1SDoug Rabson #endif /* !_MACHINE_ATOMIC_H_ */
907