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