xref: /openbsd-src/sys/arch/amd64/include/atomic.h (revision 58689e6b0b5995de18bdddc69f544418dde3b8bd)
1*58689e6bSjca /*	$OpenBSD: atomic.h,v 1.23 2023/11/11 18:47:02 jca Exp $	*/
2f5df1827Smickey /*	$NetBSD: atomic.h,v 1.1 2003/04/26 18:39:37 fvdl Exp $	*/
3f5df1827Smickey 
4f5df1827Smickey /*
5f5df1827Smickey  * Copyright 2002 (c) Wasabi Systems, Inc.
6f5df1827Smickey  * All rights reserved.
7f5df1827Smickey  *
8f5df1827Smickey  * Written by Frank van der Linden for Wasabi Systems, Inc.
9f5df1827Smickey  *
10f5df1827Smickey  * Redistribution and use in source and binary forms, with or without
11f5df1827Smickey  * modification, are permitted provided that the following conditions
12f5df1827Smickey  * are met:
13f5df1827Smickey  * 1. Redistributions of source code must retain the above copyright
14f5df1827Smickey  *    notice, this list of conditions and the following disclaimer.
15f5df1827Smickey  * 2. Redistributions in binary form must reproduce the above copyright
16f5df1827Smickey  *    notice, this list of conditions and the following disclaimer in the
17f5df1827Smickey  *    documentation and/or other materials provided with the distribution.
18f5df1827Smickey  * 3. All advertising materials mentioning features or use of this software
19f5df1827Smickey  *    must display the following acknowledgement:
20f5df1827Smickey  *      This product includes software developed for the NetBSD Project by
21f5df1827Smickey  *      Wasabi Systems, Inc.
22f5df1827Smickey  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
23f5df1827Smickey  *    or promote products derived from this software without specific prior
24f5df1827Smickey  *    written permission.
25f5df1827Smickey  *
26f5df1827Smickey  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
27f5df1827Smickey  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28f5df1827Smickey  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29f5df1827Smickey  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
30f5df1827Smickey  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31f5df1827Smickey  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32f5df1827Smickey  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33f5df1827Smickey  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34f5df1827Smickey  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35f5df1827Smickey  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36f5df1827Smickey  * POSSIBILITY OF SUCH DAMAGE.
37f5df1827Smickey  */
38f5df1827Smickey 
392fa72412Spirofti #ifndef _MACHINE_ATOMIC_H_
402fa72412Spirofti #define _MACHINE_ATOMIC_H_
41f5df1827Smickey 
42f57756c9Sart /*
43f57756c9Sart  * Perform atomic operations on memory. Should be atomic with respect
44f57756c9Sart  * to interrupts and multiple processors.
45f57756c9Sart  *
46f57756c9Sart  * void atomic_setbits_int(volatile u_int *a, u_int mask) { *a |= mask; }
47*58689e6bSjca  * void atomic_clearbits_int(volatile u_int *a, u_int mask) { *a &= ~mask; }
48f57756c9Sart  */
49f57756c9Sart 
50b67e4186Smpi #if !defined(_LOCORE)
51f5df1827Smickey 
52b67e4186Smpi #if defined(MULTIPROCESSOR) || !defined(_KERNEL)
53b67e4186Smpi #define _LOCK "lock"
54f57756c9Sart #else
55b67e4186Smpi #define _LOCK
56f57756c9Sart #endif
57f57756c9Sart 
58813b3f90Sdlg static inline unsigned int
_atomic_cas_uint(volatile unsigned int * p,unsigned int e,unsigned int n)59813b3f90Sdlg _atomic_cas_uint(volatile unsigned int *p, unsigned int e, unsigned int n)
60813b3f90Sdlg {
61b67e4186Smpi 	__asm volatile(_LOCK " cmpxchgl %2, %1"
62813b3f90Sdlg 	    : "=a" (n), "=m" (*p)
63e3eaccaeSguenther 	    : "r" (n), "a" (e), "m" (*p));
64813b3f90Sdlg 
65813b3f90Sdlg 	return (n);
66813b3f90Sdlg }
67813b3f90Sdlg #define atomic_cas_uint(_p, _e, _n) _atomic_cas_uint((_p), (_e), (_n))
68813b3f90Sdlg 
69813b3f90Sdlg static inline unsigned long
_atomic_cas_ulong(volatile unsigned long * p,unsigned long e,unsigned long n)70813b3f90Sdlg _atomic_cas_ulong(volatile unsigned long *p, unsigned long e, unsigned long n)
71813b3f90Sdlg {
72b67e4186Smpi 	__asm volatile(_LOCK " cmpxchgq %2, %1"
73813b3f90Sdlg 	    : "=a" (n), "=m" (*p)
74e3eaccaeSguenther 	    : "r" (n), "a" (e), "m" (*p));
75813b3f90Sdlg 
76813b3f90Sdlg 	return (n);
77813b3f90Sdlg }
78813b3f90Sdlg #define atomic_cas_ulong(_p, _e, _n) _atomic_cas_ulong((_p), (_e), (_n))
79813b3f90Sdlg 
80813b3f90Sdlg static inline void *
_atomic_cas_ptr(volatile void * p,void * e,void * n)81b6a8cdecSdlg _atomic_cas_ptr(volatile void *p, void *e, void *n)
82813b3f90Sdlg {
83b67e4186Smpi 	__asm volatile(_LOCK " cmpxchgq %2, %1"
84b6a8cdecSdlg 	    : "=a" (n), "=m" (*(unsigned long *)p)
85e3eaccaeSguenther 	    : "r" (n), "a" (e), "m" (*(unsigned long *)p));
86813b3f90Sdlg 
87813b3f90Sdlg 	return (n);
88813b3f90Sdlg }
89813b3f90Sdlg #define atomic_cas_ptr(_p, _e, _n) _atomic_cas_ptr((_p), (_e), (_n))
90813b3f90Sdlg 
919b702505Sdlg static inline unsigned int
_atomic_swap_uint(volatile unsigned int * p,unsigned int n)929b702505Sdlg _atomic_swap_uint(volatile unsigned int *p, unsigned int n)
939b702505Sdlg {
949b702505Sdlg 	__asm volatile("xchgl %0, %1"
959b702505Sdlg 	    : "=a" (n), "=m" (*p)
969b702505Sdlg 	    : "0" (n), "m" (*p));
979b702505Sdlg 
989b702505Sdlg 	return (n);
999b702505Sdlg }
1009b702505Sdlg #define atomic_swap_uint(_p, _n) _atomic_swap_uint((_p), (_n))
1019b702505Sdlg #define atomic_swap_32(_p, _n) _atomic_swap_uint((_p), (_n))
1029b702505Sdlg 
1039b702505Sdlg static inline unsigned long
_atomic_swap_ulong(volatile unsigned long * p,unsigned long n)1049b702505Sdlg _atomic_swap_ulong(volatile unsigned long *p, unsigned long n)
1059b702505Sdlg {
1069b702505Sdlg 	__asm volatile("xchgq %0, %1"
1079b702505Sdlg 	    : "=a" (n), "=m" (*p)
1089b702505Sdlg 	    : "0" (n), "m" (*p));
1099b702505Sdlg 
1109b702505Sdlg 	return (n);
1119b702505Sdlg }
1129b702505Sdlg #define atomic_swap_ulong(_p, _n) _atomic_swap_ulong((_p), (_n))
1139b702505Sdlg 
1149b702505Sdlg static inline uint64_t
_atomic_swap_64(volatile uint64_t * p,uint64_t n)1159b702505Sdlg _atomic_swap_64(volatile uint64_t *p, uint64_t n)
1169b702505Sdlg {
1179b702505Sdlg 	__asm volatile("xchgq %0, %1"
1189b702505Sdlg 	    : "=a" (n), "=m" (*p)
1199b702505Sdlg 	    : "0" (n), "m" (*p));
1209b702505Sdlg 
1219b702505Sdlg 	return (n);
1229b702505Sdlg }
1239b702505Sdlg #define atomic_swap_64(_p, _n) _atomic_swap_64((_p), (_n))
1249b702505Sdlg 
1259b702505Sdlg static inline void *
_atomic_swap_ptr(volatile void * p,void * n)1269b702505Sdlg _atomic_swap_ptr(volatile void *p, void *n)
1279b702505Sdlg {
1289b702505Sdlg 	__asm volatile("xchgq %0, %1"
1299b702505Sdlg 	    : "=a" (n), "=m" (*(unsigned long *)p)
1309b702505Sdlg 	    : "0" (n), "m" (*(unsigned long *)p));
1319b702505Sdlg 
1329b702505Sdlg 	return (n);
1339b702505Sdlg }
1349b702505Sdlg #define atomic_swap_ptr(_p, _n) _atomic_swap_ptr((_p), (_n))
1359b702505Sdlg 
136e3eaccaeSguenther static inline void
_atomic_inc_int(volatile unsigned int * p)137e3eaccaeSguenther _atomic_inc_int(volatile unsigned int *p)
138e3eaccaeSguenther {
139b67e4186Smpi 	__asm volatile(_LOCK " incl %0"
140e3eaccaeSguenther 	    : "+m" (*p));
141e3eaccaeSguenther }
142e3eaccaeSguenther #define atomic_inc_int(_p) _atomic_inc_int(_p)
143e3eaccaeSguenther 
144e3eaccaeSguenther static inline void
_atomic_inc_long(volatile unsigned long * p)145e3eaccaeSguenther _atomic_inc_long(volatile unsigned long *p)
146e3eaccaeSguenther {
147b67e4186Smpi 	__asm volatile(_LOCK " incq %0"
148e3eaccaeSguenther 	    : "+m" (*p));
149e3eaccaeSguenther }
150e3eaccaeSguenther #define atomic_inc_long(_p) _atomic_inc_long(_p)
151e3eaccaeSguenther 
152e3eaccaeSguenther static inline void
_atomic_dec_int(volatile unsigned int * p)153e3eaccaeSguenther _atomic_dec_int(volatile unsigned int *p)
154e3eaccaeSguenther {
155b67e4186Smpi 	__asm volatile(_LOCK " decl %0"
156e3eaccaeSguenther 	    : "+m" (*p));
157e3eaccaeSguenther }
158e3eaccaeSguenther #define atomic_dec_int(_p) _atomic_dec_int(_p)
159e3eaccaeSguenther 
160e3eaccaeSguenther static inline void
_atomic_dec_long(volatile unsigned long * p)161e3eaccaeSguenther _atomic_dec_long(volatile unsigned long *p)
162e3eaccaeSguenther {
163b67e4186Smpi 	__asm volatile(_LOCK " decq %0"
164e3eaccaeSguenther 	    : "+m" (*p));
165e3eaccaeSguenther }
166e3eaccaeSguenther #define atomic_dec_long(_p) _atomic_dec_long(_p)
167e3eaccaeSguenther 
168e3eaccaeSguenther static inline void
_atomic_add_int(volatile unsigned int * p,unsigned int v)169e3eaccaeSguenther _atomic_add_int(volatile unsigned int *p, unsigned int v)
170e3eaccaeSguenther {
171b67e4186Smpi 	__asm volatile(_LOCK " addl %1,%0"
172e3eaccaeSguenther 	    : "+m" (*p)
173e3eaccaeSguenther 	    : "a" (v));
174e3eaccaeSguenther }
175e3eaccaeSguenther #define atomic_add_int(_p, _v) _atomic_add_int(_p, _v)
176e3eaccaeSguenther 
177e3eaccaeSguenther static inline void
_atomic_add_long(volatile unsigned long * p,unsigned long v)178e3eaccaeSguenther _atomic_add_long(volatile unsigned long *p, unsigned long v)
179e3eaccaeSguenther {
180b67e4186Smpi 	__asm volatile(_LOCK " addq %1,%0"
181e3eaccaeSguenther 	    : "+m" (*p)
182e3eaccaeSguenther 	    : "a" (v));
183e3eaccaeSguenther }
184e3eaccaeSguenther #define atomic_add_long(_p, _v) _atomic_add_long(_p, _v)
185e3eaccaeSguenther 
186e3eaccaeSguenther static inline void
_atomic_sub_int(volatile unsigned int * p,unsigned int v)187e3eaccaeSguenther _atomic_sub_int(volatile unsigned int *p, unsigned int v)
188e3eaccaeSguenther {
189b67e4186Smpi 	__asm volatile(_LOCK " subl %1,%0"
190e3eaccaeSguenther 	    : "+m" (*p)
191e3eaccaeSguenther 	    : "a" (v));
192e3eaccaeSguenther }
193e3eaccaeSguenther #define atomic_sub_int(_p, _v) _atomic_sub_int(_p, _v)
194e3eaccaeSguenther 
195e3eaccaeSguenther static inline void
_atomic_sub_long(volatile unsigned long * p,unsigned long v)196e3eaccaeSguenther _atomic_sub_long(volatile unsigned long *p, unsigned long v)
197e3eaccaeSguenther {
198b67e4186Smpi 	__asm volatile(_LOCK " subq %1,%0"
199e3eaccaeSguenther 	    : "+m" (*p)
200e3eaccaeSguenther 	    : "a" (v));
201e3eaccaeSguenther }
202e3eaccaeSguenther #define atomic_sub_long(_p, _v) _atomic_sub_long(_p, _v)
203e3eaccaeSguenther 
204e3eaccaeSguenther 
205e3eaccaeSguenther static inline unsigned long
_atomic_add_int_nv(volatile unsigned int * p,unsigned int v)206e3eaccaeSguenther _atomic_add_int_nv(volatile unsigned int *p, unsigned int v)
207e3eaccaeSguenther {
208e3eaccaeSguenther 	unsigned int rv = v;
209e3eaccaeSguenther 
210b67e4186Smpi 	__asm volatile(_LOCK " xaddl %0,%1"
211e3eaccaeSguenther 	    : "+a" (rv), "+m" (*p));
212e3eaccaeSguenther 
213e3eaccaeSguenther 	return (rv + v);
214e3eaccaeSguenther }
215e3eaccaeSguenther #define atomic_add_int_nv(_p, _v) _atomic_add_int_nv(_p, _v)
216e3eaccaeSguenther 
217e3eaccaeSguenther static inline unsigned long
_atomic_add_long_nv(volatile unsigned long * p,unsigned long v)218e3eaccaeSguenther _atomic_add_long_nv(volatile unsigned long *p, unsigned long v)
219e3eaccaeSguenther {
220e3eaccaeSguenther 	unsigned long rv = v;
221e3eaccaeSguenther 
222b67e4186Smpi 	__asm volatile(_LOCK " xaddq %0,%1"
223e3eaccaeSguenther 	    : "+a" (rv), "+m" (*p));
224e3eaccaeSguenther 
225e3eaccaeSguenther 	return (rv + v);
226e3eaccaeSguenther }
227e3eaccaeSguenther #define atomic_add_long_nv(_p, _v) _atomic_add_long_nv(_p, _v)
228e3eaccaeSguenther 
229e3eaccaeSguenther static inline unsigned long
_atomic_sub_int_nv(volatile unsigned int * p,unsigned int v)230e3eaccaeSguenther _atomic_sub_int_nv(volatile unsigned int *p, unsigned int v)
231e3eaccaeSguenther {
232e3eaccaeSguenther 	unsigned int rv = 0 - v;
233e3eaccaeSguenther 
234b67e4186Smpi 	__asm volatile(_LOCK " xaddl %0,%1"
235e3eaccaeSguenther 	    : "+a" (rv), "+m" (*p));
236e3eaccaeSguenther 
237e3eaccaeSguenther 	return (rv - v);
238e3eaccaeSguenther }
239e3eaccaeSguenther #define atomic_sub_int_nv(_p, _v) _atomic_sub_int_nv(_p, _v)
240e3eaccaeSguenther 
241e3eaccaeSguenther static inline unsigned long
_atomic_sub_long_nv(volatile unsigned long * p,unsigned long v)242e3eaccaeSguenther _atomic_sub_long_nv(volatile unsigned long *p, unsigned long v)
243e3eaccaeSguenther {
244e3eaccaeSguenther 	unsigned long rv = 0 - v;
245e3eaccaeSguenther 
246b67e4186Smpi 	__asm volatile(_LOCK " xaddq %0,%1"
247e3eaccaeSguenther 	    : "+a" (rv), "+m" (*p));
248e3eaccaeSguenther 
249e3eaccaeSguenther 	return (rv - v);
250e3eaccaeSguenther }
251e3eaccaeSguenther #define atomic_sub_long_nv(_p, _v) _atomic_sub_long_nv(_p, _v)
252e3eaccaeSguenther 
253877a88e5Skettenis /*
254877a88e5Skettenis  * The AMD64 architecture is rather strongly ordered.  When accessing
25536fd90dcSjsg  * normal write-back cacheable memory, only reads may be reordered with
256877a88e5Skettenis  * older writes to different locations.  There are a few instructions
257877a88e5Skettenis  * (clfush, non-temporal move instructions) that obey weaker ordering
258877a88e5Skettenis  * rules, but those instructions will only be used in (inline)
259877a88e5Skettenis  * assembly code where we can add the necessary fence instructions
260877a88e5Skettenis  * ourselves.
261877a88e5Skettenis  */
262877a88e5Skettenis 
263dd81489dSjsg #define __membar(_f) do { __asm volatile(_f ::: "memory"); } while (0)
264877a88e5Skettenis 
265b67e4186Smpi #if defined(MULTIPROCESSOR) || !defined(_KERNEL)
266877a88e5Skettenis #define membar_enter()		__membar("mfence")
267877a88e5Skettenis #define membar_exit()		__membar("")
268877a88e5Skettenis #define membar_producer()	__membar("")
269877a88e5Skettenis #define membar_consumer()	__membar("")
270877a88e5Skettenis #define membar_sync()		__membar("mfence")
271877a88e5Skettenis #else
272877a88e5Skettenis #define membar_enter()		__membar("")
273877a88e5Skettenis #define membar_exit()		__membar("")
274877a88e5Skettenis #define membar_producer()	__membar("")
275877a88e5Skettenis #define membar_consumer()	__membar("")
276877a88e5Skettenis #define membar_sync()		__membar("")
277877a88e5Skettenis #endif
278877a88e5Skettenis 
2799f3f0ed4Skettenis #define membar_enter_after_atomic()	__membar("")
2809f3f0ed4Skettenis #define membar_exit_before_atomic()	__membar("")
2819f3f0ed4Skettenis 
282b67e4186Smpi #ifdef _KERNEL
283b67e4186Smpi 
28407376847Ssf /* virtio needs MP membars even on SP kernels */
28507376847Ssf #define virtio_membar_producer()	__membar("")
28607376847Ssf #define virtio_membar_consumer()	__membar("")
28707376847Ssf #define virtio_membar_sync()		__membar("mfence")
28807376847Ssf 
289f5df1827Smickey static __inline void
x86_atomic_setbits_u32(volatile u_int32_t * ptr,u_int32_t bits)2908aa3ef09Sderaadt x86_atomic_setbits_u32(volatile u_int32_t *ptr, u_int32_t bits)
2918aa3ef09Sderaadt {
292b67e4186Smpi 	__asm volatile(_LOCK " orl %1,%0" :  "=m" (*ptr) : "ir" (bits));
293f5df1827Smickey }
294f5df1827Smickey 
295f5df1827Smickey static __inline void
x86_atomic_clearbits_u32(volatile u_int32_t * ptr,u_int32_t bits)2968aa3ef09Sderaadt x86_atomic_clearbits_u32(volatile u_int32_t *ptr, u_int32_t bits)
2978aa3ef09Sderaadt {
298b67e4186Smpi 	__asm volatile(_LOCK " andl %1,%0" :  "=m" (*ptr) : "ir" (~bits));
299f5df1827Smickey }
300f5df1827Smickey 
301f5df1827Smickey static __inline void
x86_atomic_setbits_u64(volatile u_int64_t * ptr,u_int64_t bits)3028aa3ef09Sderaadt x86_atomic_setbits_u64(volatile u_int64_t *ptr, u_int64_t bits)
3038aa3ef09Sderaadt {
304b67e4186Smpi 	__asm volatile(_LOCK " orq %1,%0" :  "=m" (*ptr) : "er" (bits));
305f5df1827Smickey }
306f5df1827Smickey 
307f5df1827Smickey static __inline void
x86_atomic_clearbits_u64(volatile u_int64_t * ptr,u_int64_t bits)3088aa3ef09Sderaadt x86_atomic_clearbits_u64(volatile u_int64_t *ptr, u_int64_t bits)
3098aa3ef09Sderaadt {
310b67e4186Smpi 	__asm volatile(_LOCK " andq %1,%0" :  "=m" (*ptr) : "er" (~bits));
311f5df1827Smickey }
312f5df1827Smickey 
3133ebc0221Sguenther #define x86_atomic_testset_ul	x86_atomic_testset_u64
3143ebc0221Sguenther #define x86_atomic_setbits_ul	x86_atomic_setbits_u64
3153ebc0221Sguenther #define x86_atomic_clearbits_ul	x86_atomic_clearbits_u64
316f5df1827Smickey 
317f57756c9Sart #define atomic_setbits_int x86_atomic_setbits_u32
318f57756c9Sart #define atomic_clearbits_int x86_atomic_clearbits_u32
319f57756c9Sart 
320b67e4186Smpi #endif /* _KERNEL */
321f57756c9Sart 
322b67e4186Smpi #undef _LOCK
323b67e4186Smpi 
324b67e4186Smpi #endif /* !defined(_LOCORE) */
3252fa72412Spirofti #endif /* _MACHINE_ATOMIC_H_ */
326