linux/arch/s390/include/asm/atomic.h
<<
>>
Prefs
   1#ifndef __ARCH_S390_ATOMIC__
   2#define __ARCH_S390_ATOMIC__
   3
   4/*
   5 * Copyright 1999,2009 IBM Corp.
   6 * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>,
   7 *            Denis Joseph Barrow,
   8 *            Arnd Bergmann <arndb@de.ibm.com>,
   9 *
  10 * Atomic operations that C can't guarantee us.
  11 * Useful for resource counting etc.
  12 * s390 uses 'Compare And Swap' for atomicity in SMP enviroment.
  13 *
  14 */
  15
  16#include <linux/compiler.h>
  17#include <linux/types.h>
  18#include <asm/system.h>
  19
  20#define ATOMIC_INIT(i)  { (i) }
  21
  22#define __CS_LOOP(ptr, op_val, op_string) ({                            \
  23        int old_val, new_val;                                           \
  24        asm volatile(                                                   \
  25                "       l       %0,%2\n"                                \
  26                "0:     lr      %1,%0\n"                                \
  27                op_string "     %1,%3\n"                                \
  28                "       cs      %0,%1,%2\n"                             \
  29                "       jl      0b"                                     \
  30                : "=&d" (old_val), "=&d" (new_val),                     \
  31                  "=Q" (((atomic_t *)(ptr))->counter)                   \
  32                : "d" (op_val),  "Q" (((atomic_t *)(ptr))->counter)     \
  33                : "cc", "memory");                                      \
  34        new_val;                                                        \
  35})
  36
  37static inline int atomic_read(const atomic_t *v)
  38{
  39        int c;
  40
  41        asm volatile(
  42                "       l       %0,%1\n"
  43                : "=d" (c) : "Q" (v->counter));
  44        return c;
  45}
  46
  47static inline void atomic_set(atomic_t *v, int i)
  48{
  49        asm volatile(
  50                "       st      %1,%0\n"
  51                : "=Q" (v->counter) : "d" (i));
  52}
  53
  54static inline int atomic_add_return(int i, atomic_t *v)
  55{
  56        return __CS_LOOP(v, i, "ar");
  57}
  58#define atomic_add(_i, _v)              atomic_add_return(_i, _v)
  59#define atomic_add_negative(_i, _v)     (atomic_add_return(_i, _v) < 0)
  60#define atomic_inc(_v)                  atomic_add_return(1, _v)
  61#define atomic_inc_return(_v)           atomic_add_return(1, _v)
  62#define atomic_inc_and_test(_v)         (atomic_add_return(1, _v) == 0)
  63
  64static inline int atomic_sub_return(int i, atomic_t *v)
  65{
  66        return __CS_LOOP(v, i, "sr");
  67}
  68#define atomic_sub(_i, _v)              atomic_sub_return(_i, _v)
  69#define atomic_sub_and_test(_i, _v)     (atomic_sub_return(_i, _v) == 0)
  70#define atomic_dec(_v)                  atomic_sub_return(1, _v)
  71#define atomic_dec_return(_v)           atomic_sub_return(1, _v)
  72#define atomic_dec_and_test(_v)         (atomic_sub_return(1, _v) == 0)
  73
  74static inline void atomic_clear_mask(unsigned long mask, atomic_t *v)
  75{
  76        __CS_LOOP(v, ~mask, "nr");
  77}
  78
  79static inline void atomic_set_mask(unsigned long mask, atomic_t *v)
  80{
  81        __CS_LOOP(v, mask, "or");
  82}
  83
  84#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
  85
  86static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
  87{
  88        asm volatile(
  89                "       cs      %0,%2,%1"
  90                : "+d" (old), "=Q" (v->counter)
  91                : "d" (new), "Q" (v->counter)
  92                : "cc", "memory");
  93        return old;
  94}
  95
  96static inline int atomic_add_unless(atomic_t *v, int a, int u)
  97{
  98        int c, old;
  99        c = atomic_read(v);
 100        for (;;) {
 101                if (unlikely(c == u))
 102                        break;
 103                old = atomic_cmpxchg(v, c, c + a);
 104                if (likely(old == c))
 105                        break;
 106                c = old;
 107        }
 108        return c != u;
 109}
 110
 111#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
 112
 113#undef __CS_LOOP
 114
 115#define ATOMIC64_INIT(i)  { (i) }
 116
 117#ifdef CONFIG_64BIT
 118
 119#define __CSG_LOOP(ptr, op_val, op_string) ({                           \
 120        long long old_val, new_val;                                     \
 121        asm volatile(                                                   \
 122                "       lg      %0,%2\n"                                \
 123                "0:     lgr     %1,%0\n"                                \
 124                op_string "     %1,%3\n"                                \
 125                "       csg     %0,%1,%2\n"                             \
 126                "       jl      0b"                                     \
 127                : "=&d" (old_val), "=&d" (new_val),                     \
 128                  "=Q" (((atomic_t *)(ptr))->counter)                   \
 129                : "d" (op_val), "Q" (((atomic_t *)(ptr))->counter)      \
 130                : "cc", "memory");                                      \
 131        new_val;                                                        \
 132})
 133
 134static inline long long atomic64_read(const atomic64_t *v)
 135{
 136        long long c;
 137
 138        asm volatile(
 139                "       lg      %0,%1\n"
 140                : "=d" (c) : "Q" (v->counter));
 141        return c;
 142}
 143
 144static inline void atomic64_set(atomic64_t *v, long long i)
 145{
 146        asm volatile(
 147                "       stg     %1,%0\n"
 148                : "=Q" (v->counter) : "d" (i));
 149}
 150
 151static inline long long atomic64_add_return(long long i, atomic64_t *v)
 152{
 153        return __CSG_LOOP(v, i, "agr");
 154}
 155
 156static inline long long atomic64_sub_return(long long i, atomic64_t *v)
 157{
 158        return __CSG_LOOP(v, i, "sgr");
 159}
 160
 161static inline void atomic64_clear_mask(unsigned long mask, atomic64_t *v)
 162{
 163        __CSG_LOOP(v, ~mask, "ngr");
 164}
 165
 166static inline void atomic64_set_mask(unsigned long mask, atomic64_t *v)
 167{
 168        __CSG_LOOP(v, mask, "ogr");
 169}
 170
 171#define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
 172
 173static inline long long atomic64_cmpxchg(atomic64_t *v,
 174                                             long long old, long long new)
 175{
 176        asm volatile(
 177                "       csg     %0,%2,%1"
 178                : "+d" (old), "=Q" (v->counter)
 179                : "d" (new), "Q" (v->counter)
 180                : "cc", "memory");
 181        return old;
 182}
 183
 184#undef __CSG_LOOP
 185
 186#else /* CONFIG_64BIT */
 187
 188typedef struct {
 189        long long counter;
 190} atomic64_t;
 191
 192static inline long long atomic64_read(const atomic64_t *v)
 193{
 194        register_pair rp;
 195
 196        asm volatile(
 197                "       lm      %0,%N0,%1"
 198                : "=&d" (rp) : "Q" (v->counter) );
 199        return rp.pair;
 200}
 201
 202static inline void atomic64_set(atomic64_t *v, long long i)
 203{
 204        register_pair rp = {.pair = i};
 205
 206        asm volatile(
 207                "       stm     %1,%N1,%0"
 208                : "=Q" (v->counter) : "d" (rp) );
 209}
 210
 211static inline long long atomic64_xchg(atomic64_t *v, long long new)
 212{
 213        register_pair rp_new = {.pair = new};
 214        register_pair rp_old;
 215
 216        asm volatile(
 217                "       lm      %0,%N0,%1\n"
 218                "0:     cds     %0,%2,%1\n"
 219                "       jl      0b\n"
 220                : "=&d" (rp_old), "=Q" (v->counter)
 221                : "d" (rp_new), "Q" (v->counter)
 222                : "cc");
 223        return rp_old.pair;
 224}
 225
 226static inline long long atomic64_cmpxchg(atomic64_t *v,
 227                                         long long old, long long new)
 228{
 229        register_pair rp_old = {.pair = old};
 230        register_pair rp_new = {.pair = new};
 231
 232        asm volatile(
 233                "       cds     %0,%2,%1"
 234                : "+&d" (rp_old), "=Q" (v->counter)
 235                : "d" (rp_new), "Q" (v->counter)
 236                : "cc");
 237        return rp_old.pair;
 238}
 239
 240
 241static inline long long atomic64_add_return(long long i, atomic64_t *v)
 242{
 243        long long old, new;
 244
 245        do {
 246                old = atomic64_read(v);
 247                new = old + i;
 248        } while (atomic64_cmpxchg(v, old, new) != old);
 249        return new;
 250}
 251
 252static inline long long atomic64_sub_return(long long i, atomic64_t *v)
 253{
 254        long long old, new;
 255
 256        do {
 257                old = atomic64_read(v);
 258                new = old - i;
 259        } while (atomic64_cmpxchg(v, old, new) != old);
 260        return new;
 261}
 262
 263static inline void atomic64_set_mask(unsigned long long mask, atomic64_t *v)
 264{
 265        long long old, new;
 266
 267        do {
 268                old = atomic64_read(v);
 269                new = old | mask;
 270        } while (atomic64_cmpxchg(v, old, new) != old);
 271}
 272
 273static inline void atomic64_clear_mask(unsigned long long mask, atomic64_t *v)
 274{
 275        long long old, new;
 276
 277        do {
 278                old = atomic64_read(v);
 279                new = old & mask;
 280        } while (atomic64_cmpxchg(v, old, new) != old);
 281}
 282
 283#endif /* CONFIG_64BIT */
 284
 285static inline int atomic64_add_unless(atomic64_t *v, long long a, long long u)
 286{
 287        long long c, old;
 288
 289        c = atomic64_read(v);
 290        for (;;) {
 291                if (unlikely(c == u))
 292                        break;
 293                old = atomic64_cmpxchg(v, c, c + a);
 294                if (likely(old == c))
 295                        break;
 296                c = old;
 297        }
 298        return c != u;
 299}
 300
 301static inline long long atomic64_dec_if_positive(atomic64_t *v)
 302{
 303        long long c, old, dec;
 304
 305        c = atomic64_read(v);
 306        for (;;) {
 307                dec = c - 1;
 308                if (unlikely(dec < 0))
 309                        break;
 310                old = atomic64_cmpxchg((v), c, dec);
 311                if (likely(old == c))
 312                        break;
 313                c = old;
 314        }
 315        return dec;
 316}
 317
 318#define atomic64_add(_i, _v)            atomic64_add_return(_i, _v)
 319#define atomic64_add_negative(_i, _v)   (atomic64_add_return(_i, _v) < 0)
 320#define atomic64_inc(_v)                atomic64_add_return(1, _v)
 321#define atomic64_inc_return(_v)         atomic64_add_return(1, _v)
 322#define atomic64_inc_and_test(_v)       (atomic64_add_return(1, _v) == 0)
 323#define atomic64_sub(_i, _v)            atomic64_sub_return(_i, _v)
 324#define atomic64_sub_and_test(_i, _v)   (atomic64_sub_return(_i, _v) == 0)
 325#define atomic64_dec(_v)                atomic64_sub_return(1, _v)
 326#define atomic64_dec_return(_v)         atomic64_sub_return(1, _v)
 327#define atomic64_dec_and_test(_v)       (atomic64_sub_return(1, _v) == 0)
 328#define atomic64_inc_not_zero(v)        atomic64_add_unless((v), 1, 0)
 329
 330#define smp_mb__before_atomic_dec()     smp_mb()
 331#define smp_mb__after_atomic_dec()      smp_mb()
 332#define smp_mb__before_atomic_inc()     smp_mb()
 333#define smp_mb__after_atomic_inc()      smp_mb()
 334
 335#include <asm-generic/atomic-long.h>
 336
 337#endif /* __ARCH_S390_ATOMIC__  */
 338