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