1 /* 2 * Atomic operations that C can't guarantee us. Useful for 3 * resource counting etc.. 4 * 5 * But use these as seldom as possible since they are much more slower 6 * than regular operations. 7 * 8 * This file is subject to the terms and conditions of the GNU General Public 9 * License. See the file "COPYING" in the main directory of this archive 10 * for more details. 11 * 12 * Copyright (C) 1996, 97, 99, 2000, 03, 04, 06 by Ralf Baechle 13 */ 14 #ifndef _ASM_ATOMIC_H 15 #define _ASM_ATOMIC_H 16 17 #include <linux/irqflags.h> 18 #include <linux/types.h> 19 #include <asm/barrier.h> 20 #include <asm/cpu-features.h> 21 #include <asm/war.h> 22 #include <asm/system.h> 23 24 #define ATOMIC_INIT(i) { (i) } 25 26 /* 27 * atomic_read - read atomic variable 28 * @v: pointer of type atomic_t 29 * 30 * Atomically reads the value of @v. 31 */ 32 #define atomic_read(v) (*(volatile int *)&(v)->counter) 33 34 /* 35 * atomic_set - set atomic variable 36 * @v: pointer of type atomic_t 37 * @i: required value 38 * 39 * Atomically sets the value of @v to @i. 40 */ 41 #define atomic_set(v, i) ((v)->counter = (i)) 42 43 /* 44 * atomic_add - add integer to atomic variable 45 * @i: integer value to add 46 * @v: pointer of type atomic_t 47 * 48 * Atomically adds @i to @v. 49 */ 50 static __inline__ void atomic_add(int i, atomic_t * v) 51 { 52 if (kernel_uses_llsc && R10000_LLSC_WAR) { 53 int temp; 54 55 __asm__ __volatile__( 56 " .set mips3 \n" 57 "1: ll %0, %1 # atomic_add \n" 58 " addu %0, %2 \n" 59 " sc %0, %1 \n" 60 " beqzl %0, 1b \n" 61 " .set mips0 \n" 62 : "=&r" (temp), "=m" (v->counter) 63 : "Ir" (i), "m" (v->counter)); 64 } else if (kernel_uses_llsc) { 65 int temp; 66 67 do { 68 __asm__ __volatile__( 69 " .set mips3 \n" 70 " ll %0, %1 # atomic_add \n" 71 " addu %0, %2 \n" 72 " sc %0, %1 \n" 73 " .set mips0 \n" 74 : "=&r" (temp), "=m" (v->counter) 75 : "Ir" (i), "m" (v->counter)); 76 } while (unlikely(!temp)); 77 } else { 78 unsigned long flags; 79 80 raw_local_irq_save(flags); 81 v->counter += i; 82 raw_local_irq_restore(flags); 83 } 84 } 85 86 /* 87 * atomic_sub - subtract the atomic variable 88 * @i: integer value to subtract 89 * @v: pointer of type atomic_t 90 * 91 * Atomically subtracts @i from @v. 92 */ 93 static __inline__ void atomic_sub(int i, atomic_t * v) 94 { 95 if (kernel_uses_llsc && R10000_LLSC_WAR) { 96 int temp; 97 98 __asm__ __volatile__( 99 " .set mips3 \n" 100 "1: ll %0, %1 # atomic_sub \n" 101 " subu %0, %2 \n" 102 " sc %0, %1 \n" 103 " beqzl %0, 1b \n" 104 " .set mips0 \n" 105 : "=&r" (temp), "=m" (v->counter) 106 : "Ir" (i), "m" (v->counter)); 107 } else if (kernel_uses_llsc) { 108 int temp; 109 110 do { 111 __asm__ __volatile__( 112 " .set mips3 \n" 113 " ll %0, %1 # atomic_sub \n" 114 " subu %0, %2 \n" 115 " sc %0, %1 \n" 116 " .set mips0 \n" 117 : "=&r" (temp), "=m" (v->counter) 118 : "Ir" (i), "m" (v->counter)); 119 } while (unlikely(!temp)); 120 } else { 121 unsigned long flags; 122 123 raw_local_irq_save(flags); 124 v->counter -= i; 125 raw_local_irq_restore(flags); 126 } 127 } 128 129 /* 130 * Same as above, but return the result value 131 */ 132 static __inline__ int atomic_add_return(int i, atomic_t * v) 133 { 134 int result; 135 136 smp_mb__before_llsc(); 137 138 if (kernel_uses_llsc && R10000_LLSC_WAR) { 139 int temp; 140 141 __asm__ __volatile__( 142 " .set mips3 \n" 143 "1: ll %1, %2 # atomic_add_return \n" 144 " addu %0, %1, %3 \n" 145 " sc %0, %2 \n" 146 " beqzl %0, 1b \n" 147 " addu %0, %1, %3 \n" 148 " .set mips0 \n" 149 : "=&r" (result), "=&r" (temp), "=m" (v->counter) 150 : "Ir" (i), "m" (v->counter) 151 : "memory"); 152 } else if (kernel_uses_llsc) { 153 int temp; 154 155 do { 156 __asm__ __volatile__( 157 " .set mips3 \n" 158 " ll %1, %2 # atomic_add_return \n" 159 " addu %0, %1, %3 \n" 160 " sc %0, %2 \n" 161 " .set mips0 \n" 162 : "=&r" (result), "=&r" (temp), "=m" (v->counter) 163 : "Ir" (i), "m" (v->counter) 164 : "memory"); 165 } while (unlikely(!result)); 166 167 result = temp + i; 168 } else { 169 unsigned long flags; 170 171 raw_local_irq_save(flags); 172 result = v->counter; 173 result += i; 174 v->counter = result; 175 raw_local_irq_restore(flags); 176 } 177 178 smp_llsc_mb(); 179 180 return result; 181 } 182 183 static __inline__ int atomic_sub_return(int i, atomic_t * v) 184 { 185 int result; 186 187 smp_mb__before_llsc(); 188 189 if (kernel_uses_llsc && R10000_LLSC_WAR) { 190 int temp; 191 192 __asm__ __volatile__( 193 " .set mips3 \n" 194 "1: ll %1, %2 # atomic_sub_return \n" 195 " subu %0, %1, %3 \n" 196 " sc %0, %2 \n" 197 " beqzl %0, 1b \n" 198 " subu %0, %1, %3 \n" 199 " .set mips0 \n" 200 : "=&r" (result), "=&r" (temp), "=m" (v->counter) 201 : "Ir" (i), "m" (v->counter) 202 : "memory"); 203 204 result = temp - i; 205 } else if (kernel_uses_llsc) { 206 int temp; 207 208 do { 209 __asm__ __volatile__( 210 " .set mips3 \n" 211 " ll %1, %2 # atomic_sub_return \n" 212 " subu %0, %1, %3 \n" 213 " sc %0, %2 \n" 214 " .set mips0 \n" 215 : "=&r" (result), "=&r" (temp), "=m" (v->counter) 216 : "Ir" (i), "m" (v->counter) 217 : "memory"); 218 } while (unlikely(!result)); 219 220 result = temp - i; 221 } else { 222 unsigned long flags; 223 224 raw_local_irq_save(flags); 225 result = v->counter; 226 result -= i; 227 v->counter = result; 228 raw_local_irq_restore(flags); 229 } 230 231 smp_llsc_mb(); 232 233 return result; 234 } 235 236 /* 237 * atomic_sub_if_positive - conditionally subtract integer from atomic variable 238 * @i: integer value to subtract 239 * @v: pointer of type atomic_t 240 * 241 * Atomically test @v and subtract @i if @v is greater or equal than @i. 242 * The function returns the old value of @v minus @i. 243 */ 244 static __inline__ int atomic_sub_if_positive(int i, atomic_t * v) 245 { 246 int result; 247 248 smp_mb__before_llsc(); 249 250 if (kernel_uses_llsc && R10000_LLSC_WAR) { 251 int temp; 252 253 __asm__ __volatile__( 254 " .set mips3 \n" 255 "1: ll %1, %2 # atomic_sub_if_positive\n" 256 " subu %0, %1, %3 \n" 257 " bltz %0, 1f \n" 258 " sc %0, %2 \n" 259 " .set noreorder \n" 260 " beqzl %0, 1b \n" 261 " subu %0, %1, %3 \n" 262 " .set reorder \n" 263 "1: \n" 264 " .set mips0 \n" 265 : "=&r" (result), "=&r" (temp), "=m" (v->counter) 266 : "Ir" (i), "m" (v->counter) 267 : "memory"); 268 } else if (kernel_uses_llsc) { 269 int temp; 270 271 __asm__ __volatile__( 272 " .set mips3 \n" 273 "1: ll %1, %2 # atomic_sub_if_positive\n" 274 " subu %0, %1, %3 \n" 275 " bltz %0, 1f \n" 276 " sc %0, %2 \n" 277 " .set noreorder \n" 278 " beqz %0, 1b \n" 279 " subu %0, %1, %3 \n" 280 " .set reorder \n" 281 "1: \n" 282 " .set mips0 \n" 283 : "=&r" (result), "=&r" (temp), "=m" (v->counter) 284 : "Ir" (i), "m" (v->counter) 285 : "memory"); 286 } else { 287 unsigned long flags; 288 289 raw_local_irq_save(flags); 290 result = v->counter; 291 result -= i; 292 if (result >= 0) 293 v->counter = result; 294 raw_local_irq_restore(flags); 295 } 296 297 smp_llsc_mb(); 298 299 return result; 300 } 301 302 #define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n))) 303 #define atomic_xchg(v, new) (xchg(&((v)->counter), (new))) 304 305 /** 306 * atomic_add_unless - add unless the number is a given value 307 * @v: pointer of type atomic_t 308 * @a: the amount to add to v... 309 * @u: ...unless v is equal to u. 310 * 311 * Atomically adds @a to @v, so long as it was not @u. 312 * Returns non-zero if @v was not @u, and zero otherwise. 313 */ 314 static __inline__ int atomic_add_unless(atomic_t *v, int a, int u) 315 { 316 int c, old; 317 c = atomic_read(v); 318 for (;;) { 319 if (unlikely(c == (u))) 320 break; 321 old = atomic_cmpxchg((v), c, c + (a)); 322 if (likely(old == c)) 323 break; 324 c = old; 325 } 326 return c != (u); 327 } 328 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) 329 330 #define atomic_dec_return(v) atomic_sub_return(1, (v)) 331 #define atomic_inc_return(v) atomic_add_return(1, (v)) 332 333 /* 334 * atomic_sub_and_test - subtract value from variable and test result 335 * @i: integer value to subtract 336 * @v: pointer of type atomic_t 337 * 338 * Atomically subtracts @i from @v and returns 339 * true if the result is zero, or false for all 340 * other cases. 341 */ 342 #define atomic_sub_and_test(i, v) (atomic_sub_return((i), (v)) == 0) 343 344 /* 345 * atomic_inc_and_test - increment and test 346 * @v: pointer of type atomic_t 347 * 348 * Atomically increments @v by 1 349 * and returns true if the result is zero, or false for all 350 * other cases. 351 */ 352 #define atomic_inc_and_test(v) (atomic_inc_return(v) == 0) 353 354 /* 355 * atomic_dec_and_test - decrement by 1 and test 356 * @v: pointer of type atomic_t 357 * 358 * Atomically decrements @v by 1 and 359 * returns true if the result is 0, or false for all other 360 * cases. 361 */ 362 #define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0) 363 364 /* 365 * atomic_dec_if_positive - decrement by 1 if old value positive 366 * @v: pointer of type atomic_t 367 */ 368 #define atomic_dec_if_positive(v) atomic_sub_if_positive(1, v) 369 370 /* 371 * atomic_inc - increment atomic variable 372 * @v: pointer of type atomic_t 373 * 374 * Atomically increments @v by 1. 375 */ 376 #define atomic_inc(v) atomic_add(1, (v)) 377 378 /* 379 * atomic_dec - decrement and test 380 * @v: pointer of type atomic_t 381 * 382 * Atomically decrements @v by 1. 383 */ 384 #define atomic_dec(v) atomic_sub(1, (v)) 385 386 /* 387 * atomic_add_negative - add and test if negative 388 * @v: pointer of type atomic_t 389 * @i: integer value to add 390 * 391 * Atomically adds @i to @v and returns true 392 * if the result is negative, or false when 393 * result is greater than or equal to zero. 394 */ 395 #define atomic_add_negative(i, v) (atomic_add_return(i, (v)) < 0) 396 397 #ifdef CONFIG_64BIT 398 399 #define ATOMIC64_INIT(i) { (i) } 400 401 /* 402 * atomic64_read - read atomic variable 403 * @v: pointer of type atomic64_t 404 * 405 */ 406 #define atomic64_read(v) (*(volatile long *)&(v)->counter) 407 408 /* 409 * atomic64_set - set atomic variable 410 * @v: pointer of type atomic64_t 411 * @i: required value 412 */ 413 #define atomic64_set(v, i) ((v)->counter = (i)) 414 415 /* 416 * atomic64_add - add integer to atomic variable 417 * @i: integer value to add 418 * @v: pointer of type atomic64_t 419 * 420 * Atomically adds @i to @v. 421 */ 422 static __inline__ void atomic64_add(long i, atomic64_t * v) 423 { 424 if (kernel_uses_llsc && R10000_LLSC_WAR) { 425 long temp; 426 427 __asm__ __volatile__( 428 " .set mips3 \n" 429 "1: lld %0, %1 # atomic64_add \n" 430 " daddu %0, %2 \n" 431 " scd %0, %1 \n" 432 " beqzl %0, 1b \n" 433 " .set mips0 \n" 434 : "=&r" (temp), "=m" (v->counter) 435 : "Ir" (i), "m" (v->counter)); 436 } else if (kernel_uses_llsc) { 437 long temp; 438 439 do { 440 __asm__ __volatile__( 441 " .set mips3 \n" 442 " lld %0, %1 # atomic64_add \n" 443 " daddu %0, %2 \n" 444 " scd %0, %1 \n" 445 " .set mips0 \n" 446 : "=&r" (temp), "=m" (v->counter) 447 : "Ir" (i), "m" (v->counter)); 448 } while (unlikely(!temp)); 449 } else { 450 unsigned long flags; 451 452 raw_local_irq_save(flags); 453 v->counter += i; 454 raw_local_irq_restore(flags); 455 } 456 } 457 458 /* 459 * atomic64_sub - subtract the atomic variable 460 * @i: integer value to subtract 461 * @v: pointer of type atomic64_t 462 * 463 * Atomically subtracts @i from @v. 464 */ 465 static __inline__ void atomic64_sub(long i, atomic64_t * v) 466 { 467 if (kernel_uses_llsc && R10000_LLSC_WAR) { 468 long temp; 469 470 __asm__ __volatile__( 471 " .set mips3 \n" 472 "1: lld %0, %1 # atomic64_sub \n" 473 " dsubu %0, %2 \n" 474 " scd %0, %1 \n" 475 " beqzl %0, 1b \n" 476 " .set mips0 \n" 477 : "=&r" (temp), "=m" (v->counter) 478 : "Ir" (i), "m" (v->counter)); 479 } else if (kernel_uses_llsc) { 480 long temp; 481 482 do { 483 __asm__ __volatile__( 484 " .set mips3 \n" 485 " lld %0, %1 # atomic64_sub \n" 486 " dsubu %0, %2 \n" 487 " scd %0, %1 \n" 488 " .set mips0 \n" 489 : "=&r" (temp), "=m" (v->counter) 490 : "Ir" (i), "m" (v->counter)); 491 } while (unlikely(!temp)); 492 } else { 493 unsigned long flags; 494 495 raw_local_irq_save(flags); 496 v->counter -= i; 497 raw_local_irq_restore(flags); 498 } 499 } 500 501 /* 502 * Same as above, but return the result value 503 */ 504 static __inline__ long atomic64_add_return(long i, atomic64_t * v) 505 { 506 long result; 507 508 smp_mb__before_llsc(); 509 510 if (kernel_uses_llsc && R10000_LLSC_WAR) { 511 long temp; 512 513 __asm__ __volatile__( 514 " .set mips3 \n" 515 "1: lld %1, %2 # atomic64_add_return \n" 516 " daddu %0, %1, %3 \n" 517 " scd %0, %2 \n" 518 " beqzl %0, 1b \n" 519 " daddu %0, %1, %3 \n" 520 " .set mips0 \n" 521 : "=&r" (result), "=&r" (temp), "=m" (v->counter) 522 : "Ir" (i), "m" (v->counter) 523 : "memory"); 524 } else if (kernel_uses_llsc) { 525 long temp; 526 527 do { 528 __asm__ __volatile__( 529 " .set mips3 \n" 530 " lld %1, %2 # atomic64_add_return \n" 531 " daddu %0, %1, %3 \n" 532 " scd %0, %2 \n" 533 " .set mips0 \n" 534 : "=&r" (result), "=&r" (temp), "=m" (v->counter) 535 : "Ir" (i), "m" (v->counter) 536 : "memory"); 537 } while (unlikely(!result)); 538 539 result = temp + i; 540 } else { 541 unsigned long flags; 542 543 raw_local_irq_save(flags); 544 result = v->counter; 545 result += i; 546 v->counter = result; 547 raw_local_irq_restore(flags); 548 } 549 550 smp_llsc_mb(); 551 552 return result; 553 } 554 555 static __inline__ long atomic64_sub_return(long i, atomic64_t * v) 556 { 557 long result; 558 559 smp_mb__before_llsc(); 560 561 if (kernel_uses_llsc && R10000_LLSC_WAR) { 562 long temp; 563 564 __asm__ __volatile__( 565 " .set mips3 \n" 566 "1: lld %1, %2 # atomic64_sub_return \n" 567 " dsubu %0, %1, %3 \n" 568 " scd %0, %2 \n" 569 " beqzl %0, 1b \n" 570 " dsubu %0, %1, %3 \n" 571 " .set mips0 \n" 572 : "=&r" (result), "=&r" (temp), "=m" (v->counter) 573 : "Ir" (i), "m" (v->counter) 574 : "memory"); 575 } else if (kernel_uses_llsc) { 576 long temp; 577 578 do { 579 __asm__ __volatile__( 580 " .set mips3 \n" 581 " lld %1, %2 # atomic64_sub_return \n" 582 " dsubu %0, %1, %3 \n" 583 " scd %0, %2 \n" 584 " .set mips0 \n" 585 : "=&r" (result), "=&r" (temp), "=m" (v->counter) 586 : "Ir" (i), "m" (v->counter) 587 : "memory"); 588 } while (unlikely(!result)); 589 590 result = temp - i; 591 } else { 592 unsigned long flags; 593 594 raw_local_irq_save(flags); 595 result = v->counter; 596 result -= i; 597 v->counter = result; 598 raw_local_irq_restore(flags); 599 } 600 601 smp_llsc_mb(); 602 603 return result; 604 } 605 606 /* 607 * atomic64_sub_if_positive - conditionally subtract integer from atomic variable 608 * @i: integer value to subtract 609 * @v: pointer of type atomic64_t 610 * 611 * Atomically test @v and subtract @i if @v is greater or equal than @i. 612 * The function returns the old value of @v minus @i. 613 */ 614 static __inline__ long atomic64_sub_if_positive(long i, atomic64_t * v) 615 { 616 long result; 617 618 smp_mb__before_llsc(); 619 620 if (kernel_uses_llsc && R10000_LLSC_WAR) { 621 long temp; 622 623 __asm__ __volatile__( 624 " .set mips3 \n" 625 "1: lld %1, %2 # atomic64_sub_if_positive\n" 626 " dsubu %0, %1, %3 \n" 627 " bltz %0, 1f \n" 628 " scd %0, %2 \n" 629 " .set noreorder \n" 630 " beqzl %0, 1b \n" 631 " dsubu %0, %1, %3 \n" 632 " .set reorder \n" 633 "1: \n" 634 " .set mips0 \n" 635 : "=&r" (result), "=&r" (temp), "=m" (v->counter) 636 : "Ir" (i), "m" (v->counter) 637 : "memory"); 638 } else if (kernel_uses_llsc) { 639 long temp; 640 641 __asm__ __volatile__( 642 " .set mips3 \n" 643 "1: lld %1, %2 # atomic64_sub_if_positive\n" 644 " dsubu %0, %1, %3 \n" 645 " bltz %0, 1f \n" 646 " scd %0, %2 \n" 647 " .set noreorder \n" 648 " beqz %0, 1b \n" 649 " dsubu %0, %1, %3 \n" 650 " .set reorder \n" 651 "1: \n" 652 " .set mips0 \n" 653 : "=&r" (result), "=&r" (temp), "=m" (v->counter) 654 : "Ir" (i), "m" (v->counter) 655 : "memory"); 656 } else { 657 unsigned long flags; 658 659 raw_local_irq_save(flags); 660 result = v->counter; 661 result -= i; 662 if (result >= 0) 663 v->counter = result; 664 raw_local_irq_restore(flags); 665 } 666 667 smp_llsc_mb(); 668 669 return result; 670 } 671 672 #define atomic64_cmpxchg(v, o, n) \ 673 ((__typeof__((v)->counter))cmpxchg(&((v)->counter), (o), (n))) 674 #define atomic64_xchg(v, new) (xchg(&((v)->counter), (new))) 675 676 /** 677 * atomic64_add_unless - add unless the number is a given value 678 * @v: pointer of type atomic64_t 679 * @a: the amount to add to v... 680 * @u: ...unless v is equal to u. 681 * 682 * Atomically adds @a to @v, so long as it was not @u. 683 * Returns non-zero if @v was not @u, and zero otherwise. 684 */ 685 static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u) 686 { 687 long c, old; 688 c = atomic64_read(v); 689 for (;;) { 690 if (unlikely(c == (u))) 691 break; 692 old = atomic64_cmpxchg((v), c, c + (a)); 693 if (likely(old == c)) 694 break; 695 c = old; 696 } 697 return c != (u); 698 } 699 700 #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) 701 702 #define atomic64_dec_return(v) atomic64_sub_return(1, (v)) 703 #define atomic64_inc_return(v) atomic64_add_return(1, (v)) 704 705 /* 706 * atomic64_sub_and_test - subtract value from variable and test result 707 * @i: integer value to subtract 708 * @v: pointer of type atomic64_t 709 * 710 * Atomically subtracts @i from @v and returns 711 * true if the result is zero, or false for all 712 * other cases. 713 */ 714 #define atomic64_sub_and_test(i, v) (atomic64_sub_return((i), (v)) == 0) 715 716 /* 717 * atomic64_inc_and_test - increment and test 718 * @v: pointer of type atomic64_t 719 * 720 * Atomically increments @v by 1 721 * and returns true if the result is zero, or false for all 722 * other cases. 723 */ 724 #define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0) 725 726 /* 727 * atomic64_dec_and_test - decrement by 1 and test 728 * @v: pointer of type atomic64_t 729 * 730 * Atomically decrements @v by 1 and 731 * returns true if the result is 0, or false for all other 732 * cases. 733 */ 734 #define atomic64_dec_and_test(v) (atomic64_sub_return(1, (v)) == 0) 735 736 /* 737 * atomic64_dec_if_positive - decrement by 1 if old value positive 738 * @v: pointer of type atomic64_t 739 */ 740 #define atomic64_dec_if_positive(v) atomic64_sub_if_positive(1, v) 741 742 /* 743 * atomic64_inc - increment atomic variable 744 * @v: pointer of type atomic64_t 745 * 746 * Atomically increments @v by 1. 747 */ 748 #define atomic64_inc(v) atomic64_add(1, (v)) 749 750 /* 751 * atomic64_dec - decrement and test 752 * @v: pointer of type atomic64_t 753 * 754 * Atomically decrements @v by 1. 755 */ 756 #define atomic64_dec(v) atomic64_sub(1, (v)) 757 758 /* 759 * atomic64_add_negative - add and test if negative 760 * @v: pointer of type atomic64_t 761 * @i: integer value to add 762 * 763 * Atomically adds @i to @v and returns true 764 * if the result is negative, or false when 765 * result is greater than or equal to zero. 766 */ 767 #define atomic64_add_negative(i, v) (atomic64_add_return(i, (v)) < 0) 768 769 #else /* !CONFIG_64BIT */ 770 771 #include <asm-generic/atomic64.h> 772 773 #endif /* CONFIG_64BIT */ 774 775 /* 776 * atomic*_return operations are serializing but not the non-*_return 777 * versions. 778 */ 779 #define smp_mb__before_atomic_dec() smp_mb__before_llsc() 780 #define smp_mb__after_atomic_dec() smp_llsc_mb() 781 #define smp_mb__before_atomic_inc() smp_mb__before_llsc() 782 #define smp_mb__after_atomic_inc() smp_llsc_mb() 783 784 #include <asm-generic/atomic-long.h> 785 786 #endif /* _ASM_ATOMIC_H */ 787