linux/arch/metag/include/asm/atomic_lock1.h
<<
>>
Prefs
   1#ifndef __ASM_METAG_ATOMIC_LOCK1_H
   2#define __ASM_METAG_ATOMIC_LOCK1_H
   3
   4#define ATOMIC_INIT(i)  { (i) }
   5
   6#include <linux/compiler.h>
   7
   8#include <asm/barrier.h>
   9#include <asm/global_lock.h>
  10
  11static inline int atomic_read(const atomic_t *v)
  12{
  13        return READ_ONCE((v)->counter);
  14}
  15
  16/*
  17 * atomic_set needs to be take the lock to protect atomic_add_unless from a
  18 * possible race, as it reads the counter twice:
  19 *
  20 *  CPU0                               CPU1
  21 *  atomic_add_unless(1, 0)
  22 *    ret = v->counter (non-zero)
  23 *    if (ret != u)                    v->counter = 0
  24 *      v->counter += 1 (counter set to 1)
  25 *
  26 * Making atomic_set take the lock ensures that ordering and logical
  27 * consistency is preserved.
  28 */
  29static inline int atomic_set(atomic_t *v, int i)
  30{
  31        unsigned long flags;
  32
  33        __global_lock1(flags);
  34        fence();
  35        v->counter = i;
  36        __global_unlock1(flags);
  37        return i;
  38}
  39
  40#define ATOMIC_OP(op, c_op)                                             \
  41static inline void atomic_##op(int i, atomic_t *v)                      \
  42{                                                                       \
  43        unsigned long flags;                                            \
  44                                                                        \
  45        __global_lock1(flags);                                          \
  46        fence();                                                        \
  47        v->counter c_op i;                                              \
  48        __global_unlock1(flags);                                        \
  49}                                                                       \
  50
  51#define ATOMIC_OP_RETURN(op, c_op)                                      \
  52static inline int atomic_##op##_return(int i, atomic_t *v)              \
  53{                                                                       \
  54        unsigned long result;                                           \
  55        unsigned long flags;                                            \
  56                                                                        \
  57        __global_lock1(flags);                                          \
  58        result = v->counter;                                            \
  59        result c_op i;                                                  \
  60        fence();                                                        \
  61        v->counter = result;                                            \
  62        __global_unlock1(flags);                                        \
  63                                                                        \
  64        return result;                                                  \
  65}
  66
  67#define ATOMIC_FETCH_OP(op, c_op)                                       \
  68static inline int atomic_fetch_##op(int i, atomic_t *v)                 \
  69{                                                                       \
  70        unsigned long result;                                           \
  71        unsigned long flags;                                            \
  72                                                                        \
  73        __global_lock1(flags);                                          \
  74        result = v->counter;                                            \
  75        fence();                                                        \
  76        v->counter c_op i;                                              \
  77        __global_unlock1(flags);                                        \
  78                                                                        \
  79        return result;                                                  \
  80}
  81
  82#define ATOMIC_OPS(op, c_op)                                            \
  83        ATOMIC_OP(op, c_op)                                             \
  84        ATOMIC_OP_RETURN(op, c_op)                                      \
  85        ATOMIC_FETCH_OP(op, c_op)
  86
  87ATOMIC_OPS(add, +=)
  88ATOMIC_OPS(sub, -=)
  89
  90#undef ATOMIC_OPS
  91#define ATOMIC_OPS(op, c_op)                                            \
  92        ATOMIC_OP(op, c_op)                                             \
  93        ATOMIC_FETCH_OP(op, c_op)
  94
  95ATOMIC_OPS(and, &=)
  96ATOMIC_OPS(or, |=)
  97ATOMIC_OPS(xor, ^=)
  98
  99#undef ATOMIC_OPS
 100#undef ATOMIC_FETCH_OP
 101#undef ATOMIC_OP_RETURN
 102#undef ATOMIC_OP
 103
 104static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
 105{
 106        int ret;
 107        unsigned long flags;
 108
 109        __global_lock1(flags);
 110        ret = v->counter;
 111        if (ret == old) {
 112                fence();
 113                v->counter = new;
 114        }
 115        __global_unlock1(flags);
 116
 117        return ret;
 118}
 119
 120#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
 121
 122static inline int __atomic_add_unless(atomic_t *v, int a, int u)
 123{
 124        int ret;
 125        unsigned long flags;
 126
 127        __global_lock1(flags);
 128        ret = v->counter;
 129        if (ret != u) {
 130                fence();
 131                v->counter += a;
 132        }
 133        __global_unlock1(flags);
 134
 135        return ret;
 136}
 137
 138static inline int atomic_sub_if_positive(int i, atomic_t *v)
 139{
 140        int ret;
 141        unsigned long flags;
 142
 143        __global_lock1(flags);
 144        ret = v->counter - 1;
 145        if (ret >= 0) {
 146                fence();
 147                v->counter = ret;
 148        }
 149        __global_unlock1(flags);
 150
 151        return ret;
 152}
 153
 154#endif /* __ASM_METAG_ATOMIC_LOCK1_H */
 155