xref: /openbsd-src/sys/arch/i386/include/atomic.h (revision dd81489db8c6745c0e25d81d82e97f90d8886b12)
1*dd81489dSjsg /*	$OpenBSD: atomic.h,v 1.20 2022/08/29 02:01:18 jsg Exp $	*/
2012ea299Sniklas /* $NetBSD: atomic.h,v 1.1.2.2 2000/02/21 18:54:07 sommerfeld Exp $ */
3012ea299Sniklas 
4012ea299Sniklas /*-
5012ea299Sniklas  * Copyright (c) 2000 The NetBSD Foundation, Inc.
6012ea299Sniklas  * All rights reserved.
7012ea299Sniklas  *
8012ea299Sniklas  * This code is derived from software contributed to The NetBSD Foundation
9012ea299Sniklas  * by RedBack Networks Inc.
10012ea299Sniklas  *
11012ea299Sniklas  * Author: Bill Sommerfeld
12012ea299Sniklas  *
13012ea299Sniklas  * Redistribution and use in source and binary forms, with or without
14012ea299Sniklas  * modification, are permitted provided that the following conditions
15012ea299Sniklas  * are met:
16012ea299Sniklas  * 1. Redistributions of source code must retain the above copyright
17012ea299Sniklas  *    notice, this list of conditions and the following disclaimer.
18012ea299Sniklas  * 2. Redistributions in binary form must reproduce the above copyright
19012ea299Sniklas  *    notice, this list of conditions and the following disclaimer in the
20012ea299Sniklas  *    documentation and/or other materials provided with the distribution.
21012ea299Sniklas  *
22012ea299Sniklas  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23012ea299Sniklas  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24012ea299Sniklas  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25012ea299Sniklas  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26012ea299Sniklas  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27012ea299Sniklas  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28012ea299Sniklas  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29012ea299Sniklas  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30012ea299Sniklas  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31012ea299Sniklas  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32012ea299Sniklas  * POSSIBILITY OF SUCH DAMAGE.
33012ea299Sniklas  */
34012ea299Sniklas 
352fa72412Spirofti #ifndef _MACHINE_ATOMIC_H_
362fa72412Spirofti #define _MACHINE_ATOMIC_H_
37012ea299Sniklas 
38f57756c9Sart /*
39f57756c9Sart  * Perform atomic operations on memory. Should be atomic with respect
40f57756c9Sart  * to interrupts and multiple processors.
41f57756c9Sart  *
42f57756c9Sart  * void atomic_setbits_int(volatile u_int *a, u_int mask) { *a |= mask; }
43f57756c9Sart  * void atomic_clearbits_int(volatile u_int *a, u_int mas) { *a &= ~mask; }
44f57756c9Sart  */
45d1ad1abeSmpi #if !defined(_LOCORE)
46012ea299Sniklas 
47d1ad1abeSmpi #if defined(MULTIPROCESSOR) || !defined(_KERNEL)
48d1ad1abeSmpi #define _LOCK "lock"
49f57756c9Sart #else
50d1ad1abeSmpi #define _LOCK
51f57756c9Sart #endif
52f57756c9Sart 
53a9b606aaSkettenis static inline unsigned int
_atomic_cas_uint(volatile unsigned int * p,unsigned int e,unsigned int n)54a9b606aaSkettenis _atomic_cas_uint(volatile unsigned int *p, unsigned int e, unsigned int n)
55a9b606aaSkettenis {
56d1ad1abeSmpi 	__asm volatile(_LOCK " cmpxchgl %2, %1"
57a9b606aaSkettenis 	    : "=a" (n), "=m" (*p)
58a9b606aaSkettenis 	    : "r" (n), "a" (e), "m" (*p));
59a9b606aaSkettenis 
60a9b606aaSkettenis 	return (n);
61a9b606aaSkettenis }
62a9b606aaSkettenis #define atomic_cas_uint(_p, _e, _n) _atomic_cas_uint((_p), (_e), (_n))
63a9b606aaSkettenis 
64a9b606aaSkettenis static inline unsigned long
_atomic_cas_ulong(volatile unsigned long * p,unsigned long e,unsigned long n)65a9b606aaSkettenis _atomic_cas_ulong(volatile unsigned long *p, unsigned long e, unsigned long n)
66a9b606aaSkettenis {
67d1ad1abeSmpi 	__asm volatile(_LOCK " cmpxchgl %2, %1"
68a9b606aaSkettenis 	    : "=a" (n), "=m" (*p)
69a9b606aaSkettenis 	    : "r" (n), "a" (e), "m" (*p));
70a9b606aaSkettenis 
71a9b606aaSkettenis 	return (n);
72a9b606aaSkettenis }
73a9b606aaSkettenis #define atomic_cas_ulong(_p, _e, _n) _atomic_cas_ulong((_p), (_e), (_n))
74a9b606aaSkettenis 
75a9b606aaSkettenis static inline void *
_atomic_cas_ptr(volatile void * p,void * e,void * n)76a9b606aaSkettenis _atomic_cas_ptr(volatile void *p, void *e, void *n)
77a9b606aaSkettenis {
78d1ad1abeSmpi 	__asm volatile(_LOCK " cmpxchgl %2, %1"
79a9b606aaSkettenis 	    : "=a" (n), "=m" (*(unsigned long *)p)
80a9b606aaSkettenis 	    : "r" (n), "a" (e), "m" (*(unsigned long *)p));
81a9b606aaSkettenis 
82a9b606aaSkettenis 	return (n);
83a9b606aaSkettenis }
84a9b606aaSkettenis #define atomic_cas_ptr(_p, _e, _n) _atomic_cas_ptr((_p), (_e), (_n))
85a9b606aaSkettenis 
86a9b606aaSkettenis static inline unsigned int
_atomic_swap_uint(volatile unsigned int * p,unsigned int n)87a9b606aaSkettenis _atomic_swap_uint(volatile unsigned int *p, unsigned int n)
88a9b606aaSkettenis {
89a9b606aaSkettenis 	__asm volatile("xchgl %0, %1"
90a9b606aaSkettenis 	    : "=a" (n), "=m" (*p)
91a9b606aaSkettenis 	    : "0" (n), "m" (*p));
92a9b606aaSkettenis 
93a9b606aaSkettenis 	return (n);
94a9b606aaSkettenis }
95a9b606aaSkettenis #define atomic_swap_uint(_p, _n) _atomic_swap_uint((_p), (_n))
96a9b606aaSkettenis #define atomic_swap_32(_p, _n) _atomic_swap_uint((_p), (_n))
97a9b606aaSkettenis 
98a9b606aaSkettenis static inline unsigned long
_atomic_swap_ulong(volatile unsigned long * p,unsigned long n)99a9b606aaSkettenis _atomic_swap_ulong(volatile unsigned long *p, unsigned long n)
100a9b606aaSkettenis {
101a9b606aaSkettenis 	__asm volatile("xchgl %0, %1"
102a9b606aaSkettenis 	    : "=a" (n), "=m" (*p)
103a9b606aaSkettenis 	    : "0" (n), "m" (*p));
104a9b606aaSkettenis 
105a9b606aaSkettenis 	return (n);
106a9b606aaSkettenis }
107a9b606aaSkettenis #define atomic_swap_ulong(_p, _n) _atomic_swap_ulong((_p), (_n))
108a9b606aaSkettenis 
109a9b606aaSkettenis static inline void *
_atomic_swap_ptr(volatile void * p,void * n)110a9b606aaSkettenis _atomic_swap_ptr(volatile void *p, void *n)
111a9b606aaSkettenis {
112a9b606aaSkettenis 	__asm volatile("xchgl %0, %1"
113a9b606aaSkettenis 	    : "=a" (n), "=m" (*(unsigned long *)p)
114a9b606aaSkettenis 	    : "0" (n), "m" (*(unsigned long *)p));
115a9b606aaSkettenis 
116a9b606aaSkettenis 	return (n);
117a9b606aaSkettenis }
118a9b606aaSkettenis #define atomic_swap_ptr(_p, _n) _atomic_swap_ptr((_p), (_n))
119a9b606aaSkettenis 
120a9b606aaSkettenis static inline void
_atomic_inc_int(volatile unsigned int * p)121a9b606aaSkettenis _atomic_inc_int(volatile unsigned int *p)
122a9b606aaSkettenis {
123d1ad1abeSmpi 	__asm volatile(_LOCK " incl %0"
124a9b606aaSkettenis 	    : "+m" (*p));
125a9b606aaSkettenis }
126a9b606aaSkettenis #define atomic_inc_int(_p) _atomic_inc_int(_p)
127a9b606aaSkettenis 
128a9b606aaSkettenis static inline void
_atomic_inc_long(volatile unsigned long * p)129a9b606aaSkettenis _atomic_inc_long(volatile unsigned long *p)
130a9b606aaSkettenis {
131d1ad1abeSmpi 	__asm volatile(_LOCK " incl %0"
132a9b606aaSkettenis 	    : "+m" (*p));
133a9b606aaSkettenis }
134a9b606aaSkettenis #define atomic_inc_long(_p) _atomic_inc_long(_p)
135a9b606aaSkettenis 
136a9b606aaSkettenis static inline void
_atomic_dec_int(volatile unsigned int * p)137a9b606aaSkettenis _atomic_dec_int(volatile unsigned int *p)
138a9b606aaSkettenis {
139d1ad1abeSmpi 	__asm volatile(_LOCK " decl %0"
140a9b606aaSkettenis 	    : "+m" (*p));
141a9b606aaSkettenis }
142a9b606aaSkettenis #define atomic_dec_int(_p) _atomic_dec_int(_p)
143a9b606aaSkettenis 
144a9b606aaSkettenis static inline void
_atomic_dec_long(volatile unsigned long * p)145a9b606aaSkettenis _atomic_dec_long(volatile unsigned long *p)
146a9b606aaSkettenis {
147d1ad1abeSmpi 	__asm volatile(_LOCK " decl %0"
148a9b606aaSkettenis 	    : "+m" (*p));
149a9b606aaSkettenis }
150a9b606aaSkettenis #define atomic_dec_long(_p) _atomic_dec_long(_p)
151a9b606aaSkettenis 
152a9b606aaSkettenis static inline void
_atomic_add_int(volatile unsigned int * p,unsigned int v)153a9b606aaSkettenis _atomic_add_int(volatile unsigned int *p, unsigned int v)
154a9b606aaSkettenis {
155d1ad1abeSmpi 	__asm volatile(_LOCK " addl %1,%0"
156a9b606aaSkettenis 	    : "+m" (*p)
157a9b606aaSkettenis 	    : "a" (v));
158a9b606aaSkettenis }
159a9b606aaSkettenis #define atomic_add_int(_p, _v) _atomic_add_int(_p, _v)
160a9b606aaSkettenis 
161a9b606aaSkettenis static inline void
_atomic_add_long(volatile unsigned long * p,unsigned long v)162a9b606aaSkettenis _atomic_add_long(volatile unsigned long *p, unsigned long v)
163a9b606aaSkettenis {
164d1ad1abeSmpi 	__asm volatile(_LOCK " addl %1,%0"
165a9b606aaSkettenis 	    : "+m" (*p)
166a9b606aaSkettenis 	    : "a" (v));
167a9b606aaSkettenis }
168a9b606aaSkettenis #define atomic_add_long(_p, _v) _atomic_add_long(_p, _v)
169a9b606aaSkettenis 
170a9b606aaSkettenis static inline void
_atomic_sub_int(volatile unsigned int * p,unsigned int v)171a9b606aaSkettenis _atomic_sub_int(volatile unsigned int *p, unsigned int v)
172a9b606aaSkettenis {
173d1ad1abeSmpi 	__asm volatile(_LOCK " subl %1,%0"
174a9b606aaSkettenis 	    : "+m" (*p)
175a9b606aaSkettenis 	    : "a" (v));
176a9b606aaSkettenis }
177a9b606aaSkettenis #define atomic_sub_int(_p, _v) _atomic_sub_int(_p, _v)
178a9b606aaSkettenis 
179a9b606aaSkettenis static inline void
_atomic_sub_long(volatile unsigned long * p,unsigned long v)180a9b606aaSkettenis _atomic_sub_long(volatile unsigned long *p, unsigned long v)
181a9b606aaSkettenis {
182d1ad1abeSmpi 	__asm volatile(_LOCK " subl %1,%0"
183a9b606aaSkettenis 	    : "+m" (*p)
184a9b606aaSkettenis 	    : "a" (v));
185a9b606aaSkettenis }
186a9b606aaSkettenis #define atomic_sub_long(_p, _v) _atomic_sub_long(_p, _v)
187a9b606aaSkettenis 
188a9b606aaSkettenis 
189a9b606aaSkettenis static inline unsigned long
_atomic_add_int_nv(volatile unsigned int * p,unsigned int v)190a9b606aaSkettenis _atomic_add_int_nv(volatile unsigned int *p, unsigned int v)
191a9b606aaSkettenis {
192a9b606aaSkettenis 	unsigned int rv = v;
193a9b606aaSkettenis 
194d1ad1abeSmpi 	__asm volatile(_LOCK " xaddl %0,%1"
195a9b606aaSkettenis 	    : "+a" (rv), "+m" (*p));
196a9b606aaSkettenis 
197a9b606aaSkettenis 	return (rv + v);
198a9b606aaSkettenis }
199a9b606aaSkettenis #define atomic_add_int_nv(_p, _v) _atomic_add_int_nv(_p, _v)
200a9b606aaSkettenis 
201a9b606aaSkettenis static inline unsigned long
_atomic_add_long_nv(volatile unsigned long * p,unsigned long v)202a9b606aaSkettenis _atomic_add_long_nv(volatile unsigned long *p, unsigned long v)
203a9b606aaSkettenis {
204a9b606aaSkettenis 	unsigned long rv = v;
205a9b606aaSkettenis 
206d1ad1abeSmpi 	__asm volatile(_LOCK " xaddl %0,%1"
207a9b606aaSkettenis 	    : "+a" (rv), "+m" (*p));
208a9b606aaSkettenis 
209a9b606aaSkettenis 	return (rv + v);
210a9b606aaSkettenis }
211a9b606aaSkettenis #define atomic_add_long_nv(_p, _v) _atomic_add_long_nv(_p, _v)
212a9b606aaSkettenis 
213a9b606aaSkettenis static inline unsigned long
_atomic_sub_int_nv(volatile unsigned int * p,unsigned int v)214a9b606aaSkettenis _atomic_sub_int_nv(volatile unsigned int *p, unsigned int v)
215a9b606aaSkettenis {
216a9b606aaSkettenis 	unsigned int rv = 0 - v;
217a9b606aaSkettenis 
218d1ad1abeSmpi 	__asm volatile(_LOCK " xaddl %0,%1"
219a9b606aaSkettenis 	    : "+a" (rv), "+m" (*p));
220a9b606aaSkettenis 
221a9b606aaSkettenis 	return (rv - v);
222a9b606aaSkettenis }
223a9b606aaSkettenis #define atomic_sub_int_nv(_p, _v) _atomic_sub_int_nv(_p, _v)
224a9b606aaSkettenis 
225a9b606aaSkettenis static inline unsigned long
_atomic_sub_long_nv(volatile unsigned long * p,unsigned long v)226a9b606aaSkettenis _atomic_sub_long_nv(volatile unsigned long *p, unsigned long v)
227a9b606aaSkettenis {
228a9b606aaSkettenis 	unsigned long rv = 0 - v;
229a9b606aaSkettenis 
230d1ad1abeSmpi 	__asm volatile(_LOCK " xaddl %0,%1"
231a9b606aaSkettenis 	    : "+a" (rv), "+m" (*p));
232a9b606aaSkettenis 
233a9b606aaSkettenis 	return (rv - v);
234a9b606aaSkettenis }
235a9b606aaSkettenis #define atomic_sub_long_nv(_p, _v) _atomic_sub_long_nv(_p, _v)
236a9b606aaSkettenis 
237a9b606aaSkettenis /*
238a9b606aaSkettenis  * The IA-32 architecture is rather strongly ordered.  When accessing
23936fd90dcSjsg  * normal write-back cacheable memory, only reads may be reordered with
240a9b606aaSkettenis  * older writes to different locations.  There are a few instructions
241a9b606aaSkettenis  * (clfush, non-temporal move instructions) that obey weaker ordering
242a9b606aaSkettenis  * rules, but those instructions will only be used in (inline)
243a9b606aaSkettenis  * assembly code where we can add the necessary fence instructions
244a9b606aaSkettenis  * ourselves.
245a9b606aaSkettenis  */
246a9b606aaSkettenis 
247*dd81489dSjsg #define __membar(_f) do { __asm volatile(_f ::: "memory"); } while (0)
248a9b606aaSkettenis 
249d1ad1abeSmpi #if defined(MULTIPROCESSOR) || !defined(_KERNEL)
250a9b606aaSkettenis #define membar_enter()		__membar("lock; addl $0,0(%%esp)")
251a9b606aaSkettenis #define membar_exit()		__membar("")
252a9b606aaSkettenis #define membar_producer()	__membar("")
253a9b606aaSkettenis #define membar_consumer()	__membar("")
254a9b606aaSkettenis #define membar_sync()		__membar("lock; addl $0,0(%%esp)")
255a9b606aaSkettenis #else
256a9b606aaSkettenis #define membar_enter()		__membar("")
257a9b606aaSkettenis #define membar_exit()		__membar("")
258a9b606aaSkettenis #define membar_producer()	__membar("")
259a9b606aaSkettenis #define membar_consumer()	__membar("")
260a9b606aaSkettenis #define membar_sync()		__membar("")
261a9b606aaSkettenis #endif
262a9b606aaSkettenis 
2639f3f0ed4Skettenis #define membar_enter_after_atomic()	__membar("")
2649f3f0ed4Skettenis #define membar_exit_before_atomic()	__membar("")
2659f3f0ed4Skettenis 
266d1ad1abeSmpi #ifdef _KERNEL
267d1ad1abeSmpi 
268a9b606aaSkettenis /* virtio needs MP membars even on SP kernels */
269a9b606aaSkettenis #define virtio_membar_producer()	__membar("")
270a9b606aaSkettenis #define virtio_membar_consumer()	__membar("")
271a9b606aaSkettenis #define virtio_membar_sync()		__membar("lock; addl $0,0(%%esp)")
272a9b606aaSkettenis 
273829cf9fdSmickey static __inline u_int64_t
i386_atomic_testset_uq(volatile u_int64_t * ptr,u_int64_t val)2748aa3ef09Sderaadt i386_atomic_testset_uq(volatile u_int64_t *ptr, u_int64_t val)
2758aa3ef09Sderaadt {
276d1ad1abeSmpi 	__asm__ volatile ("\n1:\t" _LOCK " cmpxchg8b (%1); jnz 1b" : "+A" (val) :
277829cf9fdSmickey 	    "r" (ptr), "b" ((u_int32_t)val), "c" ((u_int32_t)(val >> 32)));
278829cf9fdSmickey 	return val;
279829cf9fdSmickey }
280829cf9fdSmickey 
281012ea299Sniklas static __inline u_int32_t
i386_atomic_testset_ul(volatile u_int32_t * ptr,unsigned long val)2828aa3ef09Sderaadt i386_atomic_testset_ul(volatile u_int32_t *ptr, unsigned long val)
2838aa3ef09Sderaadt {
284012ea299Sniklas 	__asm__ volatile ("xchgl %0,(%2)" :"=r" (val):"0" (val),"r" (ptr));
285012ea299Sniklas 	return val;
286012ea299Sniklas }
287012ea299Sniklas 
288012ea299Sniklas static __inline int
i386_atomic_testset_i(volatile int * ptr,unsigned long val)2898aa3ef09Sderaadt i386_atomic_testset_i(volatile int *ptr, unsigned long val)
2908aa3ef09Sderaadt {
291012ea299Sniklas 	__asm__ volatile ("xchgl %0,(%2)" :"=r" (val):"0" (val),"r" (ptr));
292012ea299Sniklas 	return val;
293012ea299Sniklas }
294012ea299Sniklas 
295012ea299Sniklas static __inline void
i386_atomic_setbits_l(volatile u_int32_t * ptr,unsigned long bits)2968aa3ef09Sderaadt i386_atomic_setbits_l(volatile u_int32_t *ptr, unsigned long bits)
2978aa3ef09Sderaadt {
298d1ad1abeSmpi 	__asm volatile(_LOCK " orl %1,%0" :  "=m" (*ptr) : "ir" (bits));
299012ea299Sniklas }
300012ea299Sniklas 
301012ea299Sniklas static __inline void
i386_atomic_clearbits_l(volatile u_int32_t * ptr,unsigned long bits)3028aa3ef09Sderaadt i386_atomic_clearbits_l(volatile u_int32_t *ptr, unsigned long bits)
3038aa3ef09Sderaadt {
304012ea299Sniklas 	bits = ~bits;
305d1ad1abeSmpi 	__asm volatile(_LOCK " andl %1,%0" :  "=m" (*ptr) : "ir" (bits));
306012ea299Sniklas }
307012ea299Sniklas 
308f57756c9Sart #define atomic_setbits_int i386_atomic_setbits_l
309f57756c9Sart #define atomic_clearbits_int i386_atomic_clearbits_l
310f57756c9Sart 
311d1ad1abeSmpi #endif /* _KERNEL */
312f57756c9Sart 
313d1ad1abeSmpi #undef _LOCK
314d1ad1abeSmpi 
315d1ad1abeSmpi #endif /* !defined(_LOCORE) */
3162fa72412Spirofti #endif /* _MACHINE_ATOMIC_H_ */
317