1 /*- 2 * Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com> 3 * All rights reserved. 4 * 5 * Portions of this software were developed by SRI International and the 6 * University of Cambridge Computer Laboratory under DARPA/AFRL contract 7 * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme. 8 * 9 * Portions of this software were developed by the University of Cambridge 10 * Computer Laboratory as part of the CTSRD Project, with support from the 11 * UK Higher Education Innovation Fund (HEIF). 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * $FreeBSD$ 35 */ 36 37 #ifndef _MACHINE_ATOMIC_H_ 38 #define _MACHINE_ATOMIC_H_ 39 40 #define fence() __asm __volatile("fence" ::: "memory"); 41 #define mb() fence() 42 #define rmb() fence() 43 #define wmb() fence() 44 45 #define ATOMIC_ACQ_REL(NAME, WIDTH) \ 46 static __inline void \ 47 atomic_##NAME##_acq_##WIDTH(__volatile uint##WIDTH##_t *p, uint##WIDTH##_t v)\ 48 { \ 49 atomic_##NAME##_##WIDTH(p, v); \ 50 fence(); \ 51 } \ 52 \ 53 static __inline void \ 54 atomic_##NAME##_rel_##WIDTH(__volatile uint##WIDTH##_t *p, uint##WIDTH##_t v)\ 55 { \ 56 fence(); \ 57 atomic_##NAME##_##WIDTH(p, v); \ 58 } 59 60 static __inline void 61 atomic_add_32(volatile uint32_t *p, uint32_t val) 62 { 63 64 __asm __volatile("amoadd.w zero, %1, %0" 65 : "+A" (*p) 66 : "r" (val) 67 : "memory"); 68 } 69 70 static __inline void 71 atomic_subtract_32(volatile uint32_t *p, uint32_t val) 72 { 73 74 __asm __volatile("amoadd.w zero, %1, %0" 75 : "+A" (*p) 76 : "r" (-val) 77 : "memory"); 78 } 79 80 static __inline void 81 atomic_set_32(volatile uint32_t *p, uint32_t val) 82 { 83 84 __asm __volatile("amoor.w zero, %1, %0" 85 : "+A" (*p) 86 : "r" (val) 87 : "memory"); 88 } 89 90 static __inline void 91 atomic_clear_32(volatile uint32_t *p, uint32_t val) 92 { 93 94 __asm __volatile("amoand.w zero, %1, %0" 95 : "+A" (*p) 96 : "r" (~val) 97 : "memory"); 98 } 99 100 static __inline int 101 atomic_cmpset_32(volatile uint32_t *p, uint32_t cmpval, uint32_t newval) 102 { 103 uint32_t tmp; 104 int res; 105 106 res = 0; 107 108 __asm __volatile( 109 "0:" 110 "li %1, 1\n" /* Preset to fail */ 111 "lr.w %0, %2\n" 112 "bne %0, %z3, 1f\n" 113 "sc.w %1, %z4, %2\n" 114 "bnez %1, 0b\n" 115 "1:" 116 : "=&r" (tmp), "=&r" (res), "+A" (*p) 117 : "rJ" (cmpval), "rJ" (newval) 118 : "memory"); 119 120 return (!res); 121 } 122 123 static __inline uint32_t 124 atomic_fetchadd_32(volatile uint32_t *p, uint32_t val) 125 { 126 uint32_t ret; 127 128 __asm __volatile("amoadd.w %0, %2, %1" 129 : "=&r" (ret), "+A" (*p) 130 : "r" (val) 131 : "memory"); 132 133 return (ret); 134 } 135 136 static __inline uint32_t 137 atomic_readandclear_32(volatile uint32_t *p) 138 { 139 uint32_t ret; 140 uint32_t val; 141 142 val = 0; 143 144 __asm __volatile("amoswap.w %0, %2, %1" 145 : "=&r"(ret), "+A" (*p) 146 : "r" (val) 147 : "memory"); 148 149 return (ret); 150 } 151 152 #define atomic_add_int atomic_add_32 153 #define atomic_clear_int atomic_clear_32 154 #define atomic_cmpset_int atomic_cmpset_32 155 #define atomic_fetchadd_int atomic_fetchadd_32 156 #define atomic_readandclear_int atomic_readandclear_32 157 #define atomic_set_int atomic_set_32 158 #define atomic_subtract_int atomic_subtract_32 159 160 ATOMIC_ACQ_REL(set, 32) 161 ATOMIC_ACQ_REL(clear, 32) 162 ATOMIC_ACQ_REL(add, 32) 163 ATOMIC_ACQ_REL(subtract, 32) 164 165 static __inline int 166 atomic_cmpset_acq_32(volatile uint32_t *p, uint32_t cmpval, uint32_t newval) 167 { 168 int res; 169 170 res = atomic_cmpset_32(p, cmpval, newval); 171 172 fence(); 173 174 return (res); 175 } 176 177 static __inline int 178 atomic_cmpset_rel_32(volatile uint32_t *p, uint32_t cmpval, uint32_t newval) 179 { 180 181 fence(); 182 183 return (atomic_cmpset_32(p, cmpval, newval)); 184 } 185 186 static __inline uint32_t 187 atomic_load_acq_32(volatile uint32_t *p) 188 { 189 uint32_t ret; 190 191 ret = *p; 192 193 fence(); 194 195 return (ret); 196 } 197 198 static __inline void 199 atomic_store_rel_32(volatile uint32_t *p, uint32_t val) 200 { 201 202 fence(); 203 204 *p = val; 205 } 206 207 #define atomic_add_acq_int atomic_add_acq_32 208 #define atomic_clear_acq_int atomic_clear_acq_32 209 #define atomic_cmpset_acq_int atomic_cmpset_acq_32 210 #define atomic_load_acq_int atomic_load_acq_32 211 #define atomic_set_acq_int atomic_set_acq_32 212 #define atomic_subtract_acq_int atomic_subtract_acq_32 213 214 #define atomic_add_rel_int atomic_add_rel_32 215 #define atomic_clear_rel_int atomic_add_rel_32 216 #define atomic_cmpset_rel_int atomic_cmpset_rel_32 217 #define atomic_set_rel_int atomic_set_rel_32 218 #define atomic_subtract_rel_int atomic_subtract_rel_32 219 #define atomic_store_rel_int atomic_store_rel_32 220 221 static __inline void 222 atomic_add_64(volatile uint64_t *p, uint64_t val) 223 { 224 225 __asm __volatile("amoadd.d zero, %1, %0" 226 : "+A" (*p) 227 : "r" (val) 228 : "memory"); 229 } 230 231 static __inline void 232 atomic_subtract_64(volatile uint64_t *p, uint64_t val) 233 { 234 235 __asm __volatile("amoadd.d zero, %1, %0" 236 : "+A" (*p) 237 : "r" (-val) 238 : "memory"); 239 } 240 241 static __inline void 242 atomic_set_64(volatile uint64_t *p, uint64_t val) 243 { 244 245 __asm __volatile("amoor.d zero, %1, %0" 246 : "+A" (*p) 247 : "r" (val) 248 : "memory"); 249 } 250 251 static __inline void 252 atomic_clear_64(volatile uint64_t *p, uint64_t val) 253 { 254 255 __asm __volatile("amoand.d zero, %1, %0" 256 : "+A" (*p) 257 : "r" (~val) 258 : "memory"); 259 } 260 261 static __inline int 262 atomic_cmpset_64(volatile uint64_t *p, uint64_t cmpval, uint64_t newval) 263 { 264 uint64_t tmp; 265 int res; 266 267 res = 0; 268 269 __asm __volatile( 270 "0:" 271 "li %1, 1\n" /* Preset to fail */ 272 "lr.d %0, %2\n" 273 "bne %0, %z3, 1f\n" 274 "sc.d %1, %z4, %2\n" 275 "bnez %1, 0b\n" 276 "1:" 277 : "=&r" (tmp), "=&r" (res), "+A" (*p) 278 : "rJ" (cmpval), "rJ" (newval) 279 : "memory"); 280 281 return (!res); 282 } 283 284 static __inline uint64_t 285 atomic_fetchadd_64(volatile uint64_t *p, uint64_t val) 286 { 287 uint64_t ret; 288 289 __asm __volatile("amoadd.d %0, %2, %1" 290 : "=&r" (ret), "+A" (*p) 291 : "r" (val) 292 : "memory"); 293 294 return (ret); 295 } 296 297 static __inline uint64_t 298 atomic_readandclear_64(volatile uint64_t *p) 299 { 300 uint64_t ret; 301 uint64_t val; 302 303 val = 0; 304 305 __asm __volatile("amoswap.d %0, %2, %1" 306 : "=&r"(ret), "+A" (*p) 307 : "r" (val) 308 : "memory"); 309 310 return (ret); 311 } 312 313 static __inline uint32_t 314 atomic_swap_32(volatile uint32_t *p, uint32_t val) 315 { 316 uint32_t old; 317 318 __asm __volatile("amoswap.w %0, %2, %1" 319 : "=&r"(old), "+A" (*p) 320 : "r" (val) 321 : "memory"); 322 323 return (old); 324 } 325 326 static __inline uint64_t 327 atomic_swap_64(volatile uint64_t *p, uint64_t val) 328 { 329 uint64_t old; 330 331 __asm __volatile("amoswap.d %0, %2, %1" 332 : "=&r"(old), "+A" (*p) 333 : "r" (val) 334 : "memory"); 335 336 return (old); 337 } 338 339 #define atomic_add_long atomic_add_64 340 #define atomic_clear_long atomic_clear_64 341 #define atomic_cmpset_long atomic_cmpset_64 342 #define atomic_fetchadd_long atomic_fetchadd_64 343 #define atomic_readandclear_long atomic_readandclear_64 344 #define atomic_set_long atomic_set_64 345 #define atomic_subtract_long atomic_subtract_64 346 347 #define atomic_add_ptr atomic_add_64 348 #define atomic_clear_ptr atomic_clear_64 349 #define atomic_cmpset_ptr atomic_cmpset_64 350 #define atomic_fetchadd_ptr atomic_fetchadd_64 351 #define atomic_readandclear_ptr atomic_readandclear_64 352 #define atomic_set_ptr atomic_set_64 353 #define atomic_subtract_ptr atomic_subtract_64 354 355 ATOMIC_ACQ_REL(set, 64) 356 ATOMIC_ACQ_REL(clear, 64) 357 ATOMIC_ACQ_REL(add, 64) 358 ATOMIC_ACQ_REL(subtract, 64) 359 360 static __inline int 361 atomic_cmpset_acq_64(volatile uint64_t *p, uint64_t cmpval, uint64_t newval) 362 { 363 int res; 364 365 res = atomic_cmpset_64(p, cmpval, newval); 366 367 fence(); 368 369 return (res); 370 } 371 372 static __inline int 373 atomic_cmpset_rel_64(volatile uint64_t *p, uint64_t cmpval, uint64_t newval) 374 { 375 376 fence(); 377 378 return (atomic_cmpset_64(p, cmpval, newval)); 379 } 380 381 static __inline uint64_t 382 atomic_load_acq_64(volatile uint64_t *p) 383 { 384 uint64_t ret; 385 386 ret = *p; 387 388 fence(); 389 390 return (ret); 391 } 392 393 static __inline void 394 atomic_store_rel_64(volatile uint64_t *p, uint64_t val) 395 { 396 397 fence(); 398 399 *p = val; 400 } 401 402 #define atomic_add_acq_long atomic_add_acq_64 403 #define atomic_clear_acq_long atomic_add_acq_64 404 #define atomic_cmpset_acq_long atomic_cmpset_acq_64 405 #define atomic_load_acq_long atomic_load_acq_64 406 #define atomic_set_acq_long atomic_set_acq_64 407 #define atomic_subtract_acq_long atomic_subtract_acq_64 408 409 #define atomic_add_acq_ptr atomic_add_acq_64 410 #define atomic_clear_acq_ptr atomic_add_acq_64 411 #define atomic_cmpset_acq_ptr atomic_cmpset_acq_64 412 #define atomic_load_acq_ptr atomic_load_acq_64 413 #define atomic_set_acq_ptr atomic_set_acq_64 414 #define atomic_subtract_acq_ptr atomic_subtract_acq_64 415 416 static __inline void 417 atomic_thread_fence_acq(void) 418 { 419 420 fence(); 421 } 422 423 static __inline void 424 atomic_thread_fence_rel(void) 425 { 426 427 fence(); 428 } 429 430 static __inline void 431 atomic_thread_fence_acq_rel(void) 432 { 433 434 fence(); 435 } 436 437 static __inline void 438 atomic_thread_fence_seq_cst(void) 439 { 440 441 fence(); 442 } 443 444 #define atomic_add_rel_long atomic_add_rel_64 445 #define atomic_clear_rel_long atomic_clear_rel_64 446 447 #define atomic_add_rel_long atomic_add_rel_64 448 #define atomic_clear_rel_long atomic_clear_rel_64 449 #define atomic_cmpset_rel_long atomic_cmpset_rel_64 450 #define atomic_set_rel_long atomic_set_rel_64 451 #define atomic_subtract_rel_long atomic_subtract_rel_64 452 #define atomic_store_rel_long atomic_store_rel_64 453 454 #define atomic_add_rel_ptr atomic_add_rel_64 455 #define atomic_clear_rel_ptr atomic_clear_rel_64 456 #define atomic_cmpset_rel_ptr atomic_cmpset_rel_64 457 #define atomic_set_rel_ptr atomic_set_rel_64 458 #define atomic_subtract_rel_ptr atomic_subtract_rel_64 459 #define atomic_store_rel_ptr atomic_store_rel_64 460 461 #endif /* _MACHINE_ATOMIC_H_ */ 462