linux/arch/powerpc/include/asm/atomic.h
<<
>>
Prefs
   1#ifndef _ASM_POWERPC_ATOMIC_H_
   2#define _ASM_POWERPC_ATOMIC_H_
   3
   4/*
   5 * PowerPC atomic operations
   6 */
   7
   8#ifdef __KERNEL__
   9#include <linux/types.h>
  10#include <asm/cmpxchg.h>
  11#include <asm/barrier.h>
  12
  13#define ATOMIC_INIT(i)          { (i) }
  14
  15/*
  16 * Since *_return_relaxed and {cmp}xchg_relaxed are implemented with
  17 * a "bne-" instruction at the end, so an isync is enough as a acquire barrier
  18 * on the platform without lwsync.
  19 */
  20#define __atomic_op_acquire(op, args...)                                \
  21({                                                                      \
  22        typeof(op##_relaxed(args)) __ret  = op##_relaxed(args);         \
  23        __asm__ __volatile__(PPC_ACQUIRE_BARRIER "" : : : "memory");    \
  24        __ret;                                                          \
  25})
  26
  27#define __atomic_op_release(op, args...)                                \
  28({                                                                      \
  29        __asm__ __volatile__(PPC_RELEASE_BARRIER "" : : : "memory");    \
  30        op##_relaxed(args);                                             \
  31})
  32
  33static __inline__ int atomic_read(const atomic_t *v)
  34{
  35        int t;
  36
  37        __asm__ __volatile__("lwz%U1%X1 %0,%1" : "=r"(t) : "m"(v->counter));
  38
  39        return t;
  40}
  41
  42static __inline__ void atomic_set(atomic_t *v, int i)
  43{
  44        __asm__ __volatile__("stw%U0%X0 %1,%0" : "=m"(v->counter) : "r"(i));
  45}
  46
  47#define ATOMIC_OP(op, asm_op)                                           \
  48static __inline__ void atomic_##op(int a, atomic_t *v)                  \
  49{                                                                       \
  50        int t;                                                          \
  51                                                                        \
  52        __asm__ __volatile__(                                           \
  53"1:     lwarx   %0,0,%3         # atomic_" #op "\n"                     \
  54        #asm_op " %0,%2,%0\n"                                           \
  55        PPC405_ERR77(0,%3)                                              \
  56"       stwcx.  %0,0,%3 \n"                                             \
  57"       bne-    1b\n"                                                   \
  58        : "=&r" (t), "+m" (v->counter)                                  \
  59        : "r" (a), "r" (&v->counter)                                    \
  60        : "cc");                                                        \
  61}                                                                       \
  62
  63#define ATOMIC_OP_RETURN_RELAXED(op, asm_op)                            \
  64static inline int atomic_##op##_return_relaxed(int a, atomic_t *v)      \
  65{                                                                       \
  66        int t;                                                          \
  67                                                                        \
  68        __asm__ __volatile__(                                           \
  69"1:     lwarx   %0,0,%3         # atomic_" #op "_return_relaxed\n"      \
  70        #asm_op " %0,%2,%0\n"                                           \
  71        PPC405_ERR77(0, %3)                                             \
  72"       stwcx.  %0,0,%3\n"                                              \
  73"       bne-    1b\n"                                                   \
  74        : "=&r" (t), "+m" (v->counter)                                  \
  75        : "r" (a), "r" (&v->counter)                                    \
  76        : "cc");                                                        \
  77                                                                        \
  78        return t;                                                       \
  79}
  80
  81#define ATOMIC_FETCH_OP_RELAXED(op, asm_op)                             \
  82static inline int atomic_fetch_##op##_relaxed(int a, atomic_t *v)       \
  83{                                                                       \
  84        int res, t;                                                     \
  85                                                                        \
  86        __asm__ __volatile__(                                           \
  87"1:     lwarx   %0,0,%4         # atomic_fetch_" #op "_relaxed\n"       \
  88        #asm_op " %1,%3,%0\n"                                           \
  89        PPC405_ERR77(0, %4)                                             \
  90"       stwcx.  %1,0,%4\n"                                              \
  91"       bne-    1b\n"                                                   \
  92        : "=&r" (res), "=&r" (t), "+m" (v->counter)                     \
  93        : "r" (a), "r" (&v->counter)                                    \
  94        : "cc");                                                        \
  95                                                                        \
  96        return res;                                                     \
  97}
  98
  99#define ATOMIC_OPS(op, asm_op)                                          \
 100        ATOMIC_OP(op, asm_op)                                           \
 101        ATOMIC_OP_RETURN_RELAXED(op, asm_op)                            \
 102        ATOMIC_FETCH_OP_RELAXED(op, asm_op)
 103
 104ATOMIC_OPS(add, add)
 105ATOMIC_OPS(sub, subf)
 106
 107#define atomic_add_return_relaxed atomic_add_return_relaxed
 108#define atomic_sub_return_relaxed atomic_sub_return_relaxed
 109
 110#define atomic_fetch_add_relaxed atomic_fetch_add_relaxed
 111#define atomic_fetch_sub_relaxed atomic_fetch_sub_relaxed
 112
 113#undef ATOMIC_OPS
 114#define ATOMIC_OPS(op, asm_op)                                          \
 115        ATOMIC_OP(op, asm_op)                                           \
 116        ATOMIC_FETCH_OP_RELAXED(op, asm_op)
 117
 118ATOMIC_OPS(and, and)
 119ATOMIC_OPS(or, or)
 120ATOMIC_OPS(xor, xor)
 121
 122#define atomic_fetch_and_relaxed atomic_fetch_and_relaxed
 123#define atomic_fetch_or_relaxed  atomic_fetch_or_relaxed
 124#define atomic_fetch_xor_relaxed atomic_fetch_xor_relaxed
 125
 126#undef ATOMIC_OPS
 127#undef ATOMIC_FETCH_OP_RELAXED
 128#undef ATOMIC_OP_RETURN_RELAXED
 129#undef ATOMIC_OP
 130
 131#define atomic_add_negative(a, v)       (atomic_add_return((a), (v)) < 0)
 132
 133static __inline__ void atomic_inc(atomic_t *v)
 134{
 135        int t;
 136
 137        __asm__ __volatile__(
 138"1:     lwarx   %0,0,%2         # atomic_inc\n\
 139        addic   %0,%0,1\n"
 140        PPC405_ERR77(0,%2)
 141"       stwcx.  %0,0,%2 \n\
 142        bne-    1b"
 143        : "=&r" (t), "+m" (v->counter)
 144        : "r" (&v->counter)
 145        : "cc", "xer");
 146}
 147
 148static __inline__ int atomic_inc_return_relaxed(atomic_t *v)
 149{
 150        int t;
 151
 152        __asm__ __volatile__(
 153"1:     lwarx   %0,0,%2         # atomic_inc_return_relaxed\n"
 154"       addic   %0,%0,1\n"
 155        PPC405_ERR77(0, %2)
 156"       stwcx.  %0,0,%2\n"
 157"       bne-    1b"
 158        : "=&r" (t), "+m" (v->counter)
 159        : "r" (&v->counter)
 160        : "cc", "xer");
 161
 162        return t;
 163}
 164
 165/*
 166 * atomic_inc_and_test - increment and test
 167 * @v: pointer of type atomic_t
 168 *
 169 * Atomically increments @v by 1
 170 * and returns true if the result is zero, or false for all
 171 * other cases.
 172 */
 173#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0)
 174
 175static __inline__ void atomic_dec(atomic_t *v)
 176{
 177        int t;
 178
 179        __asm__ __volatile__(
 180"1:     lwarx   %0,0,%2         # atomic_dec\n\
 181        addic   %0,%0,-1\n"
 182        PPC405_ERR77(0,%2)\
 183"       stwcx.  %0,0,%2\n\
 184        bne-    1b"
 185        : "=&r" (t), "+m" (v->counter)
 186        : "r" (&v->counter)
 187        : "cc", "xer");
 188}
 189
 190static __inline__ int atomic_dec_return_relaxed(atomic_t *v)
 191{
 192        int t;
 193
 194        __asm__ __volatile__(
 195"1:     lwarx   %0,0,%2         # atomic_dec_return_relaxed\n"
 196"       addic   %0,%0,-1\n"
 197        PPC405_ERR77(0, %2)
 198"       stwcx.  %0,0,%2\n"
 199"       bne-    1b"
 200        : "=&r" (t), "+m" (v->counter)
 201        : "r" (&v->counter)
 202        : "cc", "xer");
 203
 204        return t;
 205}
 206
 207#define atomic_inc_return_relaxed atomic_inc_return_relaxed
 208#define atomic_dec_return_relaxed atomic_dec_return_relaxed
 209
 210#define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
 211#define atomic_cmpxchg_relaxed(v, o, n) \
 212        cmpxchg_relaxed(&((v)->counter), (o), (n))
 213#define atomic_cmpxchg_acquire(v, o, n) \
 214        cmpxchg_acquire(&((v)->counter), (o), (n))
 215
 216#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
 217#define atomic_xchg_relaxed(v, new) xchg_relaxed(&((v)->counter), (new))
 218
 219/**
 220 * __atomic_add_unless - add unless the number is a given value
 221 * @v: pointer of type atomic_t
 222 * @a: the amount to add to v...
 223 * @u: ...unless v is equal to u.
 224 *
 225 * Atomically adds @a to @v, so long as it was not @u.
 226 * Returns the old value of @v.
 227 */
 228static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u)
 229{
 230        int t;
 231
 232        __asm__ __volatile__ (
 233        PPC_ATOMIC_ENTRY_BARRIER
 234"1:     lwarx   %0,0,%1         # __atomic_add_unless\n\
 235        cmpw    0,%0,%3 \n\
 236        beq     2f \n\
 237        add     %0,%2,%0 \n"
 238        PPC405_ERR77(0,%2)
 239"       stwcx.  %0,0,%1 \n\
 240        bne-    1b \n"
 241        PPC_ATOMIC_EXIT_BARRIER
 242"       subf    %0,%2,%0 \n\
 2432:"
 244        : "=&r" (t)
 245        : "r" (&v->counter), "r" (a), "r" (u)
 246        : "cc", "memory");
 247
 248        return t;
 249}
 250
 251/**
 252 * atomic_inc_not_zero - increment unless the number is zero
 253 * @v: pointer of type atomic_t
 254 *
 255 * Atomically increments @v by 1, so long as @v is non-zero.
 256 * Returns non-zero if @v was non-zero, and zero otherwise.
 257 */
 258static __inline__ int atomic_inc_not_zero(atomic_t *v)
 259{
 260        int t1, t2;
 261
 262        __asm__ __volatile__ (
 263        PPC_ATOMIC_ENTRY_BARRIER
 264"1:     lwarx   %0,0,%2         # atomic_inc_not_zero\n\
 265        cmpwi   0,%0,0\n\
 266        beq-    2f\n\
 267        addic   %1,%0,1\n"
 268        PPC405_ERR77(0,%2)
 269"       stwcx.  %1,0,%2\n\
 270        bne-    1b\n"
 271        PPC_ATOMIC_EXIT_BARRIER
 272        "\n\
 2732:"
 274        : "=&r" (t1), "=&r" (t2)
 275        : "r" (&v->counter)
 276        : "cc", "xer", "memory");
 277
 278        return t1;
 279}
 280#define atomic_inc_not_zero(v) atomic_inc_not_zero((v))
 281
 282#define atomic_sub_and_test(a, v)       (atomic_sub_return((a), (v)) == 0)
 283#define atomic_dec_and_test(v)          (atomic_dec_return((v)) == 0)
 284
 285/*
 286 * Atomically test *v and decrement if it is greater than 0.
 287 * The function returns the old value of *v minus 1, even if
 288 * the atomic variable, v, was not decremented.
 289 */
 290static __inline__ int atomic_dec_if_positive(atomic_t *v)
 291{
 292        int t;
 293
 294        __asm__ __volatile__(
 295        PPC_ATOMIC_ENTRY_BARRIER
 296"1:     lwarx   %0,0,%1         # atomic_dec_if_positive\n\
 297        cmpwi   %0,1\n\
 298        addi    %0,%0,-1\n\
 299        blt-    2f\n"
 300        PPC405_ERR77(0,%1)
 301"       stwcx.  %0,0,%1\n\
 302        bne-    1b"
 303        PPC_ATOMIC_EXIT_BARRIER
 304        "\n\
 3052:"     : "=&b" (t)
 306        : "r" (&v->counter)
 307        : "cc", "memory");
 308
 309        return t;
 310}
 311#define atomic_dec_if_positive atomic_dec_if_positive
 312
 313#ifdef __powerpc64__
 314
 315#define ATOMIC64_INIT(i)        { (i) }
 316
 317static __inline__ long atomic64_read(const atomic64_t *v)
 318{
 319        long t;
 320
 321        __asm__ __volatile__("ld%U1%X1 %0,%1" : "=r"(t) : "m"(v->counter));
 322
 323        return t;
 324}
 325
 326static __inline__ void atomic64_set(atomic64_t *v, long i)
 327{
 328        __asm__ __volatile__("std%U0%X0 %1,%0" : "=m"(v->counter) : "r"(i));
 329}
 330
 331#define ATOMIC64_OP(op, asm_op)                                         \
 332static __inline__ void atomic64_##op(long a, atomic64_t *v)             \
 333{                                                                       \
 334        long t;                                                         \
 335                                                                        \
 336        __asm__ __volatile__(                                           \
 337"1:     ldarx   %0,0,%3         # atomic64_" #op "\n"                   \
 338        #asm_op " %0,%2,%0\n"                                           \
 339"       stdcx.  %0,0,%3 \n"                                             \
 340"       bne-    1b\n"                                                   \
 341        : "=&r" (t), "+m" (v->counter)                                  \
 342        : "r" (a), "r" (&v->counter)                                    \
 343        : "cc");                                                        \
 344}
 345
 346#define ATOMIC64_OP_RETURN_RELAXED(op, asm_op)                          \
 347static inline long                                                      \
 348atomic64_##op##_return_relaxed(long a, atomic64_t *v)                   \
 349{                                                                       \
 350        long t;                                                         \
 351                                                                        \
 352        __asm__ __volatile__(                                           \
 353"1:     ldarx   %0,0,%3         # atomic64_" #op "_return_relaxed\n"    \
 354        #asm_op " %0,%2,%0\n"                                           \
 355"       stdcx.  %0,0,%3\n"                                              \
 356"       bne-    1b\n"                                                   \
 357        : "=&r" (t), "+m" (v->counter)                                  \
 358        : "r" (a), "r" (&v->counter)                                    \
 359        : "cc");                                                        \
 360                                                                        \
 361        return t;                                                       \
 362}
 363
 364#define ATOMIC64_FETCH_OP_RELAXED(op, asm_op)                           \
 365static inline long                                                      \
 366atomic64_fetch_##op##_relaxed(long a, atomic64_t *v)                    \
 367{                                                                       \
 368        long res, t;                                                    \
 369                                                                        \
 370        __asm__ __volatile__(                                           \
 371"1:     ldarx   %0,0,%4         # atomic64_fetch_" #op "_relaxed\n"     \
 372        #asm_op " %1,%3,%0\n"                                           \
 373"       stdcx.  %1,0,%4\n"                                              \
 374"       bne-    1b\n"                                                   \
 375        : "=&r" (res), "=&r" (t), "+m" (v->counter)                     \
 376        : "r" (a), "r" (&v->counter)                                    \
 377        : "cc");                                                        \
 378                                                                        \
 379        return res;                                                     \
 380}
 381
 382#define ATOMIC64_OPS(op, asm_op)                                        \
 383        ATOMIC64_OP(op, asm_op)                                         \
 384        ATOMIC64_OP_RETURN_RELAXED(op, asm_op)                          \
 385        ATOMIC64_FETCH_OP_RELAXED(op, asm_op)
 386
 387ATOMIC64_OPS(add, add)
 388ATOMIC64_OPS(sub, subf)
 389
 390#define atomic64_add_return_relaxed atomic64_add_return_relaxed
 391#define atomic64_sub_return_relaxed atomic64_sub_return_relaxed
 392
 393#define atomic64_fetch_add_relaxed atomic64_fetch_add_relaxed
 394#define atomic64_fetch_sub_relaxed atomic64_fetch_sub_relaxed
 395
 396#undef ATOMIC64_OPS
 397#define ATOMIC64_OPS(op, asm_op)                                        \
 398        ATOMIC64_OP(op, asm_op)                                         \
 399        ATOMIC64_FETCH_OP_RELAXED(op, asm_op)
 400
 401ATOMIC64_OPS(and, and)
 402ATOMIC64_OPS(or, or)
 403ATOMIC64_OPS(xor, xor)
 404
 405#define atomic64_fetch_and_relaxed atomic64_fetch_and_relaxed
 406#define atomic64_fetch_or_relaxed  atomic64_fetch_or_relaxed
 407#define atomic64_fetch_xor_relaxed atomic64_fetch_xor_relaxed
 408
 409#undef ATOPIC64_OPS
 410#undef ATOMIC64_FETCH_OP_RELAXED
 411#undef ATOMIC64_OP_RETURN_RELAXED
 412#undef ATOMIC64_OP
 413
 414#define atomic64_add_negative(a, v)     (atomic64_add_return((a), (v)) < 0)
 415
 416static __inline__ void atomic64_inc(atomic64_t *v)
 417{
 418        long t;
 419
 420        __asm__ __volatile__(
 421"1:     ldarx   %0,0,%2         # atomic64_inc\n\
 422        addic   %0,%0,1\n\
 423        stdcx.  %0,0,%2 \n\
 424        bne-    1b"
 425        : "=&r" (t), "+m" (v->counter)
 426        : "r" (&v->counter)
 427        : "cc", "xer");
 428}
 429
 430static __inline__ long atomic64_inc_return_relaxed(atomic64_t *v)
 431{
 432        long t;
 433
 434        __asm__ __volatile__(
 435"1:     ldarx   %0,0,%2         # atomic64_inc_return_relaxed\n"
 436"       addic   %0,%0,1\n"
 437"       stdcx.  %0,0,%2\n"
 438"       bne-    1b"
 439        : "=&r" (t), "+m" (v->counter)
 440        : "r" (&v->counter)
 441        : "cc", "xer");
 442
 443        return t;
 444}
 445
 446/*
 447 * atomic64_inc_and_test - increment and test
 448 * @v: pointer of type atomic64_t
 449 *
 450 * Atomically increments @v by 1
 451 * and returns true if the result is zero, or false for all
 452 * other cases.
 453 */
 454#define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0)
 455
 456static __inline__ void atomic64_dec(atomic64_t *v)
 457{
 458        long t;
 459
 460        __asm__ __volatile__(
 461"1:     ldarx   %0,0,%2         # atomic64_dec\n\
 462        addic   %0,%0,-1\n\
 463        stdcx.  %0,0,%2\n\
 464        bne-    1b"
 465        : "=&r" (t), "+m" (v->counter)
 466        : "r" (&v->counter)
 467        : "cc", "xer");
 468}
 469
 470static __inline__ long atomic64_dec_return_relaxed(atomic64_t *v)
 471{
 472        long t;
 473
 474        __asm__ __volatile__(
 475"1:     ldarx   %0,0,%2         # atomic64_dec_return_relaxed\n"
 476"       addic   %0,%0,-1\n"
 477"       stdcx.  %0,0,%2\n"
 478"       bne-    1b"
 479        : "=&r" (t), "+m" (v->counter)
 480        : "r" (&v->counter)
 481        : "cc", "xer");
 482
 483        return t;
 484}
 485
 486#define atomic64_inc_return_relaxed atomic64_inc_return_relaxed
 487#define atomic64_dec_return_relaxed atomic64_dec_return_relaxed
 488
 489#define atomic64_sub_and_test(a, v)     (atomic64_sub_return((a), (v)) == 0)
 490#define atomic64_dec_and_test(v)        (atomic64_dec_return((v)) == 0)
 491
 492/*
 493 * Atomically test *v and decrement if it is greater than 0.
 494 * The function returns the old value of *v minus 1.
 495 */
 496static __inline__ long atomic64_dec_if_positive(atomic64_t *v)
 497{
 498        long t;
 499
 500        __asm__ __volatile__(
 501        PPC_ATOMIC_ENTRY_BARRIER
 502"1:     ldarx   %0,0,%1         # atomic64_dec_if_positive\n\
 503        addic.  %0,%0,-1\n\
 504        blt-    2f\n\
 505        stdcx.  %0,0,%1\n\
 506        bne-    1b"
 507        PPC_ATOMIC_EXIT_BARRIER
 508        "\n\
 5092:"     : "=&r" (t)
 510        : "r" (&v->counter)
 511        : "cc", "xer", "memory");
 512
 513        return t;
 514}
 515
 516#define atomic64_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
 517#define atomic64_cmpxchg_relaxed(v, o, n) \
 518        cmpxchg_relaxed(&((v)->counter), (o), (n))
 519#define atomic64_cmpxchg_acquire(v, o, n) \
 520        cmpxchg_acquire(&((v)->counter), (o), (n))
 521
 522#define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
 523#define atomic64_xchg_relaxed(v, new) xchg_relaxed(&((v)->counter), (new))
 524
 525/**
 526 * atomic64_add_unless - add unless the number is a given value
 527 * @v: pointer of type atomic64_t
 528 * @a: the amount to add to v...
 529 * @u: ...unless v is equal to u.
 530 *
 531 * Atomically adds @a to @v, so long as it was not @u.
 532 * Returns the old value of @v.
 533 */
 534static __inline__ int atomic64_add_unless(atomic64_t *v, long a, long u)
 535{
 536        long t;
 537
 538        __asm__ __volatile__ (
 539        PPC_ATOMIC_ENTRY_BARRIER
 540"1:     ldarx   %0,0,%1         # __atomic_add_unless\n\
 541        cmpd    0,%0,%3 \n\
 542        beq     2f \n\
 543        add     %0,%2,%0 \n"
 544"       stdcx.  %0,0,%1 \n\
 545        bne-    1b \n"
 546        PPC_ATOMIC_EXIT_BARRIER
 547"       subf    %0,%2,%0 \n\
 5482:"
 549        : "=&r" (t)
 550        : "r" (&v->counter), "r" (a), "r" (u)
 551        : "cc", "memory");
 552
 553        return t != u;
 554}
 555
 556/**
 557 * atomic_inc64_not_zero - increment unless the number is zero
 558 * @v: pointer of type atomic64_t
 559 *
 560 * Atomically increments @v by 1, so long as @v is non-zero.
 561 * Returns non-zero if @v was non-zero, and zero otherwise.
 562 */
 563static __inline__ long atomic64_inc_not_zero(atomic64_t *v)
 564{
 565        long t1, t2;
 566
 567        __asm__ __volatile__ (
 568        PPC_ATOMIC_ENTRY_BARRIER
 569"1:     ldarx   %0,0,%2         # atomic64_inc_not_zero\n\
 570        cmpdi   0,%0,0\n\
 571        beq-    2f\n\
 572        addic   %1,%0,1\n\
 573        stdcx.  %1,0,%2\n\
 574        bne-    1b\n"
 575        PPC_ATOMIC_EXIT_BARRIER
 576        "\n\
 5772:"
 578        : "=&r" (t1), "=&r" (t2)
 579        : "r" (&v->counter)
 580        : "cc", "xer", "memory");
 581
 582        return t1;
 583}
 584
 585#endif /* __powerpc64__ */
 586
 587#endif /* __KERNEL__ */
 588#endif /* _ASM_POWERPC_ATOMIC_H_ */
 589