1 /* $OpenBSD: atomic.h,v 1.12 2023/04/10 04:21:20 jsg Exp $ */
2
3 /* Public Domain */
4
5 #ifndef _MACHINE_ATOMIC_H_
6 #define _MACHINE_ATOMIC_H_
7
8 #if defined(_KERNEL)
9
10 typedef volatile u_int __cpu_simple_lock_t __attribute__((__aligned__(16)));
11
12 #define __SIMPLELOCK_LOCKED 0
13 #define __SIMPLELOCK_UNLOCKED 1
14
15 static inline void
__cpu_simple_lock_init(__cpu_simple_lock_t * l)16 __cpu_simple_lock_init(__cpu_simple_lock_t *l)
17 {
18 *l = __SIMPLELOCK_UNLOCKED;
19 }
20
21 static inline unsigned int
__cpu_simple_lock_ldcws(__cpu_simple_lock_t * l)22 __cpu_simple_lock_ldcws(__cpu_simple_lock_t *l)
23 {
24 unsigned int o;
25
26 asm volatile("ldcws 0(%2), %0" : "=&r" (o), "+m" (l) : "r" (l));
27
28 return (o);
29 }
30
31 static inline int
__cpu_simple_lock_try(__cpu_simple_lock_t * l)32 __cpu_simple_lock_try(__cpu_simple_lock_t *l)
33 {
34 return (__cpu_simple_lock_ldcws(l) == __SIMPLELOCK_UNLOCKED);
35 }
36
37 static inline void
__cpu_simple_lock(__cpu_simple_lock_t * l)38 __cpu_simple_lock(__cpu_simple_lock_t *l)
39 {
40 while (!__cpu_simple_lock_ldcws(l))
41 ;
42 }
43
44 static inline void
__cpu_simple_unlock(__cpu_simple_lock_t * l)45 __cpu_simple_unlock(__cpu_simple_lock_t *l)
46 {
47 *l = __SIMPLELOCK_UNLOCKED;
48 }
49
50 #ifdef MULTIPROCESSOR
51 extern __cpu_simple_lock_t atomic_lock;
52 #define ATOMIC_LOCK __cpu_simple_lock(&atomic_lock);
53 #define ATOMIC_UNLOCK __cpu_simple_unlock(&atomic_lock);
54 #else
55 #define ATOMIC_LOCK
56 #define ATOMIC_UNLOCK
57 #endif
58
59 static inline register_t
atomic_enter(void)60 atomic_enter(void)
61 {
62 register_t eiem;
63
64 __asm volatile("mfctl %%cr15, %0": "=r" (eiem));
65 __asm volatile("mtctl %r0, %cr15");
66 ATOMIC_LOCK;
67
68 return (eiem);
69 }
70
71 static inline void
atomic_leave(register_t eiem)72 atomic_leave(register_t eiem)
73 {
74 ATOMIC_UNLOCK;
75 __asm volatile("mtctl %0, %%cr15":: "r" (eiem));
76 }
77
78 static inline unsigned int
_atomic_cas_uint(volatile unsigned int * uip,unsigned int o,unsigned int n)79 _atomic_cas_uint(volatile unsigned int *uip, unsigned int o, unsigned int n)
80 {
81 register_t eiem;
82 unsigned int rv;
83
84 eiem = atomic_enter();
85 rv = *uip;
86 if (rv == o)
87 *uip = n;
88 atomic_leave(eiem);
89
90 return (rv);
91 }
92 #define atomic_cas_uint(_p, _o, _n) _atomic_cas_uint((_p), (_o), (_n))
93
94 static inline unsigned long
_atomic_cas_ulong(volatile unsigned long * uip,unsigned long o,unsigned long n)95 _atomic_cas_ulong(volatile unsigned long *uip, unsigned long o, unsigned long n)
96 {
97 register_t eiem;
98 unsigned long rv;
99
100 eiem = atomic_enter();
101 rv = *uip;
102 if (rv == o)
103 *uip = n;
104 atomic_leave(eiem);
105
106 return (rv);
107 }
108 #define atomic_cas_ulong(_p, _o, _n) _atomic_cas_ulong((_p), (_o), (_n))
109
110 static inline void *
_atomic_cas_ptr(volatile void * uip,void * o,void * n)111 _atomic_cas_ptr(volatile void *uip, void *o, void *n)
112 {
113 register_t eiem;
114 void * volatile *uipp = (void * volatile *)uip;
115 void *rv;
116
117 eiem = atomic_enter();
118 rv = *uipp;
119 if (rv == o)
120 *uipp = n;
121 atomic_leave(eiem);
122
123 return (rv);
124 }
125 #define atomic_cas_ptr(_p, _o, _n) _atomic_cas_ptr((_p), (_o), (_n))
126
127 static inline unsigned int
_atomic_swap_uint(volatile unsigned int * uip,unsigned int n)128 _atomic_swap_uint(volatile unsigned int *uip, unsigned int n)
129 {
130 register_t eiem;
131 unsigned int rv;
132
133 eiem = atomic_enter();
134 rv = *uip;
135 *uip = n;
136 atomic_leave(eiem);
137
138 return (rv);
139 }
140 #define atomic_swap_uint(_p, _n) _atomic_swap_uint((_p), (_n))
141
142 static inline unsigned long
_atomic_swap_ulong(volatile unsigned long * uip,unsigned long n)143 _atomic_swap_ulong(volatile unsigned long *uip, unsigned long n)
144 {
145 register_t eiem;
146 unsigned long rv;
147
148 eiem = atomic_enter();
149 rv = *uip;
150 *uip = n;
151 atomic_leave(eiem);
152
153 return (rv);
154 }
155 #define atomic_swap_ulong(_p, _n) _atomic_swap_ulong((_p), (_n))
156
157 static inline void *
_atomic_swap_ptr(volatile void * uip,void * n)158 _atomic_swap_ptr(volatile void *uip, void *n)
159 {
160 register_t eiem;
161 void * volatile *uipp = (void * volatile *)uip;
162 void *rv;
163
164 eiem = atomic_enter();
165 rv = *uipp;
166 *uipp = n;
167 atomic_leave(eiem);
168
169 return (rv);
170 }
171 #define atomic_swap_ptr(_p, _n) _atomic_swap_ptr((_p), (_n))
172
173 static __inline unsigned int
_atomic_add_int_nv(volatile unsigned int * uip,unsigned int v)174 _atomic_add_int_nv(volatile unsigned int *uip, unsigned int v)
175 {
176 register_t eiem;
177 unsigned int rv;
178
179 eiem = atomic_enter();
180 rv = *uip + v;
181 *uip = rv;
182 atomic_leave(eiem);
183
184 return (rv);
185 }
186 #define atomic_add_int_nv(_uip, _v) _atomic_add_int_nv((_uip), (_v))
187 #define atomic_sub_int_nv(_uip, _v) _atomic_add_int_nv((_uip), 0 - (_v))
188
189 static __inline unsigned long
_atomic_add_long_nv(volatile unsigned long * uip,unsigned long v)190 _atomic_add_long_nv(volatile unsigned long *uip, unsigned long v)
191 {
192 register_t eiem;
193 unsigned long rv;
194
195 eiem = atomic_enter();
196 rv = *uip + v;
197 *uip = rv;
198 atomic_leave(eiem);
199
200 return (rv);
201 }
202 #define atomic_add_long_nv(_uip, _v) _atomic_add_long_nv((_uip), (_v))
203 #define atomic_sub_long_nv(_uip, _v) _atomic_add_long_nv((_uip), 0 - (_v))
204
205 static __inline void
atomic_setbits_int(volatile unsigned int * uip,unsigned int v)206 atomic_setbits_int(volatile unsigned int *uip, unsigned int v)
207 {
208 register_t eiem;
209
210 eiem = atomic_enter();
211 *uip |= v;
212 atomic_leave(eiem);
213 }
214
215 static __inline void
atomic_clearbits_int(volatile unsigned int * uip,unsigned int v)216 atomic_clearbits_int(volatile unsigned int *uip, unsigned int v)
217 {
218 register_t eiem;
219
220 eiem = atomic_enter();
221 *uip &= ~v;
222 atomic_leave(eiem);
223 }
224
225 static __inline void
atomic_setbits_long(volatile unsigned long * uip,unsigned long v)226 atomic_setbits_long(volatile unsigned long *uip, unsigned long v)
227 {
228 register_t eiem;
229
230 eiem = atomic_enter();
231 *uip |= v;
232 atomic_leave(eiem);
233 }
234
235 static __inline void
atomic_clearbits_long(volatile unsigned long * uip,unsigned long v)236 atomic_clearbits_long(volatile unsigned long *uip, unsigned long v)
237 {
238 register_t eiem;
239
240 eiem = atomic_enter();
241 *uip &= ~v;
242 atomic_leave(eiem);
243 }
244
245 #endif /* defined(_KERNEL) */
246
247 /*
248 * Although the PA-RISC 2.0 architecture allows an implementation to
249 * be weakly ordered, all PA-RISC processors to date implement a
250 * strong memory ordering model. So all we need is a compiler
251 * barrier.
252 */
253
254 static inline void
__insn_barrier(void)255 __insn_barrier(void)
256 {
257 __asm volatile("" : : : "memory");
258 }
259
260 #define membar_enter() __insn_barrier()
261 #define membar_exit() __insn_barrier()
262 #define membar_producer() __insn_barrier()
263 #define membar_consumer() __insn_barrier()
264 #define membar_sync() __insn_barrier()
265
266 #endif /* _MACHINE_ATOMIC_H_ */
267