| Commit | Line | Data |
|---|---|---|
| 984263bc MD |
1 | /*- |
| 2 | * Copyright (c) 1998 Doug Rabson | |
| 3 | * All rights reserved. | |
| 4 | * | |
| 5 | * Redistribution and use in source and binary forms, with or without | |
| 6 | * modification, are permitted provided that the following conditions | |
| 7 | * are met: | |
| 8 | * 1. Redistributions of source code must retain the above copyright | |
| 9 | * notice, this list of conditions and the following disclaimer. | |
| 10 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 11 | * notice, this list of conditions and the following disclaimer in the | |
| 12 | * documentation and/or other materials provided with the distribution. | |
| 13 | * | |
| 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
| 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
| 18 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| 19 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| 20 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 21 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| 22 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| 23 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 24 | * SUCH DAMAGE. | |
| 25 | * | |
| 26 | * $FreeBSD: src/sys/i386/include/atomic.h,v 1.9.2.1 2000/07/07 00:38:47 obrien Exp $ | |
| 5b296f84 | 27 | * $DragonFly: src/sys/cpu/i386/include/atomic.h,v 1.25 2008/06/26 23:06:50 dillon Exp $ |
| 984263bc | 28 | */ |
| a9295349 MD |
29 | #ifndef _CPU_ATOMIC_H_ |
| 30 | #define _CPU_ATOMIC_H_ | |
| 984263bc | 31 | |
| 1bd40720 MD |
32 | #ifndef _SYS_TYPES_H_ |
| 33 | #include <sys/types.h> | |
| 34 | #endif | |
| 35 | ||
| 984263bc MD |
36 | /* |
| 37 | * Various simple arithmetic on memory which is atomic in the presence | |
| 38 | * of interrupts and multiple processors. | |
| 39 | * | |
| 40 | * atomic_set_char(P, V) (*(u_char*)(P) |= (V)) | |
| 41 | * atomic_clear_char(P, V) (*(u_char*)(P) &= ~(V)) | |
| 42 | * atomic_add_char(P, V) (*(u_char*)(P) += (V)) | |
| 43 | * atomic_subtract_char(P, V) (*(u_char*)(P) -= (V)) | |
| 44 | * | |
| 45 | * atomic_set_short(P, V) (*(u_short*)(P) |= (V)) | |
| 46 | * atomic_clear_short(P, V) (*(u_short*)(P) &= ~(V)) | |
| 47 | * atomic_add_short(P, V) (*(u_short*)(P) += (V)) | |
| 48 | * atomic_subtract_short(P, V) (*(u_short*)(P) -= (V)) | |
| 49 | * | |
| 50 | * atomic_set_int(P, V) (*(u_int*)(P) |= (V)) | |
| 51 | * atomic_clear_int(P, V) (*(u_int*)(P) &= ~(V)) | |
| 52 | * atomic_add_int(P, V) (*(u_int*)(P) += (V)) | |
| 53 | * atomic_subtract_int(P, V) (*(u_int*)(P) -= (V)) | |
| 54 | * | |
| 55 | * atomic_set_long(P, V) (*(u_long*)(P) |= (V)) | |
| 56 | * atomic_clear_long(P, V) (*(u_long*)(P) &= ~(V)) | |
| 57 | * atomic_add_long(P, V) (*(u_long*)(P) += (V)) | |
| 58 | * atomic_subtract_long(P, V) (*(u_long*)(P) -= (V)) | |
| 59 | */ | |
| 60 | ||
| 61 | /* | |
| 62 | * The above functions are expanded inline in the statically-linked | |
| 63 | * kernel. Lock prefixes are generated if an SMP kernel is being | |
| 46ebb8bc | 64 | * built, or if user code is using these functions. |
| 984263bc MD |
65 | * |
| 66 | * Kernel modules call real functions which are built into the kernel. | |
| 67 | * This allows kernel modules to be portable between UP and SMP systems. | |
| 68 | */ | |
| 69 | #if defined(KLD_MODULE) | |
| 70 | #define ATOMIC_ASM(NAME, TYPE, OP, V) \ | |
| 630fe4cb MD |
71 | extern void atomic_##NAME##_##TYPE(volatile u_##TYPE *p, u_##TYPE v); \ |
| 72 | extern void atomic_##NAME##_##TYPE##_nonlocked(volatile u_##TYPE *p, u_##TYPE v); | |
| 984263bc | 73 | #else /* !KLD_MODULE */ |
| 46ebb8bc | 74 | #if defined(SMP) || !defined(_KERNEL) |
| 984263bc MD |
75 | #define MPLOCKED "lock ; " |
| 76 | #else | |
| 77 | #define MPLOCKED | |
| 78 | #endif | |
| 79 | ||
| 80 | /* | |
| 81 | * The assembly is volatilized to demark potential before-and-after side | |
| a2a5ad0d MD |
82 | * effects if an interrupt or SMP collision were to occur. The primary |
| 83 | * atomic instructions are MP safe, the nonlocked instructions are | |
| 84 | * local-interrupt-safe (so we don't depend on C 'X |= Y' generating an | |
| 85 | * atomic instruction). | |
| 5249a4cd MD |
86 | * |
| 87 | * +m - memory is read and written (=m - memory is only written) | |
| 88 | * iq - integer constant or %ax/%bx/%cx/%dx (ir = int constant or any reg) | |
| 89 | * (Note: byte instructions only work on %ax,%bx,%cx, or %dx). iq | |
| 90 | * is good enough for our needs so don't get fancy. | |
| 984263bc | 91 | */ |
| a2a5ad0d | 92 | |
| 984263bc MD |
93 | /* egcs 1.1.2+ version */ |
| 94 | #define ATOMIC_ASM(NAME, TYPE, OP, V) \ | |
| 95 | static __inline void \ | |
| 96 | atomic_##NAME##_##TYPE(volatile u_##TYPE *p, u_##TYPE v)\ | |
| 97 | { \ | |
| 98 | __asm __volatile(MPLOCKED OP \ | |
| 5249a4cd MD |
99 | : "+m" (*p) \ |
| 100 | : "iq" (V)); \ | |
| a2a5ad0d MD |
101 | } \ |
| 102 | static __inline void \ | |
| 103 | atomic_##NAME##_##TYPE##_nonlocked(volatile u_##TYPE *p, u_##TYPE v)\ | |
| 104 | { \ | |
| ea475962 | 105 | __asm __volatile(OP \ |
| 5249a4cd MD |
106 | : "+m" (*p) \ |
| 107 | : "iq" (V)); \ | |
| 984263bc MD |
108 | } |
| 109 | ||
| 984263bc MD |
110 | #endif /* KLD_MODULE */ |
| 111 | ||
| 984263bc | 112 | /* egcs 1.1.2+ version */ |
| ef9e98e2 MD |
113 | ATOMIC_ASM(set, char, "orb %b1,%0", v) |
| 114 | ATOMIC_ASM(clear, char, "andb %b1,%0", ~v) | |
| 115 | ATOMIC_ASM(add, char, "addb %b1,%0", v) | |
| 116 | ATOMIC_ASM(subtract, char, "subb %b1,%0", v) | |
| 984263bc | 117 | |
| ef9e98e2 MD |
118 | ATOMIC_ASM(set, short, "orw %w1,%0", v) |
| 119 | ATOMIC_ASM(clear, short, "andw %w1,%0", ~v) | |
| 120 | ATOMIC_ASM(add, short, "addw %w1,%0", v) | |
| 121 | ATOMIC_ASM(subtract, short, "subw %w1,%0", v) | |
| 984263bc | 122 | |
| ef9e98e2 MD |
123 | ATOMIC_ASM(set, int, "orl %1,%0", v) |
| 124 | ATOMIC_ASM(clear, int, "andl %1,%0", ~v) | |
| 125 | ATOMIC_ASM(add, int, "addl %1,%0", v) | |
| 126 | ATOMIC_ASM(subtract, int, "subl %1,%0", v) | |
| 984263bc | 127 | |
| ef9e98e2 MD |
128 | ATOMIC_ASM(set, long, "orl %1,%0", v) |
| 129 | ATOMIC_ASM(clear, long, "andl %1,%0", ~v) | |
| 130 | ATOMIC_ASM(add, long, "addl %1,%0", v) | |
| 131 | ATOMIC_ASM(subtract, long, "subl %1,%0", v) | |
| 984263bc | 132 | |
| 6fc51f62 | 133 | /* |
| 4c9f5a7f MD |
134 | * atomic_poll_acquire_int(P) Returns non-zero on success, 0 if the lock |
| 135 | * has already been acquired. | |
| 6fc51f62 MD |
136 | * atomic_poll_release_int(P) |
| 137 | * | |
| 4c9f5a7f MD |
138 | * These support the NDIS driver and are also used for IPIQ interlocks |
| 139 | * between cpus. Both the acquisition and release must be | |
| 140 | * cache-synchronizing instructions. | |
| 6fc51f62 MD |
141 | */ |
| 142 | ||
| 143 | #if defined(KLD_MODULE) | |
| 144 | ||
| b1af91cb | 145 | extern int atomic_swap_int(volatile int *addr, int value); |
| 6fc51f62 MD |
146 | extern int atomic_poll_acquire_int(volatile u_int *p); |
| 147 | extern void atomic_poll_release_int(volatile u_int *p); | |
| 148 | ||
| 149 | #else | |
| 150 | ||
| b1af91cb JH |
151 | static __inline int |
| 152 | atomic_swap_int(volatile int *addr, int value) | |
| 153 | { | |
| 154 | __asm __volatile("xchgl %0, %1" : | |
| 155 | "=r" (value), "=m" (*addr) : "0" (value) : "memory"); | |
| 156 | return (value); | |
| 157 | } | |
| 158 | ||
| 6fc51f62 MD |
159 | static __inline |
| 160 | int | |
| 161 | atomic_poll_acquire_int(volatile u_int *p) | |
| 162 | { | |
| 163 | u_int data; | |
| 164 | ||
| 165 | __asm __volatile(MPLOCKED "btsl $0,%0; setnc %%al; andl $255,%%eax" : "+m" (*p), "=a" (data)); | |
| 166 | return(data); | |
| 167 | } | |
| 168 | ||
| 169 | static __inline | |
| 170 | void | |
| 171 | atomic_poll_release_int(volatile u_int *p) | |
| 172 | { | |
| 4c9f5a7f | 173 | __asm __volatile(MPLOCKED "btrl $0,%0" : "+m" (*p)); |
| 6fc51f62 MD |
174 | } |
| 175 | ||
| 176 | #endif | |
| 177 | ||
| e9cb6d99 MD |
178 | /* |
| 179 | * These functions operate on a 32 bit interrupt interlock which is defined | |
| 180 | * as follows: | |
| 181 | * | |
| 182 | * bit 0-30 interrupt handler disabled bits (counter) | |
| 183 | * bit 31 interrupt handler currently running bit (1 = run) | |
| 184 | * | |
| f0ca723e MD |
185 | * atomic_intr_cond_test(P) Determine if the interlock is in an |
| 186 | * acquired state. Returns 0 if it not | |
| 187 | * acquired, non-zero if it is. | |
| e9cb6d99 | 188 | * |
| 477d3c1c MD |
189 | * atomic_intr_cond_try(P) |
| 190 | * Increment the request counter and attempt to | |
| 191 | * set bit 31 to acquire the interlock. If | |
| 192 | * we are unable to set bit 31 the request | |
| 193 | * counter is decremented and we return -1, | |
| 194 | * otherwise we return 0. | |
| 195 | * | |
| e9cb6d99 MD |
196 | * atomic_intr_cond_enter(P, func, arg) |
| 197 | * Increment the request counter and attempt to | |
| 198 | * set bit 31 to acquire the interlock. If | |
| 199 | * we are unable to set bit 31 func(arg) is | |
| 200 | * called in a loop until we are able to set | |
| 201 | * bit 31. | |
| 202 | * | |
| 203 | * atomic_intr_cond_exit(P, func, arg) | |
| 204 | * Decrement the request counter and clear bit | |
| 205 | * 31. If the request counter is still non-zero | |
| 206 | * call func(arg) once. | |
| 207 | * | |
| 208 | * atomic_intr_handler_disable(P) | |
| 209 | * Set bit 30, indicating that the interrupt | |
| 210 | * handler has been disabled. Must be called | |
| 211 | * after the hardware is disabled. | |
| 212 | * | |
| 213 | * Returns bit 31 indicating whether a serialized | |
| 214 | * accessor is active (typically the interrupt | |
| 215 | * handler is running). 0 == not active, | |
| 216 | * non-zero == active. | |
| 217 | * | |
| 218 | * atomic_intr_handler_enable(P) | |
| 219 | * Clear bit 30, indicating that the interrupt | |
| 220 | * handler has been enabled. Must be called | |
| 221 | * before the hardware is actually enabled. | |
| 222 | * | |
| 223 | * atomic_intr_handler_is_enabled(P) | |
| 224 | * Returns bit 30, 0 indicates that the handler | |
| 225 | * is enabled, non-zero indicates that it is | |
| 226 | * disabled. The request counter portion of | |
| 227 | * the field is ignored. | |
| 228 | */ | |
| 229 | ||
| e9cb6d99 MD |
230 | #if defined(KLD_MODULE) |
| 231 | ||
| aa368711 JS |
232 | void atomic_intr_init(__atomic_intr_t *p); |
| 233 | int atomic_intr_handler_disable(__atomic_intr_t *p); | |
| 234 | void atomic_intr_handler_enable(__atomic_intr_t *p); | |
| 235 | int atomic_intr_handler_is_enabled(__atomic_intr_t *p); | |
| 236 | int atomic_intr_cond_test(__atomic_intr_t *p); | |
| 237 | int atomic_intr_cond_try(__atomic_intr_t *p); | |
| 238 | void atomic_intr_cond_enter(__atomic_intr_t *p, void (*func)(void *), void *arg); | |
| 239 | void atomic_intr_cond_exit(__atomic_intr_t *p, void (*func)(void *), void *arg); | |
| e9cb6d99 MD |
240 | |
| 241 | #else | |
| 242 | ||
| 243 | static __inline | |
| 244 | void | |
| aa368711 | 245 | atomic_intr_init(__atomic_intr_t *p) |
| e9cb6d99 MD |
246 | { |
| 247 | *p = 0; | |
| 248 | } | |
| 249 | ||
| 250 | static __inline | |
| 251 | int | |
| aa368711 | 252 | atomic_intr_handler_disable(__atomic_intr_t *p) |
| e9cb6d99 MD |
253 | { |
| 254 | int data; | |
| 255 | ||
| 256 | __asm __volatile(MPLOCKED "orl $0x40000000,%1; movl %1,%%eax; " \ | |
| 257 | "andl $0x80000000,%%eax" \ | |
| f0ca723e | 258 | : "=a"(data) , "+m"(*p)); |
| e9cb6d99 MD |
259 | return(data); |
| 260 | } | |
| 261 | ||
| 262 | static __inline | |
| 263 | void | |
| aa368711 | 264 | atomic_intr_handler_enable(__atomic_intr_t *p) |
| e9cb6d99 | 265 | { |
| 9c095379 | 266 | __asm __volatile(MPLOCKED "andl $0xBFFFFFFF,%0" : "+m" (*p)); |
| e9cb6d99 MD |
267 | } |
| 268 | ||
| 269 | static __inline | |
| 270 | int | |
| aa368711 | 271 | atomic_intr_handler_is_enabled(__atomic_intr_t *p) |
| e9cb6d99 MD |
272 | { |
| 273 | int data; | |
| 274 | ||
| 275 | __asm __volatile("movl %1,%%eax; andl $0x40000000,%%eax" \ | |
| 276 | : "=a"(data) : "m"(*p)); | |
| 277 | return(data); | |
| 278 | } | |
| 279 | ||
| 280 | static __inline | |
| 281 | void | |
| aa368711 | 282 | atomic_intr_cond_enter(__atomic_intr_t *p, void (*func)(void *), void *arg) |
| e9cb6d99 MD |
283 | { |
| 284 | __asm __volatile(MPLOCKED "incl %0; " \ | |
| 285 | "1: ;" \ | |
| 286 | MPLOCKED "btsl $31,%0; jnc 2f; " \ | |
| 287 | "pushl %2; call *%1; addl $4,%%esp; " \ | |
| 288 | "jmp 1b; " \ | |
| 289 | "2: ;" \ | |
| 290 | : "+m" (*p) \ | |
| 291 | : "r"(func), "m"(arg) \ | |
| 292 | : "ax", "cx", "dx"); | |
| 293 | } | |
| 294 | ||
| 477d3c1c MD |
295 | /* |
| 296 | * Attempt to enter the interrupt condition variable. Returns zero on | |
| 297 | * success, 1 on failure. | |
| 298 | */ | |
| 299 | static __inline | |
| 300 | int | |
| aa368711 | 301 | atomic_intr_cond_try(__atomic_intr_t *p) |
| 477d3c1c MD |
302 | { |
| 303 | int ret; | |
| 304 | ||
| 3c9ed2a4 MD |
305 | __asm __volatile(MPLOCKED "incl %0; " \ |
| 306 | "1: ;" \ | |
| 307 | "subl %%eax,%%eax; " \ | |
| 308 | MPLOCKED "btsl $31,%0; jnc 2f; " \ | |
| 309 | MPLOCKED "decl %0; " \ | |
| 310 | "movl $1,%%eax;" \ | |
| 311 | "2: ;" | |
| caae4d60 | 312 | : "+m" (*p), "=&a"(ret) |
| c4fb66bd | 313 | : : "cx", "dx"); |
| 477d3c1c MD |
314 | return (ret); |
| 315 | } | |
| 316 | ||
| 317 | ||
| e9cb6d99 | 318 | static __inline |
| d02b46cd | 319 | int |
| aa368711 | 320 | atomic_intr_cond_test(__atomic_intr_t *p) |
| d02b46cd | 321 | { |
| f0ca723e | 322 | return((int)(*p & 0x80000000)); |
| d02b46cd MD |
323 | } |
| 324 | ||
| 325 | static __inline | |
| e9cb6d99 | 326 | void |
| aa368711 | 327 | atomic_intr_cond_exit(__atomic_intr_t *p, void (*func)(void *), void *arg) |
| e9cb6d99 MD |
328 | { |
| 329 | __asm __volatile(MPLOCKED "decl %0; " \ | |
| 330 | MPLOCKED "btrl $31,%0; " \ | |
| 331 | "testl $0x3FFFFFFF,%0; jz 1f; " \ | |
| 332 | "pushl %2; call *%1; addl $4,%%esp; " \ | |
| 333 | "1: ;" \ | |
| 334 | : "+m" (*p) \ | |
| 335 | : "r"(func), "m"(arg) \ | |
| 336 | : "ax", "cx", "dx"); | |
| 337 | } | |
| 338 | ||
| 339 | #endif | |
| 340 | ||
| 3a4e0cd7 SZ |
341 | /* |
| 342 | * Atomic compare and set | |
| 343 | * | |
| 74dd601f | 344 | * if (*_dst == _old) *_dst = _new (all 32 bit words) |
| 3a4e0cd7 SZ |
345 | * |
| 346 | * Returns 0 on failure, non-zero on success | |
| 347 | */ | |
| 348 | #if defined(KLD_MODULE) | |
| 5b296f84 | 349 | |
| 74dd601f | 350 | extern int atomic_cmpset_int(volatile u_int *_dst, u_int _old, u_int _new); |
| 46037fcb SS |
351 | extern long atomic_cmpset_long(volatile u_long *_dst, u_long _exp, u_long _src); |
| 352 | extern u_int atomic_fetchadd_int(volatile u_int *_p, u_int _v); | |
| 5b296f84 | 353 | |
| 3a4e0cd7 | 354 | #else |
| 5b296f84 | 355 | |
| 3a4e0cd7 | 356 | static __inline int |
| 74dd601f | 357 | atomic_cmpset_int(volatile u_int *_dst, u_int _old, u_int _new) |
| 3a4e0cd7 | 358 | { |
| 750f8fdb | 359 | u_int res = _old; |
| 3a4e0cd7 SZ |
360 | |
| 361 | __asm __volatile(MPLOCKED "cmpxchgl %2,%1; " \ | |
| 74dd601f VBD |
362 | : "+a" (res), "=m" (*_dst) \ |
| 363 | : "r" (_new), "m" (*_dst) \ | |
| 3a4e0cd7 | 364 | : "memory"); |
| ab6109fb | 365 | return (res == _old); |
| 3a4e0cd7 | 366 | } |
| 5b296f84 | 367 | |
| a22fe0ac | 368 | static __inline long |
| 46037fcb | 369 | atomic_cmpset_long(volatile u_long *_dst, u_long _exp, u_long _src) |
| 5b296f84 | 370 | { |
| 46037fcb SS |
371 | return (atomic_cmpset_int((volatile u_int *)_dst, (u_int)_exp, |
| 372 | (u_int)_src)); | |
| 5b296f84 MD |
373 | } |
| 374 | ||
| 375 | /* | |
| 376 | * Atomically add the value of v to the integer pointed to by p and return | |
| 377 | * the previous value of *p. | |
| 378 | */ | |
| 379 | static __inline u_int | |
| 46037fcb | 380 | atomic_fetchadd_int(volatile u_int *_p, u_int _v) |
| 5b296f84 MD |
381 | { |
| 382 | __asm __volatile(MPLOCKED "xaddl %0,%1; " \ | |
| 46037fcb SS |
383 | : "+r" (_v), "=m" (*_p) \ |
| 384 | : "m" (*_p) \ | |
| 5b296f84 | 385 | : "memory"); |
| 46037fcb | 386 | return (_v); |
| 5b296f84 MD |
387 | } |
| 388 | ||
| 3a4e0cd7 SZ |
389 | #endif /* KLD_MODULE */ |
| 390 | ||
| 299ec900 HT |
391 | #if defined(KLD_MODULE) |
| 392 | ||
| 393 | #define ATOMIC_STORE_LOAD(TYPE, LOP, SOP) \ | |
| 394 | extern u_##TYPE atomic_load_acq_##TYPE(volatile u_##TYPE *p); \ | |
| 395 | extern void atomic_store_rel_##TYPE(volatile u_##TYPE *p, u_##TYPE v); | |
| 396 | ||
| 397 | #else /* !KLD_MODULE */ | |
| 398 | ||
| 399 | #if defined(_KERNEL) && !defined(SMP) | |
| 400 | /* | |
| 401 | * We assume that a = b will do atomic loads and stores. However, on a | |
| 402 | * PentiumPro or higher, reads may pass writes, so for that case we have | |
| 403 | * to use a serializing instruction (i.e. with LOCK) to do the load in | |
| 404 | * SMP kernels. For UP kernels, however, the cache of the single processor | |
| 405 | * is always consistent, so we don't need any memory barriers. | |
| 406 | */ | |
| 407 | #define ATOMIC_STORE_LOAD(TYPE, LOP, SOP) \ | |
| 408 | static __inline u_##TYPE \ | |
| 409 | atomic_load_acq_##TYPE(volatile u_##TYPE *p) \ | |
| 410 | { \ | |
| 411 | return (*p); \ | |
| 412 | } \ | |
| 413 | \ | |
| 414 | static __inline void \ | |
| 415 | atomic_store_rel_##TYPE(volatile u_##TYPE *p, u_##TYPE v)\ | |
| 416 | { \ | |
| 417 | *p = v; \ | |
| 418 | } \ | |
| 419 | struct __hack | |
| 420 | ||
| 421 | #else /* !(_KERNEL && !SMP) */ | |
| 422 | ||
| 423 | #define ATOMIC_STORE_LOAD(TYPE, LOP, SOP) \ | |
| 424 | static __inline u_##TYPE \ | |
| 425 | atomic_load_acq_##TYPE(volatile u_##TYPE *p) \ | |
| 426 | { \ | |
| 427 | u_##TYPE res; \ | |
| 428 | \ | |
| 429 | __asm __volatile(MPLOCKED LOP \ | |
| 430 | : "=a" (res), /* 0 */ \ | |
| 431 | "=m" (*p) /* 1 */ \ | |
| 432 | : "m" (*p) /* 2 */ \ | |
| 433 | : "memory"); \ | |
| 434 | \ | |
| 435 | return (res); \ | |
| 436 | } \ | |
| 437 | \ | |
| 438 | /* \ | |
| 439 | * The XCHG instruction asserts LOCK automagically. \ | |
| 440 | */ \ | |
| 441 | static __inline void \ | |
| 442 | atomic_store_rel_##TYPE(volatile u_##TYPE *p, u_##TYPE v)\ | |
| 443 | { \ | |
| 444 | __asm __volatile(SOP \ | |
| 445 | : "=m" (*p), /* 0 */ \ | |
| 446 | "+r" (v) /* 1 */ \ | |
| 447 | : "m" (*p)); /* 2 */ \ | |
| 448 | } \ | |
| 449 | struct __hack | |
| 450 | ||
| 451 | #endif /* _KERNEL && !SMP */ | |
| 452 | ||
| 453 | #endif /* !KLD_MODULE */ | |
| 454 | ||
| 455 | ATOMIC_STORE_LOAD(char, "cmpxchgb %b0,%1", "xchgb %b1,%0"); | |
| 456 | ATOMIC_STORE_LOAD(short,"cmpxchgw %w0,%1", "xchgw %w1,%0"); | |
| 457 | ATOMIC_STORE_LOAD(int, "cmpxchgl %0,%1", "xchgl %1,%0"); | |
| 458 | ATOMIC_STORE_LOAD(long, "cmpxchgl %0,%1", "xchgl %1,%0"); | |
| 459 | ||
| 750f8fdb SW |
460 | #undef ATOMIC_ASM |
| 461 | #undef ATOMIC_STORE_LOAD | |
| 462 | ||
| 5b296f84 MD |
463 | /* Acquire and release variants are identical to the normal ones. */ |
| 464 | #define atomic_set_acq_char atomic_set_char | |
| 465 | #define atomic_set_rel_char atomic_set_char | |
| 466 | #define atomic_clear_acq_char atomic_clear_char | |
| 467 | #define atomic_clear_rel_char atomic_clear_char | |
| 468 | #define atomic_add_acq_char atomic_add_char | |
| 469 | #define atomic_add_rel_char atomic_add_char | |
| 470 | #define atomic_subtract_acq_char atomic_subtract_char | |
| 471 | #define atomic_subtract_rel_char atomic_subtract_char | |
| 472 | ||
| 473 | #define atomic_set_acq_short atomic_set_short | |
| 474 | #define atomic_set_rel_short atomic_set_short | |
| 475 | #define atomic_clear_acq_short atomic_clear_short | |
| 476 | #define atomic_clear_rel_short atomic_clear_short | |
| 477 | #define atomic_add_acq_short atomic_add_short | |
| 478 | #define atomic_add_rel_short atomic_add_short | |
| 479 | #define atomic_subtract_acq_short atomic_subtract_short | |
| 480 | #define atomic_subtract_rel_short atomic_subtract_short | |
| 481 | ||
| 482 | #define atomic_set_acq_int atomic_set_int | |
| 483 | #define atomic_set_rel_int atomic_set_int | |
| 484 | #define atomic_clear_acq_int atomic_clear_int | |
| 485 | #define atomic_clear_rel_int atomic_clear_int | |
| 486 | #define atomic_add_acq_int atomic_add_int | |
| 487 | #define atomic_add_rel_int atomic_add_int | |
| 488 | #define atomic_subtract_acq_int atomic_subtract_int | |
| 489 | #define atomic_subtract_rel_int atomic_subtract_int | |
| 490 | #define atomic_cmpset_acq_int atomic_cmpset_int | |
| 491 | #define atomic_cmpset_rel_int atomic_cmpset_int | |
| 492 | ||
| 493 | #define atomic_set_acq_long atomic_set_long | |
| 494 | #define atomic_set_rel_long atomic_set_long | |
| 495 | #define atomic_clear_acq_long atomic_clear_long | |
| 496 | #define atomic_clear_rel_long atomic_clear_long | |
| 497 | #define atomic_add_acq_long atomic_add_long | |
| 498 | #define atomic_add_rel_long atomic_add_long | |
| 499 | #define atomic_subtract_acq_long atomic_subtract_long | |
| 500 | #define atomic_subtract_rel_long atomic_subtract_long | |
| 501 | #define atomic_cmpset_acq_long atomic_cmpset_long | |
| 502 | #define atomic_cmpset_rel_long atomic_cmpset_long | |
| 503 | ||
| 504 | /* Operations on 8-bit bytes. */ | |
| 505 | #define atomic_set_8 atomic_set_char | |
| 506 | #define atomic_set_acq_8 atomic_set_acq_char | |
| 507 | #define atomic_set_rel_8 atomic_set_rel_char | |
| 508 | #define atomic_clear_8 atomic_clear_char | |
| 509 | #define atomic_clear_acq_8 atomic_clear_acq_char | |
| 510 | #define atomic_clear_rel_8 atomic_clear_rel_char | |
| 511 | #define atomic_add_8 atomic_add_char | |
| 512 | #define atomic_add_acq_8 atomic_add_acq_char | |
| 513 | #define atomic_add_rel_8 atomic_add_rel_char | |
| 514 | #define atomic_subtract_8 atomic_subtract_char | |
| 515 | #define atomic_subtract_acq_8 atomic_subtract_acq_char | |
| 516 | #define atomic_subtract_rel_8 atomic_subtract_rel_char | |
| 517 | #define atomic_load_acq_8 atomic_load_acq_char | |
| 518 | #define atomic_store_rel_8 atomic_store_rel_char | |
| 519 | ||
| 520 | /* Operations on 16-bit words. */ | |
| 521 | #define atomic_set_16 atomic_set_short | |
| 522 | #define atomic_set_acq_16 atomic_set_acq_short | |
| 523 | #define atomic_set_rel_16 atomic_set_rel_short | |
| 524 | #define atomic_clear_16 atomic_clear_short | |
| 525 | #define atomic_clear_acq_16 atomic_clear_acq_short | |
| 526 | #define atomic_clear_rel_16 atomic_clear_rel_short | |
| 527 | #define atomic_add_16 atomic_add_short | |
| 528 | #define atomic_add_acq_16 atomic_add_acq_short | |
| 529 | #define atomic_add_rel_16 atomic_add_rel_short | |
| 530 | #define atomic_subtract_16 atomic_subtract_short | |
| 531 | #define atomic_subtract_acq_16 atomic_subtract_acq_short | |
| 532 | #define atomic_subtract_rel_16 atomic_subtract_rel_short | |
| 533 | #define atomic_load_acq_16 atomic_load_acq_short | |
| 534 | #define atomic_store_rel_16 atomic_store_rel_short | |
| 535 | ||
| 536 | /* Operations on 32-bit double words. */ | |
| 537 | #define atomic_set_32 atomic_set_int | |
| 538 | #define atomic_set_acq_32 atomic_set_acq_int | |
| 539 | #define atomic_set_rel_32 atomic_set_rel_int | |
| 540 | #define atomic_clear_32 atomic_clear_int | |
| 541 | #define atomic_clear_acq_32 atomic_clear_acq_int | |
| 542 | #define atomic_clear_rel_32 atomic_clear_rel_int | |
| 543 | #define atomic_add_32 atomic_add_int | |
| 544 | #define atomic_add_acq_32 atomic_add_acq_int | |
| 545 | #define atomic_add_rel_32 atomic_add_rel_int | |
| 546 | #define atomic_subtract_32 atomic_subtract_int | |
| 547 | #define atomic_subtract_acq_32 atomic_subtract_acq_int | |
| 548 | #define atomic_subtract_rel_32 atomic_subtract_rel_int | |
| 549 | #define atomic_load_acq_32 atomic_load_acq_int | |
| 550 | #define atomic_store_rel_32 atomic_store_rel_int | |
| 551 | #define atomic_cmpset_32 atomic_cmpset_int | |
| 552 | #define atomic_cmpset_acq_32 atomic_cmpset_acq_int | |
| 553 | #define atomic_cmpset_rel_32 atomic_cmpset_rel_int | |
| 554 | #define atomic_readandclear_32 atomic_readandclear_int | |
| 555 | #define atomic_fetchadd_32 atomic_fetchadd_int | |
| 556 | ||
| 557 | /* Operations on pointers. */ | |
| 558 | #define atomic_set_ptr(p, v) \ | |
| 559 | atomic_set_int((volatile u_int *)(p), (u_int)(v)) | |
| 560 | #define atomic_set_acq_ptr(p, v) \ | |
| 561 | atomic_set_acq_int((volatile u_int *)(p), (u_int)(v)) | |
| 562 | #define atomic_set_rel_ptr(p, v) \ | |
| 563 | atomic_set_rel_int((volatile u_int *)(p), (u_int)(v)) | |
| 564 | #define atomic_clear_ptr(p, v) \ | |
| 565 | atomic_clear_int((volatile u_int *)(p), (u_int)(v)) | |
| 566 | #define atomic_clear_acq_ptr(p, v) \ | |
| 567 | atomic_clear_acq_int((volatile u_int *)(p), (u_int)(v)) | |
| 568 | #define atomic_clear_rel_ptr(p, v) \ | |
| 569 | atomic_clear_rel_int((volatile u_int *)(p), (u_int)(v)) | |
| 570 | #define atomic_add_ptr(p, v) \ | |
| 571 | atomic_add_int((volatile u_int *)(p), (u_int)(v)) | |
| 572 | #define atomic_add_acq_ptr(p, v) \ | |
| 573 | atomic_add_acq_int((volatile u_int *)(p), (u_int)(v)) | |
| 574 | #define atomic_add_rel_ptr(p, v) \ | |
| 575 | atomic_add_rel_int((volatile u_int *)(p), (u_int)(v)) | |
| 576 | #define atomic_subtract_ptr(p, v) \ | |
| 577 | atomic_subtract_int((volatile u_int *)(p), (u_int)(v)) | |
| 578 | #define atomic_subtract_acq_ptr(p, v) \ | |
| 579 | atomic_subtract_acq_int((volatile u_int *)(p), (u_int)(v)) | |
| 580 | #define atomic_subtract_rel_ptr(p, v) \ | |
| 581 | atomic_subtract_rel_int((volatile u_int *)(p), (u_int)(v)) | |
| 582 | #define atomic_load_acq_ptr(p) \ | |
| 583 | atomic_load_acq_int((volatile u_int *)(p)) | |
| 584 | #define atomic_store_rel_ptr(p, v) \ | |
| 585 | atomic_store_rel_int((volatile u_int *)(p), (v)) | |
| 586 | #define atomic_cmpset_ptr(dst, old, new) \ | |
| 587 | atomic_cmpset_int((volatile u_int *)(dst), (u_int)(old), (u_int)(new)) | |
| 588 | #define atomic_cmpset_acq_ptr(dst, old, new) \ | |
| 589 | atomic_cmpset_acq_int((volatile u_int *)(dst), (u_int)(old), \ | |
| 590 | (u_int)(new)) | |
| 591 | #define atomic_cmpset_rel_ptr(dst, old, new) \ | |
| 592 | atomic_cmpset_rel_int((volatile u_int *)(dst), (u_int)(old), \ | |
| 593 | (u_int)(new)) | |
| 594 | #define atomic_readandclear_ptr(p) \ | |
| 595 | atomic_readandclear_int((volatile u_int *)(p)) | |
| 596 | ||
| a9295349 | 597 | #endif /* ! _CPU_ATOMIC_H_ */ |