linux/arch/m32r/include/asm/atomic.h
<<
>>
Prefs
   1#ifndef _ASM_M32R_ATOMIC_H
   2#define _ASM_M32R_ATOMIC_H
   3
   4/*
   5 *  linux/include/asm-m32r/atomic.h
   6 *
   7 *  M32R version:
   8 *    Copyright (C) 2001, 2002  Hitoshi Yamamoto
   9 *    Copyright (C) 2004  Hirokazu Takata <takata at linux-m32r.org>
  10 */
  11
  12#include <linux/types.h>
  13#include <asm/assembler.h>
  14#include <asm/cmpxchg.h>
  15#include <asm/dcache_clear.h>
  16#include <asm/barrier.h>
  17
  18/*
  19 * Atomic operations that C can't guarantee us.  Useful for
  20 * resource counting etc..
  21 */
  22
  23#define ATOMIC_INIT(i)  { (i) }
  24
  25/**
  26 * atomic_read - read atomic variable
  27 * @v: pointer of type atomic_t
  28 *
  29 * Atomically reads the value of @v.
  30 */
  31#define atomic_read(v)  ACCESS_ONCE((v)->counter)
  32
  33/**
  34 * atomic_set - set atomic variable
  35 * @v: pointer of type atomic_t
  36 * @i: required value
  37 *
  38 * Atomically sets the value of @v to @i.
  39 */
  40#define atomic_set(v,i) (((v)->counter) = (i))
  41
  42#ifdef CONFIG_CHIP_M32700_TS1
  43#define __ATOMIC_CLOBBER        , "r4"
  44#else
  45#define __ATOMIC_CLOBBER
  46#endif
  47
  48#define ATOMIC_OP(op)                                                   \
  49static __inline__ void atomic_##op(int i, atomic_t *v)                  \
  50{                                                                       \
  51        unsigned long flags;                                            \
  52        int result;                                                     \
  53                                                                        \
  54        local_irq_save(flags);                                          \
  55        __asm__ __volatile__ (                                          \
  56                "# atomic_" #op "               \n\t"                   \
  57                DCACHE_CLEAR("%0", "r4", "%1")                          \
  58                M32R_LOCK" %0, @%1;             \n\t"                   \
  59                #op " %0, %2;                   \n\t"                   \
  60                M32R_UNLOCK" %0, @%1;           \n\t"                   \
  61                : "=&r" (result)                                        \
  62                : "r" (&v->counter), "r" (i)                            \
  63                : "memory"                                              \
  64                __ATOMIC_CLOBBER                                        \
  65        );                                                              \
  66        local_irq_restore(flags);                                       \
  67}                                                                       \
  68
  69#define ATOMIC_OP_RETURN(op)                                            \
  70static __inline__ int atomic_##op##_return(int i, atomic_t *v)          \
  71{                                                                       \
  72        unsigned long flags;                                            \
  73        int result;                                                     \
  74                                                                        \
  75        local_irq_save(flags);                                          \
  76        __asm__ __volatile__ (                                          \
  77                "# atomic_" #op "_return        \n\t"                   \
  78                DCACHE_CLEAR("%0", "r4", "%1")                          \
  79                M32R_LOCK" %0, @%1;             \n\t"                   \
  80                #op " %0, %2;                   \n\t"                   \
  81                M32R_UNLOCK" %0, @%1;           \n\t"                   \
  82                : "=&r" (result)                                        \
  83                : "r" (&v->counter), "r" (i)                            \
  84                : "memory"                                              \
  85                __ATOMIC_CLOBBER                                        \
  86        );                                                              \
  87        local_irq_restore(flags);                                       \
  88                                                                        \
  89        return result;                                                  \
  90}
  91
  92#define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op)
  93
  94ATOMIC_OPS(add)
  95ATOMIC_OPS(sub)
  96
  97#undef ATOMIC_OPS
  98#undef ATOMIC_OP_RETURN
  99#undef ATOMIC_OP
 100
 101/**
 102 * atomic_sub_and_test - subtract value from variable and test result
 103 * @i: integer value to subtract
 104 * @v: pointer of type atomic_t
 105 *
 106 * Atomically subtracts @i from @v and returns
 107 * true if the result is zero, or false for all
 108 * other cases.
 109 */
 110#define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0)
 111
 112/**
 113 * atomic_inc_return - increment atomic variable and return it
 114 * @v: pointer of type atomic_t
 115 *
 116 * Atomically increments @v by 1 and returns the result.
 117 */
 118static __inline__ int atomic_inc_return(atomic_t *v)
 119{
 120        unsigned long flags;
 121        int result;
 122
 123        local_irq_save(flags);
 124        __asm__ __volatile__ (
 125                "# atomic_inc_return            \n\t"
 126                DCACHE_CLEAR("%0", "r4", "%1")
 127                M32R_LOCK" %0, @%1;             \n\t"
 128                "addi   %0, #1;                 \n\t"
 129                M32R_UNLOCK" %0, @%1;           \n\t"
 130                : "=&r" (result)
 131                : "r" (&v->counter)
 132                : "memory"
 133                __ATOMIC_CLOBBER
 134        );
 135        local_irq_restore(flags);
 136
 137        return result;
 138}
 139
 140/**
 141 * atomic_dec_return - decrement atomic variable and return it
 142 * @v: pointer of type atomic_t
 143 *
 144 * Atomically decrements @v by 1 and returns the result.
 145 */
 146static __inline__ int atomic_dec_return(atomic_t *v)
 147{
 148        unsigned long flags;
 149        int result;
 150
 151        local_irq_save(flags);
 152        __asm__ __volatile__ (
 153                "# atomic_dec_return            \n\t"
 154                DCACHE_CLEAR("%0", "r4", "%1")
 155                M32R_LOCK" %0, @%1;             \n\t"
 156                "addi   %0, #-1;                \n\t"
 157                M32R_UNLOCK" %0, @%1;           \n\t"
 158                : "=&r" (result)
 159                : "r" (&v->counter)
 160                : "memory"
 161                __ATOMIC_CLOBBER
 162        );
 163        local_irq_restore(flags);
 164
 165        return result;
 166}
 167
 168/**
 169 * atomic_inc - increment atomic variable
 170 * @v: pointer of type atomic_t
 171 *
 172 * Atomically increments @v by 1.
 173 */
 174#define atomic_inc(v) ((void)atomic_inc_return(v))
 175
 176/**
 177 * atomic_dec - decrement atomic variable
 178 * @v: pointer of type atomic_t
 179 *
 180 * Atomically decrements @v by 1.
 181 */
 182#define atomic_dec(v) ((void)atomic_dec_return(v))
 183
 184/**
 185 * atomic_inc_and_test - increment and test
 186 * @v: pointer of type atomic_t
 187 *
 188 * Atomically increments @v by 1
 189 * and returns true if the result is zero, or false for all
 190 * other cases.
 191 */
 192#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0)
 193
 194/**
 195 * atomic_dec_and_test - decrement and test
 196 * @v: pointer of type atomic_t
 197 *
 198 * Atomically decrements @v by 1 and
 199 * returns true if the result is 0, or false for all
 200 * other cases.
 201 */
 202#define atomic_dec_and_test(v) (atomic_dec_return(v) == 0)
 203
 204/**
 205 * atomic_add_negative - add and test if negative
 206 * @v: pointer of type atomic_t
 207 * @i: integer value to add
 208 *
 209 * Atomically adds @i to @v and returns true
 210 * if the result is negative, or false when
 211 * result is greater than or equal to zero.
 212 */
 213#define atomic_add_negative(i,v) (atomic_add_return((i), (v)) < 0)
 214
 215#define atomic_cmpxchg(v, o, n) ((int)cmpxchg(&((v)->counter), (o), (n)))
 216#define atomic_xchg(v, new) (xchg(&((v)->counter), new))
 217
 218/**
 219 * __atomic_add_unless - add unless the number is a given value
 220 * @v: pointer of type atomic_t
 221 * @a: the amount to add to v...
 222 * @u: ...unless v is equal to u.
 223 *
 224 * Atomically adds @a to @v, so long as it was not @u.
 225 * Returns the old value of @v.
 226 */
 227static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u)
 228{
 229        int c, old;
 230        c = atomic_read(v);
 231        for (;;) {
 232                if (unlikely(c == (u)))
 233                        break;
 234                old = atomic_cmpxchg((v), c, c + (a));
 235                if (likely(old == c))
 236                        break;
 237                c = old;
 238        }
 239        return c;
 240}
 241
 242
 243static __inline__ void atomic_clear_mask(unsigned long  mask, atomic_t *addr)
 244{
 245        unsigned long flags;
 246        unsigned long tmp;
 247
 248        local_irq_save(flags);
 249        __asm__ __volatile__ (
 250                "# atomic_clear_mask            \n\t"
 251                DCACHE_CLEAR("%0", "r5", "%1")
 252                M32R_LOCK" %0, @%1;             \n\t"
 253                "and    %0, %2;                 \n\t"
 254                M32R_UNLOCK" %0, @%1;           \n\t"
 255                : "=&r" (tmp)
 256                : "r" (addr), "r" (~mask)
 257                : "memory"
 258                __ATOMIC_CLOBBER
 259        );
 260        local_irq_restore(flags);
 261}
 262
 263static __inline__ void atomic_set_mask(unsigned long  mask, atomic_t *addr)
 264{
 265        unsigned long flags;
 266        unsigned long tmp;
 267
 268        local_irq_save(flags);
 269        __asm__ __volatile__ (
 270                "# atomic_set_mask              \n\t"
 271                DCACHE_CLEAR("%0", "r5", "%1")
 272                M32R_LOCK" %0, @%1;             \n\t"
 273                "or     %0, %2;                 \n\t"
 274                M32R_UNLOCK" %0, @%1;           \n\t"
 275                : "=&r" (tmp)
 276                : "r" (addr), "r" (mask)
 277                : "memory"
 278                __ATOMIC_CLOBBER
 279        );
 280        local_irq_restore(flags);
 281}
 282
 283#endif  /* _ASM_M32R_ATOMIC_H */
 284