atomic.h revision 100251
138517Sdfr/*-
238517Sdfr * Copyright (c) 1998 Doug Rabson
338517Sdfr * All rights reserved.
438517Sdfr *
538517Sdfr * Redistribution and use in source and binary forms, with or without
638517Sdfr * modification, are permitted provided that the following conditions
738517Sdfr * are met:
838517Sdfr * 1. Redistributions of source code must retain the above copyright
938517Sdfr *    notice, this list of conditions and the following disclaimer.
1038517Sdfr * 2. Redistributions in binary form must reproduce the above copyright
1138517Sdfr *    notice, this list of conditions and the following disclaimer in the
1238517Sdfr *    documentation and/or other materials provided with the distribution.
1338517Sdfr *
1438517Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1538517Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1638517Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1738517Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1838517Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1938517Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2038517Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2138517Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2238517Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2338517Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2438517Sdfr * SUCH DAMAGE.
2538517Sdfr *
2650477Speter * $FreeBSD: head/sys/i386/include/atomic.h 100251 2002-07-17 16:19:37Z markm $
2738517Sdfr */
2838517Sdfr#ifndef _MACHINE_ATOMIC_H_
2938517Sdfr#define _MACHINE_ATOMIC_H_
3038517Sdfr
31100251Smarkm#ifndef __GNUC__
32100251Smarkm#ifndef lint
33100251Smarkm#error "This file must be compiled with GCC or lint"
34100251Smarkm#endif /* lint */
35100251Smarkm#endif /* __GNUC__ */
36100251Smarkm
3738517Sdfr/*
3838517Sdfr * Various simple arithmetic on memory which is atomic in the presence
3948797Salc * of interrupts and multiple processors.
4038517Sdfr *
4148797Salc * atomic_set_char(P, V)	(*(u_char*)(P) |= (V))
4248797Salc * atomic_clear_char(P, V)	(*(u_char*)(P) &= ~(V))
4348797Salc * atomic_add_char(P, V)	(*(u_char*)(P) += (V))
4448797Salc * atomic_subtract_char(P, V)	(*(u_char*)(P) -= (V))
4548797Salc *
4648797Salc * atomic_set_short(P, V)	(*(u_short*)(P) |= (V))
4748797Salc * atomic_clear_short(P, V)	(*(u_short*)(P) &= ~(V))
4848797Salc * atomic_add_short(P, V)	(*(u_short*)(P) += (V))
4948797Salc * atomic_subtract_short(P, V)	(*(u_short*)(P) -= (V))
5048797Salc *
5148797Salc * atomic_set_int(P, V)		(*(u_int*)(P) |= (V))
5248797Salc * atomic_clear_int(P, V)	(*(u_int*)(P) &= ~(V))
5348797Salc * atomic_add_int(P, V)		(*(u_int*)(P) += (V))
5448797Salc * atomic_subtract_int(P, V)	(*(u_int*)(P) -= (V))
5566695Sjhb * atomic_readandclear_int(P)	(return  *(u_int*)P; *(u_int*)P = 0;)
5648797Salc *
5748797Salc * atomic_set_long(P, V)	(*(u_long*)(P) |= (V))
5848797Salc * atomic_clear_long(P, V)	(*(u_long*)(P) &= ~(V))
5948797Salc * atomic_add_long(P, V)	(*(u_long*)(P) += (V))
6048797Salc * atomic_subtract_long(P, V)	(*(u_long*)(P) -= (V))
6166695Sjhb * atomic_readandclear_long(P)	(return  *(u_long*)P; *(u_long*)P = 0;)
6238517Sdfr */
6338517Sdfr
6448797Salc/*
6549999Salc * The above functions are expanded inline in the statically-linked
6649999Salc * kernel.  Lock prefixes are generated if an SMP kernel is being
6749999Salc * built.
6849999Salc *
6949999Salc * Kernel modules call real functions which are built into the kernel.
7049999Salc * This allows kernel modules to be portable between UP and SMP systems.
7148797Salc */
7249999Salc#if defined(KLD_MODULE)
7388117Sjhb#define ATOMIC_ASM(NAME, TYPE, OP, CONS, V)			\
74100251Smarkmvoid atomic_##NAME##_##TYPE(volatile u_##TYPE *p, u_##TYPE v)
7549999Salc
7666695Sjhbint atomic_cmpset_int(volatile u_int *dst, u_int exp, u_int src);
7765514Sphk
7871085Sjhb#define	ATOMIC_STORE_LOAD(TYPE, LOP, SOP)			\
7971085Sjhbu_##TYPE	atomic_load_acq_##TYPE(volatile u_##TYPE *p);	\
80100251Smarkmvoid		atomic_store_rel_##TYPE(volatile u_##TYPE *p, u_##TYPE v)
8171085Sjhb
8249999Salc#else /* !KLD_MODULE */
8372358Smarkm
8484679Sjhb/*
8584679Sjhb * For userland, assume the SMP case and use lock prefixes so that
8684679Sjhb * the binaries will run on both types of systems.
8784679Sjhb */
8884679Sjhb#if defined(SMP) || !defined(_KERNEL)
8991469Sbmilekic#define MPLOCKED	lock ;
9090515Sbde#else
9148797Salc#define MPLOCKED
9290515Sbde#endif
9338517Sdfr
9448797Salc/*
9548797Salc * The assembly is volatilized to demark potential before-and-after side
9648797Salc * effects if an interrupt or SMP collision were to occur.
9748797Salc */
98100251Smarkm#ifdef __GNUC__
9988117Sjhb#define ATOMIC_ASM(NAME, TYPE, OP, CONS, V)		\
10048797Salcstatic __inline void					\
10149043Salcatomic_##NAME##_##TYPE(volatile u_##TYPE *p, u_##TYPE v)\
10248797Salc{							\
10391469Sbmilekic	__asm __volatile(__XSTRING(MPLOCKED) OP		\
10486301Sjhb			 : "+m" (*p)			\
10588117Sjhb			 : CONS (V));			\
10648797Salc}
107100251Smarkm#else /* !__GNUC__ */
108100251Smarkm#define ATOMIC_ASM(NAME, TYPE, OP, CONS, V)			\
109100251Smarkmvoid atomic_##NAME##_##TYPE(volatile u_##TYPE *p, u_##TYPE v)
110100251Smarkm#endif /* __GNUC__ */
11151938Speter
11265514Sphk/*
11365514Sphk * Atomic compare and set, used by the mutex functions
11465514Sphk *
11565514Sphk * if (*dst == exp) *dst = src (all 32 bit words)
11665514Sphk *
11765514Sphk * Returns 0 on failure, non-zero on success
11865514Sphk */
11965514Sphk
120100251Smarkm#if defined(__GNUC__)
12165514Sphk#if defined(I386_CPU)
12265514Sphkstatic __inline int
12365514Sphkatomic_cmpset_int(volatile u_int *dst, u_int exp, u_int src)
12465514Sphk{
12565514Sphk	int res = exp;
12665514Sphk
12765514Sphk	__asm __volatile(
12865514Sphk	"	pushfl ;		"
12965514Sphk	"	cli ;			"
13086303Sjhb	"	cmpl	%0,%2 ;		"
13165514Sphk	"	jne	1f ;		"
13286303Sjhb	"	movl	%1,%2 ;		"
13365514Sphk	"1:				"
13465514Sphk	"       sete	%%al;		"
13565514Sphk	"	movzbl	%%al,%0 ;	"
13665514Sphk	"	popfl ;			"
13765514Sphk	"# atomic_cmpset_int"
13886303Sjhb	: "+a" (res)			/* 0 (result) */
13986303Sjhb	: "r" (src),			/* 1 */
14086303Sjhb	  "m" (*(dst))			/* 2 */
14165514Sphk	: "memory");
14265514Sphk
14365514Sphk	return (res);
14465514Sphk}
14565514Sphk#else /* defined(I386_CPU) */
14665514Sphkstatic __inline int
14765514Sphkatomic_cmpset_int(volatile u_int *dst, u_int exp, u_int src)
14865514Sphk{
14965514Sphk	int res = exp;
15065514Sphk
15165514Sphk	__asm __volatile (
15291469Sbmilekic	"	" __XSTRING(MPLOCKED) "	"
15386303Sjhb	"	cmpxchgl %1,%2 ;	"
15465514Sphk	"       setz	%%al ;		"
15565514Sphk	"	movzbl	%%al,%0 ;	"
15665514Sphk	"1:				"
15765514Sphk	"# atomic_cmpset_int"
15886303Sjhb	: "+a" (res)			/* 0 (result) */
15986303Sjhb	: "r" (src),			/* 1 */
16086303Sjhb	  "m" (*(dst))			/* 2 */
16165514Sphk	: "memory");
16265514Sphk
16365514Sphk	return (res);
16465514Sphk}
16565514Sphk#endif /* defined(I386_CPU) */
166100251Smarkm#else /* !defined(__GNUC__) */
167100251Smarkmstatic __inline int
168100251Smarkmatomic_cmpset_int(volatile u_int *dst __unused, u_int exp __unused,
169100251Smarkm    u_int src __unused)
170100251Smarkm{
171100251Smarkm}
172100251Smarkm#endif /* defined(__GNUC__) */
17365514Sphk
174100251Smarkm#if defined(__GNUC__)
17571023Sjhb#if defined(I386_CPU)
17667351Sjhb/*
17767351Sjhb * We assume that a = b will do atomic loads and stores.
17871023Sjhb *
17971023Sjhb * XXX: This is _NOT_ safe on a P6 or higher because it does not guarantee
18071023Sjhb * memory ordering.  These should only be used on a 386.
18167351Sjhb */
18271023Sjhb#define ATOMIC_STORE_LOAD(TYPE, LOP, SOP)		\
18367351Sjhbstatic __inline u_##TYPE				\
18467351Sjhbatomic_load_acq_##TYPE(volatile u_##TYPE *p)		\
18567351Sjhb{							\
18667351Sjhb	return (*p);					\
18767351Sjhb}							\
18867351Sjhb							\
18967351Sjhbstatic __inline void					\
19067351Sjhbatomic_store_rel_##TYPE(volatile u_##TYPE *p, u_##TYPE v)\
19167351Sjhb{							\
19267351Sjhb	*p = v;						\
19367351Sjhb	__asm __volatile("" : : : "memory");		\
19467351Sjhb}
195100251Smarkm#else /* !defined(I386_CPU) */
19667351Sjhb
19771023Sjhb#define ATOMIC_STORE_LOAD(TYPE, LOP, SOP)		\
19871023Sjhbstatic __inline u_##TYPE				\
19971023Sjhbatomic_load_acq_##TYPE(volatile u_##TYPE *p)		\
20071023Sjhb{							\
20171023Sjhb	u_##TYPE res;					\
20271023Sjhb							\
20391469Sbmilekic	__asm __volatile(__XSTRING(MPLOCKED) LOP	\
20471141Sjhb	: "=a" (res),			/* 0 (result) */\
20571023Sjhb	  "+m" (*p)			/* 1 */		\
20688117Sjhb	: : "memory");				 	\
20771023Sjhb							\
20871023Sjhb	return (res);					\
20971023Sjhb}							\
21071023Sjhb							\
21171023Sjhb/*							\
21271023Sjhb * The XCHG instruction asserts LOCK automagically.	\
21371023Sjhb */							\
21471023Sjhbstatic __inline void					\
21571023Sjhbatomic_store_rel_##TYPE(volatile u_##TYPE *p, u_##TYPE v)\
21671023Sjhb{							\
21771023Sjhb	__asm __volatile(SOP				\
21871023Sjhb	: "+m" (*p),			/* 0 */		\
21971023Sjhb	  "+r" (v)			/* 1 */		\
22071023Sjhb	: : "memory");				 	\
22171023Sjhb}
22271023Sjhb#endif	/* defined(I386_CPU) */
223100251Smarkm#else /* !defined(__GNUC__) */
224100251Smarkm
225100251Smarkm/*
226100251Smarkm * XXXX: Dummy functions!!
227100251Smarkm */
228100251Smarkm#define ATOMIC_STORE_LOAD(TYPE, LOP, SOP)			\
229100251Smarkmu_##TYPE atomic_load_acq_##TYPE(volatile u_##TYPE *p __unused);	\
230100251Smarkmvoid atomic_store_rel_##TYPE(volatile u_##TYPE *p __unused,	\
231100251Smarkm    u_##TYPE v __unused)
232100251Smarkm
233100251Smarkm#endif /* defined(__GNUC__) */
23471085Sjhb#endif /* KLD_MODULE */
23567351Sjhb
236100251SmarkmATOMIC_ASM(set,	     char,  "orb %b1,%0",  "iq",  v);
237100251SmarkmATOMIC_ASM(clear,    char,  "andb %b1,%0", "iq", ~v);
238100251SmarkmATOMIC_ASM(add,	     char,  "addb %b1,%0", "iq",  v);
239100251SmarkmATOMIC_ASM(subtract, char,  "subb %b1,%0", "iq",  v);
24071085Sjhb
241100251SmarkmATOMIC_ASM(set,	     short, "orw %w1,%0",  "ir",  v);
242100251SmarkmATOMIC_ASM(clear,    short, "andw %w1,%0", "ir", ~v);
243100251SmarkmATOMIC_ASM(add,	     short, "addw %w1,%0", "ir",  v);
244100251SmarkmATOMIC_ASM(subtract, short, "subw %w1,%0", "ir",  v);
24571085Sjhb
246100251SmarkmATOMIC_ASM(set,	     int,   "orl %1,%0",   "ir",  v);
247100251SmarkmATOMIC_ASM(clear,    int,   "andl %1,%0",  "ir", ~v);
248100251SmarkmATOMIC_ASM(add,	     int,   "addl %1,%0",  "ir",  v);
249100251SmarkmATOMIC_ASM(subtract, int,   "subl %1,%0",  "ir",  v);
25071085Sjhb
251100251SmarkmATOMIC_ASM(set,	     long,  "orl %1,%0",   "ir",  v);
252100251SmarkmATOMIC_ASM(clear,    long,  "andl %1,%0",  "ir", ~v);
253100251SmarkmATOMIC_ASM(add,	     long,  "addl %1,%0",  "ir",  v);
254100251SmarkmATOMIC_ASM(subtract, long,  "subl %1,%0",  "ir",  v);
25571085Sjhb
256100251SmarkmATOMIC_STORE_LOAD(char,	"cmpxchgb %b0,%1", "xchgb %b1,%0");
257100251SmarkmATOMIC_STORE_LOAD(short,"cmpxchgw %w0,%1", "xchgw %w1,%0");
258100251SmarkmATOMIC_STORE_LOAD(int,	"cmpxchgl %0,%1",  "xchgl %1,%0");
259100251SmarkmATOMIC_STORE_LOAD(long,	"cmpxchgl %0,%1",  "xchgl %1,%0");
26071023Sjhb
26171085Sjhb#undef ATOMIC_ASM
26267351Sjhb#undef ATOMIC_STORE_LOAD
26367351Sjhb
26471085Sjhb#define	atomic_set_acq_char		atomic_set_char
26571085Sjhb#define	atomic_set_rel_char		atomic_set_char
26671085Sjhb#define	atomic_clear_acq_char		atomic_clear_char
26771085Sjhb#define	atomic_clear_rel_char		atomic_clear_char
26871085Sjhb#define	atomic_add_acq_char		atomic_add_char
26971085Sjhb#define	atomic_add_rel_char		atomic_add_char
27071085Sjhb#define	atomic_subtract_acq_char	atomic_subtract_char
27171085Sjhb#define	atomic_subtract_rel_char	atomic_subtract_char
27271085Sjhb
27371085Sjhb#define	atomic_set_acq_short		atomic_set_short
27471085Sjhb#define	atomic_set_rel_short		atomic_set_short
27571085Sjhb#define	atomic_clear_acq_short		atomic_clear_short
27671085Sjhb#define	atomic_clear_rel_short		atomic_clear_short
27771085Sjhb#define	atomic_add_acq_short		atomic_add_short
27871085Sjhb#define	atomic_add_rel_short		atomic_add_short
27971085Sjhb#define	atomic_subtract_acq_short	atomic_subtract_short
28071085Sjhb#define	atomic_subtract_rel_short	atomic_subtract_short
28171085Sjhb
28271085Sjhb#define	atomic_set_acq_int		atomic_set_int
28371085Sjhb#define	atomic_set_rel_int		atomic_set_int
28471085Sjhb#define	atomic_clear_acq_int		atomic_clear_int
28571085Sjhb#define	atomic_clear_rel_int		atomic_clear_int
28671085Sjhb#define	atomic_add_acq_int		atomic_add_int
28771085Sjhb#define	atomic_add_rel_int		atomic_add_int
28871085Sjhb#define	atomic_subtract_acq_int		atomic_subtract_int
28971085Sjhb#define	atomic_subtract_rel_int		atomic_subtract_int
29071085Sjhb#define atomic_cmpset_acq_int		atomic_cmpset_int
29171085Sjhb#define atomic_cmpset_rel_int		atomic_cmpset_int
29271085Sjhb
29371085Sjhb#define	atomic_set_acq_long		atomic_set_long
29471085Sjhb#define	atomic_set_rel_long		atomic_set_long
29571085Sjhb#define	atomic_clear_acq_long		atomic_clear_long
29671085Sjhb#define	atomic_clear_rel_long		atomic_clear_long
29771085Sjhb#define	atomic_add_acq_long		atomic_add_long
29871085Sjhb#define	atomic_add_rel_long		atomic_add_long
29971085Sjhb#define	atomic_subtract_acq_long	atomic_subtract_long
30071085Sjhb#define	atomic_subtract_rel_long	atomic_subtract_long
30171085Sjhb#define	atomic_cmpset_long		atomic_cmpset_int
30271085Sjhb#define	atomic_cmpset_acq_long		atomic_cmpset_acq_int
30371085Sjhb#define	atomic_cmpset_rel_long		atomic_cmpset_rel_int
30471085Sjhb
30571085Sjhb#define atomic_cmpset_acq_ptr		atomic_cmpset_ptr
30671085Sjhb#define atomic_cmpset_rel_ptr		atomic_cmpset_ptr
30771085Sjhb
30871085Sjhb#define	atomic_set_8		atomic_set_char
30971085Sjhb#define	atomic_set_acq_8	atomic_set_acq_char
31071085Sjhb#define	atomic_set_rel_8	atomic_set_rel_char
31171085Sjhb#define	atomic_clear_8		atomic_clear_char
31271085Sjhb#define	atomic_clear_acq_8	atomic_clear_acq_char
31371085Sjhb#define	atomic_clear_rel_8	atomic_clear_rel_char
31471085Sjhb#define	atomic_add_8		atomic_add_char
31571085Sjhb#define	atomic_add_acq_8	atomic_add_acq_char
31671085Sjhb#define	atomic_add_rel_8	atomic_add_rel_char
31771085Sjhb#define	atomic_subtract_8	atomic_subtract_char
31871085Sjhb#define	atomic_subtract_acq_8	atomic_subtract_acq_char
31971085Sjhb#define	atomic_subtract_rel_8	atomic_subtract_rel_char
32071085Sjhb#define	atomic_load_acq_8	atomic_load_acq_char
32171085Sjhb#define	atomic_store_rel_8	atomic_store_rel_char
32271085Sjhb
32371085Sjhb#define	atomic_set_16		atomic_set_short
32471085Sjhb#define	atomic_set_acq_16	atomic_set_acq_short
32571085Sjhb#define	atomic_set_rel_16	atomic_set_rel_short
32671085Sjhb#define	atomic_clear_16		atomic_clear_short
32771085Sjhb#define	atomic_clear_acq_16	atomic_clear_acq_short
32871085Sjhb#define	atomic_clear_rel_16	atomic_clear_rel_short
32971085Sjhb#define	atomic_add_16		atomic_add_short
33071085Sjhb#define	atomic_add_acq_16	atomic_add_acq_short
33171085Sjhb#define	atomic_add_rel_16	atomic_add_rel_short
33271085Sjhb#define	atomic_subtract_16	atomic_subtract_short
33371085Sjhb#define	atomic_subtract_acq_16	atomic_subtract_acq_short
33471085Sjhb#define	atomic_subtract_rel_16	atomic_subtract_rel_short
33571085Sjhb#define	atomic_load_acq_16	atomic_load_acq_short
33671085Sjhb#define	atomic_store_rel_16	atomic_store_rel_short
33771085Sjhb
33871085Sjhb#define	atomic_set_32		atomic_set_int
33971085Sjhb#define	atomic_set_acq_32	atomic_set_acq_int
34071085Sjhb#define	atomic_set_rel_32	atomic_set_rel_int
34171085Sjhb#define	atomic_clear_32		atomic_clear_int
34271085Sjhb#define	atomic_clear_acq_32	atomic_clear_acq_int
34371085Sjhb#define	atomic_clear_rel_32	atomic_clear_rel_int
34471085Sjhb#define	atomic_add_32		atomic_add_int
34571085Sjhb#define	atomic_add_acq_32	atomic_add_acq_int
34671085Sjhb#define	atomic_add_rel_32	atomic_add_rel_int
34771085Sjhb#define	atomic_subtract_32	atomic_subtract_int
34871085Sjhb#define	atomic_subtract_acq_32	atomic_subtract_acq_int
34971085Sjhb#define	atomic_subtract_rel_32	atomic_subtract_rel_int
35071085Sjhb#define	atomic_load_acq_32	atomic_load_acq_int
35171085Sjhb#define	atomic_store_rel_32	atomic_store_rel_int
35271085Sjhb#define	atomic_cmpset_32	atomic_cmpset_int
35371085Sjhb#define	atomic_cmpset_acq_32	atomic_cmpset_acq_int
35471085Sjhb#define	atomic_cmpset_rel_32	atomic_cmpset_rel_int
35571085Sjhb#define	atomic_readandclear_32	atomic_readandclear_int
35671085Sjhb
35771085Sjhb#if !defined(WANT_FUNCTIONS)
35865514Sphkstatic __inline int
35965514Sphkatomic_cmpset_ptr(volatile void *dst, void *exp, void *src)
36065514Sphk{
36165514Sphk
36271085Sjhb	return (atomic_cmpset_int((volatile u_int *)dst, (u_int)exp,
36371085Sjhb	    (u_int)src));
36465514Sphk}
36566695Sjhb
36667351Sjhbstatic __inline void *
36767351Sjhbatomic_load_acq_ptr(volatile void *p)
36867351Sjhb{
36967351Sjhb	return (void *)atomic_load_acq_int((volatile u_int *)p);
37067351Sjhb}
37167351Sjhb
37267351Sjhbstatic __inline void
37367351Sjhbatomic_store_rel_ptr(volatile void *p, void *v)
37467351Sjhb{
37567351Sjhb	atomic_store_rel_int((volatile u_int *)p, (u_int)v);
37667351Sjhb}
37767351Sjhb
37867351Sjhb#define ATOMIC_PTR(NAME)				\
37967351Sjhbstatic __inline void					\
38067351Sjhbatomic_##NAME##_ptr(volatile void *p, uintptr_t v)	\
38167351Sjhb{							\
38267351Sjhb	atomic_##NAME##_int((volatile u_int *)p, v);	\
38367351Sjhb}							\
38467351Sjhb							\
38567351Sjhbstatic __inline void					\
38667351Sjhbatomic_##NAME##_acq_ptr(volatile void *p, uintptr_t v)	\
38767351Sjhb{							\
38867351Sjhb	atomic_##NAME##_acq_int((volatile u_int *)p, v);\
38967351Sjhb}							\
39067351Sjhb							\
39167351Sjhbstatic __inline void					\
39267351Sjhbatomic_##NAME##_rel_ptr(volatile void *p, uintptr_t v)	\
39367351Sjhb{							\
39467351Sjhb	atomic_##NAME##_rel_int((volatile u_int *)p, v);\
39567351Sjhb}
39667351Sjhb
39767351SjhbATOMIC_PTR(set)
39867351SjhbATOMIC_PTR(clear)
39967351SjhbATOMIC_PTR(add)
40067351SjhbATOMIC_PTR(subtract)
40167351Sjhb
40267351Sjhb#undef ATOMIC_PTR
40367351Sjhb
404100251Smarkm#if defined(__GNUC__)
40566695Sjhbstatic __inline u_int
40666695Sjhbatomic_readandclear_int(volatile u_int *addr)
40766695Sjhb{
40866695Sjhb	u_int result;
40966695Sjhb
41066695Sjhb	__asm __volatile (
41166695Sjhb	"	xorl	%0,%0 ;		"
41266695Sjhb	"	xchgl	%1,%0 ;		"
41366695Sjhb	"# atomic_readandclear_int"
41466695Sjhb	: "=&r" (result)		/* 0 (result) */
41566695Sjhb	: "m" (*addr));			/* 1 (addr) */
41666695Sjhb
41766695Sjhb	return (result);
41866695Sjhb}
419100251Smarkm#else /* !defined(__GNUC__) */
420100251Smarkm/*
421100251Smarkm * XXXX: Dummy!
422100251Smarkm */
423100251Smarkmstatic __inline u_int
424100251Smarkmatomic_readandclear_int(volatile u_int *addr __unused)
425100251Smarkm{
426100251Smarkm}
427100251Smarkm#endif /* defined(__GNUC__) */
42866695Sjhb
429100251Smarkm#if defined(__GNUC__)
43066695Sjhbstatic __inline u_long
43166695Sjhbatomic_readandclear_long(volatile u_long *addr)
43266695Sjhb{
43366695Sjhb	u_long result;
43466695Sjhb
43566695Sjhb	__asm __volatile (
43666695Sjhb	"	xorl	%0,%0 ;		"
43766695Sjhb	"	xchgl	%1,%0 ;		"
43866695Sjhb	"# atomic_readandclear_int"
43966695Sjhb	: "=&r" (result)		/* 0 (result) */
44066695Sjhb	: "m" (*addr));			/* 1 (addr) */
44166695Sjhb
44266695Sjhb	return (result);
44366695Sjhb}
444100251Smarkm#else /* !defined(__GNUC__) */
445100251Smarkm/*
446100251Smarkm * XXXX: Dummy!
447100251Smarkm */
448100251Smarkmstatic __inline u_long
449100251Smarkmatomic_readandclear_long(volatile u_long *addr __unused)
450100251Smarkm{
451100251Smarkm}
452100251Smarkm#endif /* defined(__GNUC__) */
45371085Sjhb#endif	/* !defined(WANT_FUNCTIONS) */
45438517Sdfr#endif /* ! _MACHINE_ATOMIC_H_ */
455