1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2008 Marcel Moolenaar 5 * Copyright (c) 2001 Benno Rice 6 * Copyright (c) 2001 David E. O'Brien 7 * Copyright (c) 1998 Doug Rabson 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * $FreeBSD$ 32 */ 33 34 #ifndef _MACHINE_ATOMIC_H_ 35 #define _MACHINE_ATOMIC_H_ 36 37 #include <sys/atomic_common.h> 38 39 #ifndef __powerpc64__ 40 #include <sys/_atomic64e.h> 41 #endif 42 43 /* 44 * The __ATOMIC_REL/ACQ() macros provide memory barriers only in conjunction 45 * with the atomic lXarx/stXcx. sequences below. They are not exposed outside 46 * of this file. See also Appendix B.2 of Book II of the architecture manual. 47 * 48 * Note that not all Book-E processors accept the light-weight sync variant. 49 * In particular, early models of E500 cores are known to wedge. Bank on all 50 * 64-bit capable CPUs to accept lwsync properly and pressimize 32-bit CPUs 51 * to use the heavier-weight sync. 52 */ 53 54 #ifdef __powerpc64__ 55 #define mb() __asm __volatile("sync" : : : "memory") 56 #define rmb() __asm __volatile("lwsync" : : : "memory") 57 #define wmb() __asm __volatile("lwsync" : : : "memory") 58 #define __ATOMIC_REL() __asm __volatile("lwsync" : : : "memory") 59 #define __ATOMIC_ACQ() __asm __volatile("isync" : : : "memory") 60 #else 61 #define mb() __asm __volatile("sync" : : : "memory") 62 #define rmb() __asm __volatile("sync" : : : "memory") 63 #define wmb() __asm __volatile("sync" : : : "memory") 64 #define __ATOMIC_REL() __asm __volatile("sync" : : : "memory") 65 #define __ATOMIC_ACQ() __asm __volatile("isync" : : : "memory") 66 #endif 67 68 static __inline void 69 powerpc_lwsync(void) 70 { 71 72 #ifdef __powerpc64__ 73 __asm __volatile("lwsync" : : : "memory"); 74 #else 75 __asm __volatile("sync" : : : "memory"); 76 #endif 77 } 78 79 /* 80 * atomic_add(p, v) 81 * { *p += v; } 82 */ 83 84 #define __atomic_add_int(p, v, t) \ 85 __asm __volatile( \ 86 "1: lwarx %0, 0, %2\n" \ 87 " add %0, %3, %0\n" \ 88 " stwcx. %0, 0, %2\n" \ 89 " bne- 1b\n" \ 90 : "=&r" (t), "=m" (*p) \ 91 : "r" (p), "r" (v), "m" (*p) \ 92 : "cr0", "memory") \ 93 /* __atomic_add_int */ 94 95 #ifdef __powerpc64__ 96 #define __atomic_add_long(p, v, t) \ 97 __asm __volatile( \ 98 "1: ldarx %0, 0, %2\n" \ 99 " add %0, %3, %0\n" \ 100 " stdcx. %0, 0, %2\n" \ 101 " bne- 1b\n" \ 102 : "=&r" (t), "=m" (*p) \ 103 : "r" (p), "r" (v), "m" (*p) \ 104 : "cr0", "memory") \ 105 /* __atomic_add_long */ 106 #else 107 #define __atomic_add_long(p, v, t) \ 108 __asm __volatile( \ 109 "1: lwarx %0, 0, %2\n" \ 110 " add %0, %3, %0\n" \ 111 " stwcx. %0, 0, %2\n" \ 112 " bne- 1b\n" \ 113 : "=&r" (t), "=m" (*p) \ 114 : "r" (p), "r" (v), "m" (*p) \ 115 : "cr0", "memory") \ 116 /* __atomic_add_long */ 117 #endif 118 119 #define _ATOMIC_ADD(type) \ 120 static __inline void \ 121 atomic_add_##type(volatile u_##type *p, u_##type v) { \ 122 u_##type t; \ 123 __atomic_add_##type(p, v, t); \ 124 } \ 125 \ 126 static __inline void \ 127 atomic_add_acq_##type(volatile u_##type *p, u_##type v) { \ 128 u_##type t; \ 129 __atomic_add_##type(p, v, t); \ 130 __ATOMIC_ACQ(); \ 131 } \ 132 \ 133 static __inline void \ 134 atomic_add_rel_##type(volatile u_##type *p, u_##type v) { \ 135 u_##type t; \ 136 __ATOMIC_REL(); \ 137 __atomic_add_##type(p, v, t); \ 138 } \ 139 /* _ATOMIC_ADD */ 140 141 _ATOMIC_ADD(int) 142 _ATOMIC_ADD(long) 143 144 #define atomic_add_32 atomic_add_int 145 #define atomic_add_acq_32 atomic_add_acq_int 146 #define atomic_add_rel_32 atomic_add_rel_int 147 148 #ifdef __powerpc64__ 149 #define atomic_add_64 atomic_add_long 150 #define atomic_add_acq_64 atomic_add_acq_long 151 #define atomic_add_rel_64 atomic_add_rel_long 152 153 #define atomic_add_ptr atomic_add_long 154 #define atomic_add_acq_ptr atomic_add_acq_long 155 #define atomic_add_rel_ptr atomic_add_rel_long 156 #else 157 #define atomic_add_ptr atomic_add_int 158 #define atomic_add_acq_ptr atomic_add_acq_int 159 #define atomic_add_rel_ptr atomic_add_rel_int 160 #endif 161 #undef _ATOMIC_ADD 162 #undef __atomic_add_long 163 #undef __atomic_add_int 164 165 /* 166 * atomic_clear(p, v) 167 * { *p &= ~v; } 168 */ 169 170 #define __atomic_clear_int(p, v, t) \ 171 __asm __volatile( \ 172 "1: lwarx %0, 0, %2\n" \ 173 " andc %0, %0, %3\n" \ 174 " stwcx. %0, 0, %2\n" \ 175 " bne- 1b\n" \ 176 : "=&r" (t), "=m" (*p) \ 177 : "r" (p), "r" (v), "m" (*p) \ 178 : "cr0", "memory") \ 179 /* __atomic_clear_int */ 180 181 #ifdef __powerpc64__ 182 #define __atomic_clear_long(p, v, t) \ 183 __asm __volatile( \ 184 "1: ldarx %0, 0, %2\n" \ 185 " andc %0, %0, %3\n" \ 186 " stdcx. %0, 0, %2\n" \ 187 " bne- 1b\n" \ 188 : "=&r" (t), "=m" (*p) \ 189 : "r" (p), "r" (v), "m" (*p) \ 190 : "cr0", "memory") \ 191 /* __atomic_clear_long */ 192 #else 193 #define __atomic_clear_long(p, v, t) \ 194 __asm __volatile( \ 195 "1: lwarx %0, 0, %2\n" \ 196 " andc %0, %0, %3\n" \ 197 " stwcx. %0, 0, %2\n" \ 198 " bne- 1b\n" \ 199 : "=&r" (t), "=m" (*p) \ 200 : "r" (p), "r" (v), "m" (*p) \ 201 : "cr0", "memory") \ 202 /* __atomic_clear_long */ 203 #endif 204 205 #define _ATOMIC_CLEAR(type) \ 206 static __inline void \ 207 atomic_clear_##type(volatile u_##type *p, u_##type v) { \ 208 u_##type t; \ 209 __atomic_clear_##type(p, v, t); \ 210 } \ 211 \ 212 static __inline void \ 213 atomic_clear_acq_##type(volatile u_##type *p, u_##type v) { \ 214 u_##type t; \ 215 __atomic_clear_##type(p, v, t); \ 216 __ATOMIC_ACQ(); \ 217 } \ 218 \ 219 static __inline void \ 220 atomic_clear_rel_##type(volatile u_##type *p, u_##type v) { \ 221 u_##type t; \ 222 __ATOMIC_REL(); \ 223 __atomic_clear_##type(p, v, t); \ 224 } \ 225 /* _ATOMIC_CLEAR */ 226 227 _ATOMIC_CLEAR(int) 228 _ATOMIC_CLEAR(long) 229 230 #define atomic_clear_32 atomic_clear_int 231 #define atomic_clear_acq_32 atomic_clear_acq_int 232 #define atomic_clear_rel_32 atomic_clear_rel_int 233 234 #ifdef __powerpc64__ 235 #define atomic_clear_64 atomic_clear_long 236 #define atomic_clear_acq_64 atomic_clear_acq_long 237 #define atomic_clear_rel_64 atomic_clear_rel_long 238 239 #define atomic_clear_ptr atomic_clear_long 240 #define atomic_clear_acq_ptr atomic_clear_acq_long 241 #define atomic_clear_rel_ptr atomic_clear_rel_long 242 #else 243 #define atomic_clear_ptr atomic_clear_int 244 #define atomic_clear_acq_ptr atomic_clear_acq_int 245 #define atomic_clear_rel_ptr atomic_clear_rel_int 246 #endif 247 #undef _ATOMIC_CLEAR 248 #undef __atomic_clear_long 249 #undef __atomic_clear_int 250 251 /* 252 * atomic_cmpset(p, o, n) 253 */ 254 /* TODO -- see below */ 255 256 /* 257 * atomic_load_acq(p) 258 */ 259 /* TODO -- see below */ 260 261 /* 262 * atomic_readandclear(p) 263 */ 264 /* TODO -- see below */ 265 266 /* 267 * atomic_set(p, v) 268 * { *p |= v; } 269 */ 270 271 #define __atomic_set_int(p, v, t) \ 272 __asm __volatile( \ 273 "1: lwarx %0, 0, %2\n" \ 274 " or %0, %3, %0\n" \ 275 " stwcx. %0, 0, %2\n" \ 276 " bne- 1b\n" \ 277 : "=&r" (t), "=m" (*p) \ 278 : "r" (p), "r" (v), "m" (*p) \ 279 : "cr0", "memory") \ 280 /* __atomic_set_int */ 281 282 #ifdef __powerpc64__ 283 #define __atomic_set_long(p, v, t) \ 284 __asm __volatile( \ 285 "1: ldarx %0, 0, %2\n" \ 286 " or %0, %3, %0\n" \ 287 " stdcx. %0, 0, %2\n" \ 288 " bne- 1b\n" \ 289 : "=&r" (t), "=m" (*p) \ 290 : "r" (p), "r" (v), "m" (*p) \ 291 : "cr0", "memory") \ 292 /* __atomic_set_long */ 293 #else 294 #define __atomic_set_long(p, v, t) \ 295 __asm __volatile( \ 296 "1: lwarx %0, 0, %2\n" \ 297 " or %0, %3, %0\n" \ 298 " stwcx. %0, 0, %2\n" \ 299 " bne- 1b\n" \ 300 : "=&r" (t), "=m" (*p) \ 301 : "r" (p), "r" (v), "m" (*p) \ 302 : "cr0", "memory") \ 303 /* __atomic_set_long */ 304 #endif 305 306 #define _ATOMIC_SET(type) \ 307 static __inline void \ 308 atomic_set_##type(volatile u_##type *p, u_##type v) { \ 309 u_##type t; \ 310 __atomic_set_##type(p, v, t); \ 311 } \ 312 \ 313 static __inline void \ 314 atomic_set_acq_##type(volatile u_##type *p, u_##type v) { \ 315 u_##type t; \ 316 __atomic_set_##type(p, v, t); \ 317 __ATOMIC_ACQ(); \ 318 } \ 319 \ 320 static __inline void \ 321 atomic_set_rel_##type(volatile u_##type *p, u_##type v) { \ 322 u_##type t; \ 323 __ATOMIC_REL(); \ 324 __atomic_set_##type(p, v, t); \ 325 } \ 326 /* _ATOMIC_SET */ 327 328 _ATOMIC_SET(int) 329 _ATOMIC_SET(long) 330 331 #define atomic_set_32 atomic_set_int 332 #define atomic_set_acq_32 atomic_set_acq_int 333 #define atomic_set_rel_32 atomic_set_rel_int 334 335 #ifdef __powerpc64__ 336 #define atomic_set_64 atomic_set_long 337 #define atomic_set_acq_64 atomic_set_acq_long 338 #define atomic_set_rel_64 atomic_set_rel_long 339 340 #define atomic_set_ptr atomic_set_long 341 #define atomic_set_acq_ptr atomic_set_acq_long 342 #define atomic_set_rel_ptr atomic_set_rel_long 343 #else 344 #define atomic_set_ptr atomic_set_int 345 #define atomic_set_acq_ptr atomic_set_acq_int 346 #define atomic_set_rel_ptr atomic_set_rel_int 347 #endif 348 #undef _ATOMIC_SET 349 #undef __atomic_set_long 350 #undef __atomic_set_int 351 352 /* 353 * atomic_subtract(p, v) 354 * { *p -= v; } 355 */ 356 357 #define __atomic_subtract_int(p, v, t) \ 358 __asm __volatile( \ 359 "1: lwarx %0, 0, %2\n" \ 360 " subf %0, %3, %0\n" \ 361 " stwcx. %0, 0, %2\n" \ 362 " bne- 1b\n" \ 363 : "=&r" (t), "=m" (*p) \ 364 : "r" (p), "r" (v), "m" (*p) \ 365 : "cr0", "memory") \ 366 /* __atomic_subtract_int */ 367 368 #ifdef __powerpc64__ 369 #define __atomic_subtract_long(p, v, t) \ 370 __asm __volatile( \ 371 "1: ldarx %0, 0, %2\n" \ 372 " subf %0, %3, %0\n" \ 373 " stdcx. %0, 0, %2\n" \ 374 " bne- 1b\n" \ 375 : "=&r" (t), "=m" (*p) \ 376 : "r" (p), "r" (v), "m" (*p) \ 377 : "cr0", "memory") \ 378 /* __atomic_subtract_long */ 379 #else 380 #define __atomic_subtract_long(p, v, t) \ 381 __asm __volatile( \ 382 "1: lwarx %0, 0, %2\n" \ 383 " subf %0, %3, %0\n" \ 384 " stwcx. %0, 0, %2\n" \ 385 " bne- 1b\n" \ 386 : "=&r" (t), "=m" (*p) \ 387 : "r" (p), "r" (v), "m" (*p) \ 388 : "cr0", "memory") \ 389 /* __atomic_subtract_long */ 390 #endif 391 392 #define _ATOMIC_SUBTRACT(type) \ 393 static __inline void \ 394 atomic_subtract_##type(volatile u_##type *p, u_##type v) { \ 395 u_##type t; \ 396 __atomic_subtract_##type(p, v, t); \ 397 } \ 398 \ 399 static __inline void \ 400 atomic_subtract_acq_##type(volatile u_##type *p, u_##type v) { \ 401 u_##type t; \ 402 __atomic_subtract_##type(p, v, t); \ 403 __ATOMIC_ACQ(); \ 404 } \ 405 \ 406 static __inline void \ 407 atomic_subtract_rel_##type(volatile u_##type *p, u_##type v) { \ 408 u_##type t; \ 409 __ATOMIC_REL(); \ 410 __atomic_subtract_##type(p, v, t); \ 411 } \ 412 /* _ATOMIC_SUBTRACT */ 413 414 _ATOMIC_SUBTRACT(int) 415 _ATOMIC_SUBTRACT(long) 416 417 #define atomic_subtract_32 atomic_subtract_int 418 #define atomic_subtract_acq_32 atomic_subtract_acq_int 419 #define atomic_subtract_rel_32 atomic_subtract_rel_int 420 421 #ifdef __powerpc64__ 422 #define atomic_subtract_64 atomic_subtract_long 423 #define atomic_subtract_acq_64 atomic_subract_acq_long 424 #define atomic_subtract_rel_64 atomic_subtract_rel_long 425 426 #define atomic_subtract_ptr atomic_subtract_long 427 #define atomic_subtract_acq_ptr atomic_subtract_acq_long 428 #define atomic_subtract_rel_ptr atomic_subtract_rel_long 429 #else 430 #define atomic_subtract_ptr atomic_subtract_int 431 #define atomic_subtract_acq_ptr atomic_subtract_acq_int 432 #define atomic_subtract_rel_ptr atomic_subtract_rel_int 433 #endif 434 #undef _ATOMIC_SUBTRACT 435 #undef __atomic_subtract_long 436 #undef __atomic_subtract_int 437 438 /* 439 * atomic_store_rel(p, v) 440 */ 441 /* TODO -- see below */ 442 443 /* 444 * Old/original implementations that still need revisiting. 445 */ 446 447 static __inline u_int 448 atomic_readandclear_int(volatile u_int *addr) 449 { 450 u_int result,temp; 451 452 __asm __volatile ( 453 "\tsync\n" /* drain writes */ 454 "1:\tlwarx %0, 0, %3\n\t" /* load old value */ 455 "li %1, 0\n\t" /* load new value */ 456 "stwcx. %1, 0, %3\n\t" /* attempt to store */ 457 "bne- 1b\n\t" /* spin if failed */ 458 : "=&r"(result), "=&r"(temp), "=m" (*addr) 459 : "r" (addr), "m" (*addr) 460 : "cr0", "memory"); 461 462 return (result); 463 } 464 465 #ifdef __powerpc64__ 466 static __inline u_long 467 atomic_readandclear_long(volatile u_long *addr) 468 { 469 u_long result,temp; 470 471 __asm __volatile ( 472 "\tsync\n" /* drain writes */ 473 "1:\tldarx %0, 0, %3\n\t" /* load old value */ 474 "li %1, 0\n\t" /* load new value */ 475 "stdcx. %1, 0, %3\n\t" /* attempt to store */ 476 "bne- 1b\n\t" /* spin if failed */ 477 : "=&r"(result), "=&r"(temp), "=m" (*addr) 478 : "r" (addr), "m" (*addr) 479 : "cr0", "memory"); 480 481 return (result); 482 } 483 #endif 484 485 #define atomic_readandclear_32 atomic_readandclear_int 486 487 #ifdef __powerpc64__ 488 #define atomic_readandclear_64 atomic_readandclear_long 489 490 #define atomic_readandclear_ptr atomic_readandclear_long 491 #else 492 static __inline u_long 493 atomic_readandclear_long(volatile u_long *addr) 494 { 495 496 return ((u_long)atomic_readandclear_int((volatile u_int *)addr)); 497 } 498 499 #define atomic_readandclear_ptr atomic_readandclear_int 500 #endif 501 502 /* 503 * We assume that a = b will do atomic loads and stores. 504 */ 505 #define ATOMIC_STORE_LOAD(TYPE) \ 506 static __inline u_##TYPE \ 507 atomic_load_acq_##TYPE(volatile u_##TYPE *p) \ 508 { \ 509 u_##TYPE v; \ 510 \ 511 v = *p; \ 512 powerpc_lwsync(); \ 513 return (v); \ 514 } \ 515 \ 516 static __inline void \ 517 atomic_store_rel_##TYPE(volatile u_##TYPE *p, u_##TYPE v) \ 518 { \ 519 \ 520 powerpc_lwsync(); \ 521 *p = v; \ 522 } 523 524 ATOMIC_STORE_LOAD(int) 525 526 #define atomic_load_acq_32 atomic_load_acq_int 527 #define atomic_store_rel_32 atomic_store_rel_int 528 529 #ifdef __powerpc64__ 530 ATOMIC_STORE_LOAD(long) 531 532 #define atomic_load_acq_64 atomic_load_acq_long 533 #define atomic_store_rel_64 atomic_store_rel_long 534 535 #define atomic_load_acq_ptr atomic_load_acq_long 536 #define atomic_store_rel_ptr atomic_store_rel_long 537 #else 538 static __inline u_long 539 atomic_load_acq_long(volatile u_long *addr) 540 { 541 542 return ((u_long)atomic_load_acq_int((volatile u_int *)addr)); 543 } 544 545 static __inline void 546 atomic_store_rel_long(volatile u_long *addr, u_long val) 547 { 548 549 atomic_store_rel_int((volatile u_int *)addr, (u_int)val); 550 } 551 552 #define atomic_load_acq_ptr atomic_load_acq_int 553 #define atomic_store_rel_ptr atomic_store_rel_int 554 #endif 555 #undef ATOMIC_STORE_LOAD 556 557 /* 558 * Atomically compare the value stored at *p with cmpval and if the 559 * two values are equal, update the value of *p with newval. Returns 560 * zero if the compare failed, nonzero otherwise. 561 */ 562 #ifdef ISA_206_ATOMICS 563 static __inline int 564 atomic_cmpset_char(volatile u_char *p, u_char cmpval, u_char newval) 565 { 566 int ret; 567 568 __asm __volatile ( 569 "1:\tlbarx %0, 0, %2\n\t" /* load old value */ 570 "cmplw %3, %0\n\t" /* compare */ 571 "bne- 2f\n\t" /* exit if not equal */ 572 "stbcx. %4, 0, %2\n\t" /* attempt to store */ 573 "bne- 1b\n\t" /* spin if failed */ 574 "li %0, 1\n\t" /* success - retval = 1 */ 575 "b 3f\n\t" /* we've succeeded */ 576 "2:\n\t" 577 "stbcx. %0, 0, %2\n\t" /* clear reservation (74xx) */ 578 "li %0, 0\n\t" /* failure - retval = 0 */ 579 "3:\n\t" 580 : "=&r" (ret), "=m" (*p) 581 : "r" (p), "r" (cmpval), "r" (newval), "m" (*p) 582 : "cr0", "memory"); 583 584 return (ret); 585 } 586 587 static __inline int 588 atomic_cmpset_short(volatile u_short *p, u_short cmpval, u_short newval) 589 { 590 int ret; 591 592 __asm __volatile ( 593 "1:\tlharx %0, 0, %2\n\t" /* load old value */ 594 "cmplw %3, %0\n\t" /* compare */ 595 "bne- 2f\n\t" /* exit if not equal */ 596 "sthcx. %4, 0, %2\n\t" /* attempt to store */ 597 "bne- 1b\n\t" /* spin if failed */ 598 "li %0, 1\n\t" /* success - retval = 1 */ 599 "b 3f\n\t" /* we've succeeded */ 600 "2:\n\t" 601 "sthcx. %0, 0, %2\n\t" /* clear reservation (74xx) */ 602 "li %0, 0\n\t" /* failure - retval = 0 */ 603 "3:\n\t" 604 : "=&r" (ret), "=m" (*p) 605 : "r" (p), "r" (cmpval), "r" (newval), "m" (*p) 606 : "cr0", "memory"); 607 608 return (ret); 609 } 610 #else 611 static __inline int 612 atomic_cmpset_masked(uint32_t *p, uint32_t cmpval, uint32_t newval, 613 uint32_t mask) 614 { 615 int ret; 616 uint32_t tmp; 617 618 __asm __volatile ( 619 "1:\tlwarx %2, 0, %3\n\t" /* load old value */ 620 "and %0, %2, %7\n\t" 621 "cmplw %4, %0\n\t" /* compare */ 622 "bne- 2f\n\t" /* exit if not equal */ 623 "andc %2, %2, %7\n\t" 624 "or %2, %2, %5\n\t" 625 "stwcx. %2, 0, %3\n\t" /* attempt to store */ 626 "bne- 1b\n\t" /* spin if failed */ 627 "li %0, 1\n\t" /* success - retval = 1 */ 628 "b 3f\n\t" /* we've succeeded */ 629 "2:\n\t" 630 "stwcx. %2, 0, %3\n\t" /* clear reservation (74xx) */ 631 "li %0, 0\n\t" /* failure - retval = 0 */ 632 "3:\n\t" 633 : "=&r" (ret), "=m" (*p), "+&r" (tmp) 634 : "r" (p), "r" (cmpval), "r" (newval), "m" (*p), 635 "r" (mask) 636 : "cr0", "memory"); 637 638 return (ret); 639 } 640 641 #define _atomic_cmpset_masked_word(a,o,v,m) atomic_cmpset_masked(a, o, v, m) 642 #endif 643 644 static __inline int 645 atomic_cmpset_int(volatile u_int* p, u_int cmpval, u_int newval) 646 { 647 int ret; 648 649 __asm __volatile ( 650 "1:\tlwarx %0, 0, %2\n\t" /* load old value */ 651 "cmplw %3, %0\n\t" /* compare */ 652 "bne- 2f\n\t" /* exit if not equal */ 653 "stwcx. %4, 0, %2\n\t" /* attempt to store */ 654 "bne- 1b\n\t" /* spin if failed */ 655 "li %0, 1\n\t" /* success - retval = 1 */ 656 "b 3f\n\t" /* we've succeeded */ 657 "2:\n\t" 658 "stwcx. %0, 0, %2\n\t" /* clear reservation (74xx) */ 659 "li %0, 0\n\t" /* failure - retval = 0 */ 660 "3:\n\t" 661 : "=&r" (ret), "=m" (*p) 662 : "r" (p), "r" (cmpval), "r" (newval), "m" (*p) 663 : "cr0", "memory"); 664 665 return (ret); 666 } 667 static __inline int 668 atomic_cmpset_long(volatile u_long* p, u_long cmpval, u_long newval) 669 { 670 int ret; 671 672 __asm __volatile ( 673 #ifdef __powerpc64__ 674 "1:\tldarx %0, 0, %2\n\t" /* load old value */ 675 "cmpld %3, %0\n\t" /* compare */ 676 "bne- 2f\n\t" /* exit if not equal */ 677 "stdcx. %4, 0, %2\n\t" /* attempt to store */ 678 #else 679 "1:\tlwarx %0, 0, %2\n\t" /* load old value */ 680 "cmplw %3, %0\n\t" /* compare */ 681 "bne- 2f\n\t" /* exit if not equal */ 682 "stwcx. %4, 0, %2\n\t" /* attempt to store */ 683 #endif 684 "bne- 1b\n\t" /* spin if failed */ 685 "li %0, 1\n\t" /* success - retval = 1 */ 686 "b 3f\n\t" /* we've succeeded */ 687 "2:\n\t" 688 #ifdef __powerpc64__ 689 "stdcx. %0, 0, %2\n\t" /* clear reservation (74xx) */ 690 #else 691 "stwcx. %0, 0, %2\n\t" /* clear reservation (74xx) */ 692 #endif 693 "li %0, 0\n\t" /* failure - retval = 0 */ 694 "3:\n\t" 695 : "=&r" (ret), "=m" (*p) 696 : "r" (p), "r" (cmpval), "r" (newval), "m" (*p) 697 : "cr0", "memory"); 698 699 return (ret); 700 } 701 702 #define ATOMIC_CMPSET_ACQ_REL(type) \ 703 static __inline int \ 704 atomic_cmpset_acq_##type(volatile u_##type *p, \ 705 u_##type cmpval, u_##type newval)\ 706 {\ 707 u_##type retval; \ 708 retval = atomic_cmpset_##type(p, cmpval, newval);\ 709 __ATOMIC_ACQ();\ 710 return (retval);\ 711 }\ 712 static __inline int \ 713 atomic_cmpset_rel_##type(volatile u_##type *p, \ 714 u_##type cmpval, u_##type newval)\ 715 {\ 716 __ATOMIC_REL();\ 717 return (atomic_cmpset_##type(p, cmpval, newval));\ 718 }\ 719 struct hack 720 721 ATOMIC_CMPSET_ACQ_REL(int); 722 ATOMIC_CMPSET_ACQ_REL(long); 723 724 #ifdef ISA_206_ATOMICS 725 #define atomic_cmpset_8 atomic_cmpset_char 726 #endif 727 #define atomic_cmpset_acq_8 atomic_cmpset_acq_char 728 #define atomic_cmpset_rel_8 atomic_cmpset_rel_char 729 730 #ifdef ISA_206_ATOMICS 731 #define atomic_cmpset_16 atomic_cmpset_short 732 #endif 733 #define atomic_cmpset_acq_16 atomic_cmpset_acq_short 734 #define atomic_cmpset_rel_16 atomic_cmpset_rel_short 735 736 #define atomic_cmpset_32 atomic_cmpset_int 737 #define atomic_cmpset_acq_32 atomic_cmpset_acq_int 738 #define atomic_cmpset_rel_32 atomic_cmpset_rel_int 739 740 #ifdef __powerpc64__ 741 #define atomic_cmpset_64 atomic_cmpset_long 742 #define atomic_cmpset_acq_64 atomic_cmpset_acq_long 743 #define atomic_cmpset_rel_64 atomic_cmpset_rel_long 744 745 #define atomic_cmpset_ptr atomic_cmpset_long 746 #define atomic_cmpset_acq_ptr atomic_cmpset_acq_long 747 #define atomic_cmpset_rel_ptr atomic_cmpset_rel_long 748 #else 749 #define atomic_cmpset_ptr atomic_cmpset_int 750 #define atomic_cmpset_acq_ptr atomic_cmpset_acq_int 751 #define atomic_cmpset_rel_ptr atomic_cmpset_rel_int 752 #endif 753 754 /* 755 * Atomically compare the value stored at *p with *cmpval and if the 756 * two values are equal, update the value of *p with newval. Returns 757 * zero if the compare failed and sets *cmpval to the read value from *p, 758 * nonzero otherwise. 759 */ 760 #ifdef ISA_206_ATOMICS 761 static __inline int 762 atomic_fcmpset_char(volatile u_char *p, u_char *cmpval, u_char newval) 763 { 764 int ret; 765 766 __asm __volatile ( 767 "lbarx %0, 0, %3\n\t" /* load old value */ 768 "cmplw %4, %0\n\t" /* compare */ 769 "bne- 1f\n\t" /* exit if not equal */ 770 "stbcx. %5, 0, %3\n\t" /* attempt to store */ 771 "bne- 1f\n\t" /* exit if failed */ 772 "li %0, 1\n\t" /* success - retval = 1 */ 773 "b 2f\n\t" /* we've succeeded */ 774 "1:\n\t" 775 "stbcx. %0, 0, %3\n\t" /* clear reservation (74xx) */ 776 "stbx %0, 0, %7\n\t" 777 "li %0, 0\n\t" /* failure - retval = 0 */ 778 "2:\n\t" 779 : "=&r" (ret), "=m" (*p), "=m" (*cmpval) 780 : "r" (p), "r" (*cmpval), "r" (newval), "m" (*p), "r"(cmpval) 781 : "cr0", "memory"); 782 783 return (ret); 784 } 785 786 static __inline int 787 atomic_fcmpset_short(volatile u_short *p, u_short *cmpval, u_short newval) 788 { 789 int ret; 790 791 __asm __volatile ( 792 "lharx %0, 0, %3\n\t" /* load old value */ 793 "cmplw %4, %0\n\t" /* compare */ 794 "bne- 1f\n\t" /* exit if not equal */ 795 "sthcx. %5, 0, %3\n\t" /* attempt to store */ 796 "bne- 1f\n\t" /* exit if failed */ 797 "li %0, 1\n\t" /* success - retval = 1 */ 798 "b 2f\n\t" /* we've succeeded */ 799 "1:\n\t" 800 "sthcx. %0, 0, %3\n\t" /* clear reservation (74xx) */ 801 "sthx %0, 0, %7\n\t" 802 "li %0, 0\n\t" /* failure - retval = 0 */ 803 "2:\n\t" 804 : "=&r" (ret), "=m" (*p), "=m" (*cmpval) 805 : "r" (p), "r" (*cmpval), "r" (newval), "m" (*p), "r"(cmpval) 806 : "cr0", "memory"); 807 808 return (ret); 809 } 810 #endif /* ISA_206_ATOMICS */ 811 812 static __inline int 813 atomic_fcmpset_int(volatile u_int *p, u_int *cmpval, u_int newval) 814 { 815 int ret; 816 817 __asm __volatile ( 818 "lwarx %0, 0, %3\n\t" /* load old value */ 819 "cmplw %4, %0\n\t" /* compare */ 820 "bne- 1f\n\t" /* exit if not equal */ 821 "stwcx. %5, 0, %3\n\t" /* attempt to store */ 822 "bne- 1f\n\t" /* exit if failed */ 823 "li %0, 1\n\t" /* success - retval = 1 */ 824 "b 2f\n\t" /* we've succeeded */ 825 "1:\n\t" 826 "stwcx. %0, 0, %3\n\t" /* clear reservation (74xx) */ 827 "stwx %0, 0, %7\n\t" 828 "li %0, 0\n\t" /* failure - retval = 0 */ 829 "2:\n\t" 830 : "=&r" (ret), "=m" (*p), "=m" (*cmpval) 831 : "r" (p), "r" (*cmpval), "r" (newval), "m" (*p), "r"(cmpval) 832 : "cr0", "memory"); 833 834 return (ret); 835 } 836 static __inline int 837 atomic_fcmpset_long(volatile u_long *p, u_long *cmpval, u_long newval) 838 { 839 int ret; 840 841 __asm __volatile ( 842 #ifdef __powerpc64__ 843 "ldarx %0, 0, %3\n\t" /* load old value */ 844 "cmpld %4, %0\n\t" /* compare */ 845 "bne- 1f\n\t" /* exit if not equal */ 846 "stdcx. %5, 0, %3\n\t" /* attempt to store */ 847 #else 848 "lwarx %0, 0, %3\n\t" /* load old value */ 849 "cmplw %4, %0\n\t" /* compare */ 850 "bne- 1f\n\t" /* exit if not equal */ 851 "stwcx. %5, 0, %3\n\t" /* attempt to store */ 852 #endif 853 "bne- 1f\n\t" /* exit if failed */ 854 "li %0, 1\n\t" /* success - retval = 1 */ 855 "b 2f\n\t" /* we've succeeded */ 856 "1:\n\t" 857 #ifdef __powerpc64__ 858 "stdcx. %0, 0, %3\n\t" /* clear reservation (74xx) */ 859 "stdx %0, 0, %7\n\t" 860 #else 861 "stwcx. %0, 0, %3\n\t" /* clear reservation (74xx) */ 862 "stwx %0, 0, %7\n\t" 863 #endif 864 "li %0, 0\n\t" /* failure - retval = 0 */ 865 "2:\n\t" 866 : "=&r" (ret), "=m" (*p), "=m" (*cmpval) 867 : "r" (p), "r" (*cmpval), "r" (newval), "m" (*p), "r"(cmpval) 868 : "cr0", "memory"); 869 870 return (ret); 871 } 872 873 #define ATOMIC_FCMPSET_ACQ_REL(type) \ 874 static __inline int \ 875 atomic_fcmpset_acq_##type(volatile u_##type *p, \ 876 u_##type *cmpval, u_##type newval)\ 877 {\ 878 u_##type retval; \ 879 retval = atomic_fcmpset_##type(p, cmpval, newval);\ 880 __ATOMIC_ACQ();\ 881 return (retval);\ 882 }\ 883 static __inline int \ 884 atomic_fcmpset_rel_##type(volatile u_##type *p, \ 885 u_##type *cmpval, u_##type newval)\ 886 {\ 887 __ATOMIC_REL();\ 888 return (atomic_fcmpset_##type(p, cmpval, newval));\ 889 }\ 890 struct hack 891 892 ATOMIC_FCMPSET_ACQ_REL(int); 893 ATOMIC_FCMPSET_ACQ_REL(long); 894 895 #ifdef ISA_206_ATOMICS 896 #define atomic_fcmpset_8 atomic_fcmpset_char 897 #endif 898 #define atomic_fcmpset_acq_8 atomic_fcmpset_acq_char 899 #define atomic_fcmpset_rel_8 atomic_fcmpset_rel_char 900 901 #ifdef ISA_206_ATOMICS 902 #define atomic_fcmpset_16 atomic_fcmpset_short 903 #endif 904 #define atomic_fcmpset_acq_16 atomic_fcmpset_acq_short 905 #define atomic_fcmpset_rel_16 atomic_fcmpset_rel_short 906 907 #define atomic_fcmpset_32 atomic_fcmpset_int 908 #define atomic_fcmpset_acq_32 atomic_fcmpset_acq_int 909 #define atomic_fcmpset_rel_32 atomic_fcmpset_rel_int 910 911 #ifdef __powerpc64__ 912 #define atomic_fcmpset_64 atomic_fcmpset_long 913 #define atomic_fcmpset_acq_64 atomic_fcmpset_acq_long 914 #define atomic_fcmpset_rel_64 atomic_fcmpset_rel_long 915 916 #define atomic_fcmpset_ptr atomic_fcmpset_long 917 #define atomic_fcmpset_acq_ptr atomic_fcmpset_acq_long 918 #define atomic_fcmpset_rel_ptr atomic_fcmpset_rel_long 919 #else 920 #define atomic_fcmpset_ptr atomic_fcmpset_int 921 #define atomic_fcmpset_acq_ptr atomic_fcmpset_acq_int 922 #define atomic_fcmpset_rel_ptr atomic_fcmpset_rel_int 923 #endif 924 925 static __inline u_int 926 atomic_fetchadd_int(volatile u_int *p, u_int v) 927 { 928 u_int value; 929 930 do { 931 value = *p; 932 } while (!atomic_cmpset_int(p, value, value + v)); 933 return (value); 934 } 935 936 static __inline u_long 937 atomic_fetchadd_long(volatile u_long *p, u_long v) 938 { 939 u_long value; 940 941 do { 942 value = *p; 943 } while (!atomic_cmpset_long(p, value, value + v)); 944 return (value); 945 } 946 947 static __inline u_int 948 atomic_swap_32(volatile u_int *p, u_int v) 949 { 950 u_int prev; 951 952 __asm __volatile( 953 "1: lwarx %0,0,%2\n" 954 " stwcx. %3,0,%2\n" 955 " bne- 1b\n" 956 : "=&r" (prev), "+m" (*(volatile u_int *)p) 957 : "r" (p), "r" (v) 958 : "cr0", "memory"); 959 960 return (prev); 961 } 962 963 #ifdef __powerpc64__ 964 static __inline u_long 965 atomic_swap_64(volatile u_long *p, u_long v) 966 { 967 u_long prev; 968 969 __asm __volatile( 970 "1: ldarx %0,0,%2\n" 971 " stdcx. %3,0,%2\n" 972 " bne- 1b\n" 973 : "=&r" (prev), "+m" (*(volatile u_long *)p) 974 : "r" (p), "r" (v) 975 : "cr0", "memory"); 976 977 return (prev); 978 } 979 #endif 980 981 #define atomic_fetchadd_32 atomic_fetchadd_int 982 #define atomic_swap_int atomic_swap_32 983 984 #ifdef __powerpc64__ 985 #define atomic_fetchadd_64 atomic_fetchadd_long 986 #define atomic_swap_long atomic_swap_64 987 #define atomic_swap_ptr atomic_swap_64 988 #else 989 #define atomic_swap_long(p,v) atomic_swap_32((volatile u_int *)(p), v) 990 #define atomic_swap_ptr(p,v) atomic_swap_32((volatile u_int *)(p), v) 991 #endif 992 993 static __inline int 994 atomic_testandset_int(volatile u_int *p, u_int v) 995 { 996 u_int m = (1u << (v & 0x1f)); 997 u_int res; 998 u_int tmp; 999 1000 __asm __volatile( 1001 "1: lwarx %0,0,%3\n" 1002 " and %1,%0,%4\n" 1003 " or %0,%0,%4\n" 1004 " stwcx. %0,0,%3\n" 1005 " bne- 1b\n" 1006 : "=&r"(tmp), "=&r"(res), "+m"(*p) 1007 : "r"(p), "r"(m) 1008 : "cr0", "memory"); 1009 1010 return (res != 0); 1011 } 1012 1013 static __inline int 1014 atomic_testandclear_int(volatile u_int *p, u_int v) 1015 { 1016 u_int m = (1u << (v & 0x1f)); 1017 u_int res; 1018 u_int tmp; 1019 1020 __asm __volatile( 1021 "1: lwarx %0,0,%3\n" 1022 " and %1,%0,%4\n" 1023 " andc %0,%0,%4\n" 1024 " stwcx. %0,0,%3\n" 1025 " bne- 1b\n" 1026 : "=&r"(tmp), "=&r"(res), "+m"(*p) 1027 : "r"(p), "r"(m) 1028 : "cr0", "memory"); 1029 1030 return (res != 0); 1031 } 1032 1033 #ifdef __powerpc64__ 1034 static __inline int 1035 atomic_testandset_long(volatile u_long *p, u_int v) 1036 { 1037 u_long m = (1ul << (v & 0x3f)); 1038 u_long res; 1039 u_long tmp; 1040 1041 __asm __volatile( 1042 "1: ldarx %0,0,%3\n" 1043 " and %1,%0,%4\n" 1044 " or %0,%0,%4\n" 1045 " stdcx. %0,0,%3\n" 1046 " bne- 1b\n" 1047 : "=&r"(tmp), "=&r"(res), "+m"(*(volatile u_long *)p) 1048 : "r"(p), "r"(m) 1049 : "cr0", "memory"); 1050 1051 return (res != 0); 1052 } 1053 1054 static __inline int 1055 atomic_testandclear_long(volatile u_long *p, u_int v) 1056 { 1057 u_long m = (1ul << (v & 0x3f)); 1058 u_long res; 1059 u_long tmp; 1060 1061 __asm __volatile( 1062 "1: ldarx %0,0,%3\n" 1063 " and %1,%0,%4\n" 1064 " andc %0,%0,%4\n" 1065 " stdcx. %0,0,%3\n" 1066 " bne- 1b\n" 1067 : "=&r"(tmp), "=&r"(res), "+m"(*p) 1068 : "r"(p), "r"(m) 1069 : "cr0", "memory"); 1070 1071 return (res != 0); 1072 } 1073 #else 1074 static __inline int 1075 atomic_testandset_long(volatile u_long *p, u_int v) 1076 { 1077 return (atomic_testandset_int((volatile u_int *)p, v)); 1078 } 1079 1080 static __inline int 1081 atomic_testandclear_long(volatile u_long *p, u_int v) 1082 { 1083 return (atomic_testandclear_int((volatile u_int *)p, v)); 1084 } 1085 #endif 1086 1087 #define atomic_testandclear_32 atomic_testandclear_int 1088 #define atomic_testandset_32 atomic_testandset_int 1089 1090 static __inline int 1091 atomic_testandset_acq_long(volatile u_long *p, u_int v) 1092 { 1093 u_int a = atomic_testandset_long(p, v); 1094 __ATOMIC_ACQ(); 1095 return (a); 1096 } 1097 1098 #define atomic_testandclear_int atomic_testandclear_int 1099 #define atomic_testandset_int atomic_testandset_int 1100 #define atomic_testandclear_long atomic_testandclear_long 1101 #define atomic_testandset_long atomic_testandset_long 1102 #define atomic_testandset_acq_long atomic_testandset_acq_long 1103 1104 static __inline void 1105 atomic_thread_fence_acq(void) 1106 { 1107 1108 powerpc_lwsync(); 1109 } 1110 1111 static __inline void 1112 atomic_thread_fence_rel(void) 1113 { 1114 1115 powerpc_lwsync(); 1116 } 1117 1118 static __inline void 1119 atomic_thread_fence_acq_rel(void) 1120 { 1121 1122 powerpc_lwsync(); 1123 } 1124 1125 static __inline void 1126 atomic_thread_fence_seq_cst(void) 1127 { 1128 1129 __asm __volatile("sync" : : : "memory"); 1130 } 1131 1132 #ifndef ISA_206_ATOMICS 1133 #include <sys/_atomic_subword.h> 1134 #define atomic_cmpset_char atomic_cmpset_8 1135 #define atomic_cmpset_short atomic_cmpset_16 1136 #define atomic_fcmpset_char atomic_fcmpset_8 1137 #define atomic_fcmpset_short atomic_fcmpset_16 1138 #endif 1139 1140 /* These need sys/_atomic_subword.h on non-ISA-2.06-atomic platforms. */ 1141 ATOMIC_CMPSET_ACQ_REL(char); 1142 ATOMIC_CMPSET_ACQ_REL(short); 1143 1144 ATOMIC_FCMPSET_ACQ_REL(char); 1145 ATOMIC_FCMPSET_ACQ_REL(short); 1146 1147 #undef __ATOMIC_REL 1148 #undef __ATOMIC_ACQ 1149 1150 #endif /* ! _MACHINE_ATOMIC_H_ */ 1151