linux/arch/avr32/include/asm/atomic.h
<<
>>
Prefs
   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 slower than
   6 * regular operations.
   7 *
   8 * Copyright (C) 2004-2006 Atmel Corporation
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of the GNU General Public License version 2 as
  12 * published by the Free Software Foundation.
  13 */
  14#ifndef __ASM_AVR32_ATOMIC_H
  15#define __ASM_AVR32_ATOMIC_H
  16
  17#include <linux/types.h>
  18#include <asm/system.h>
  19
  20#define ATOMIC_INIT(i)  { (i) }
  21
  22#define atomic_read(v)          ((v)->counter)
  23#define atomic_set(v, i)        (((v)->counter) = i)
  24
  25/*
  26 * atomic_sub_return - subtract the atomic variable
  27 * @i: integer value to subtract
  28 * @v: pointer of type atomic_t
  29 *
  30 * Atomically subtracts @i from @v. Returns the resulting value.
  31 */
  32static inline int atomic_sub_return(int i, atomic_t *v)
  33{
  34        int result;
  35
  36        asm volatile(
  37                "/* atomic_sub_return */\n"
  38                "1:     ssrf    5\n"
  39                "       ld.w    %0, %2\n"
  40                "       sub     %0, %3\n"
  41                "       stcond  %1, %0\n"
  42                "       brne    1b"
  43                : "=&r"(result), "=o"(v->counter)
  44                : "m"(v->counter), "rKs21"(i)
  45                : "cc");
  46
  47        return result;
  48}
  49
  50/*
  51 * atomic_add_return - add integer to atomic variable
  52 * @i: integer value to add
  53 * @v: pointer of type atomic_t
  54 *
  55 * Atomically adds @i to @v. Returns the resulting value.
  56 */
  57static inline int atomic_add_return(int i, atomic_t *v)
  58{
  59        int result;
  60
  61        if (__builtin_constant_p(i) && (i >= -1048575) && (i <= 1048576))
  62                result = atomic_sub_return(-i, v);
  63        else
  64                asm volatile(
  65                        "/* atomic_add_return */\n"
  66                        "1:     ssrf    5\n"
  67                        "       ld.w    %0, %1\n"
  68                        "       add     %0, %3\n"
  69                        "       stcond  %2, %0\n"
  70                        "       brne    1b"
  71                        : "=&r"(result), "=o"(v->counter)
  72                        : "m"(v->counter), "r"(i)
  73                        : "cc", "memory");
  74
  75        return result;
  76}
  77
  78/*
  79 * atomic_sub_unless - sub unless the number is a given value
  80 * @v: pointer of type atomic_t
  81 * @a: the amount to add to v...
  82 * @u: ...unless v is equal to u.
  83 *
  84 * If the atomic value v is not equal to u, this function subtracts a
  85 * from v, and returns non zero. If v is equal to u then it returns
  86 * zero. This is done as an atomic operation.
  87*/
  88static inline int atomic_sub_unless(atomic_t *v, int a, int u)
  89{
  90        int tmp, result = 0;
  91
  92        asm volatile(
  93                "/* atomic_sub_unless */\n"
  94                "1:     ssrf    5\n"
  95                "       ld.w    %0, %3\n"
  96                "       cp.w    %0, %5\n"
  97                "       breq    1f\n"
  98                "       sub     %0, %4\n"
  99                "       stcond  %2, %0\n"
 100                "       brne    1b\n"
 101                "       mov     %1, 1\n"
 102                "1:"
 103                : "=&r"(tmp), "=&r"(result), "=o"(v->counter)
 104                : "m"(v->counter), "rKs21"(a), "rKs21"(u), "1"(result)
 105                : "cc", "memory");
 106
 107        return result;
 108}
 109
 110/*
 111 * atomic_add_unless - add unless the number is a given value
 112 * @v: pointer of type atomic_t
 113 * @a: the amount to add to v...
 114 * @u: ...unless v is equal to u.
 115 *
 116 * If the atomic value v is not equal to u, this function adds a to v,
 117 * and returns non zero. If v is equal to u then it returns zero. This
 118 * is done as an atomic operation.
 119*/
 120static inline int atomic_add_unless(atomic_t *v, int a, int u)
 121{
 122        int tmp, result;
 123
 124        if (__builtin_constant_p(a) && (a >= -1048575) && (a <= 1048576))
 125                result = atomic_sub_unless(v, -a, u);
 126        else {
 127                result = 0;
 128                asm volatile(
 129                        "/* atomic_add_unless */\n"
 130                        "1:     ssrf    5\n"
 131                        "       ld.w    %0, %3\n"
 132                        "       cp.w    %0, %5\n"
 133                        "       breq    1f\n"
 134                        "       add     %0, %4\n"
 135                        "       stcond  %2, %0\n"
 136                        "       brne    1b\n"
 137                        "       mov     %1, 1\n"
 138                        "1:"
 139                        : "=&r"(tmp), "=&r"(result), "=o"(v->counter)
 140                        : "m"(v->counter), "r"(a), "ir"(u), "1"(result)
 141                        : "cc", "memory");
 142        }
 143
 144        return result;
 145}
 146
 147/*
 148 * atomic_sub_if_positive - conditionally subtract integer from atomic variable
 149 * @i: integer value to subtract
 150 * @v: pointer of type atomic_t
 151 *
 152 * Atomically test @v and subtract @i if @v is greater or equal than @i.
 153 * The function returns the old value of @v minus @i.
 154 */
 155static inline int atomic_sub_if_positive(int i, atomic_t *v)
 156{
 157        int result;
 158
 159        asm volatile(
 160                "/* atomic_sub_if_positive */\n"
 161                "1:     ssrf    5\n"
 162                "       ld.w    %0, %2\n"
 163                "       sub     %0, %3\n"
 164                "       brlt    1f\n"
 165                "       stcond  %1, %0\n"
 166                "       brne    1b\n"
 167                "1:"
 168                : "=&r"(result), "=o"(v->counter)
 169                : "m"(v->counter), "ir"(i)
 170                : "cc", "memory");
 171
 172        return result;
 173}
 174
 175#define atomic_xchg(v, new)     (xchg(&((v)->counter), new))
 176#define atomic_cmpxchg(v, o, n) (cmpxchg(&((v)->counter), (o), (n)))
 177
 178#define atomic_sub(i, v)        (void)atomic_sub_return(i, v)
 179#define atomic_add(i, v)        (void)atomic_add_return(i, v)
 180#define atomic_dec(v)           atomic_sub(1, (v))
 181#define atomic_inc(v)           atomic_add(1, (v))
 182
 183#define atomic_dec_return(v)    atomic_sub_return(1, v)
 184#define atomic_inc_return(v)    atomic_add_return(1, v)
 185
 186#define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0)
 187#define atomic_inc_and_test(v) (atomic_add_return(1, v) == 0)
 188#define atomic_dec_and_test(v) (atomic_sub_return(1, v) == 0)
 189#define atomic_add_negative(i, v) (atomic_add_return(i, v) < 0)
 190
 191#define atomic_inc_not_zero(v)  atomic_add_unless(v, 1, 0)
 192#define atomic_dec_if_positive(v) atomic_sub_if_positive(1, v)
 193
 194#define smp_mb__before_atomic_dec()     barrier()
 195#define smp_mb__after_atomic_dec()      barrier()
 196#define smp_mb__before_atomic_inc()     barrier()
 197#define smp_mb__after_atomic_inc()      barrier()
 198
 199#include <asm-generic/atomic.h>
 200
 201#endif /*  __ASM_AVR32_ATOMIC_H */
 202