a448d94ab721802f4d196b72b20fd0b45c52a8df
[sfrench/cifs-2.6.git] / arch / microblaze / include / asm / atomic.h
1 /*
2  * Copyright (C) 2006 Atmark Techno, Inc.
3  *
4  * This file is subject to the terms and conditions of the GNU General Public
5  * License. See the file "COPYING" in the main directory of this archive
6  * for more details.
7  */
8
9 #ifndef _ASM_MICROBLAZE_ATOMIC_H
10 #define _ASM_MICROBLAZE_ATOMIC_H
11
12 #include <linux/types.h>
13 #include <linux/compiler.h> /* likely */
14 #include <asm/system.h> /* local_irq_XXX and friends */
15
16 #define ATOMIC_INIT(i)          { (i) }
17 #define atomic_read(v)          ((v)->counter)
18 #define atomic_set(v, i)        (((v)->counter) = (i))
19
20 #define atomic_inc(v)           (atomic_add_return(1, (v)))
21 #define atomic_dec(v)           (atomic_sub_return(1, (v)))
22
23 #define atomic_add(i, v)        (atomic_add_return(i, (v)))
24 #define atomic_sub(i, v)        (atomic_sub_return(i, (v)))
25
26 #define atomic_inc_return(v)    (atomic_add_return(1, (v)))
27 #define atomic_dec_return(v)    (atomic_sub_return(1, (v)))
28
29 #define atomic_inc_and_test(v)  (atomic_add_return(1, (v)) == 0)
30 #define atomic_dec_and_test(v)  (atomic_sub_return(1, (v)) == 0)
31
32 #define atomic_inc_not_zero(v)  (atomic_add_unless((v), 1, 0))
33
34 #define atomic_sub_and_test(i, v) (atomic_sub_return((i), (v)) == 0)
35
36 static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
37 {
38         int ret;
39         unsigned long flags;
40
41         local_irq_save(flags);
42         ret = v->counter;
43         if (likely(ret == old))
44                 v->counter = new;
45         local_irq_restore(flags);
46
47         return ret;
48 }
49
50 static inline int atomic_add_unless(atomic_t *v, int a, int u)
51 {
52         int c, old;
53
54         c = atomic_read(v);
55         while (c != u && (old = atomic_cmpxchg((v), c, c + a)) != c)
56                 c = old;
57         return c != u;
58 }
59
60 static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
61 {
62         unsigned long flags;
63
64         local_irq_save(flags);
65         *addr &= ~mask;
66         local_irq_restore(flags);
67 }
68
69 /**
70  * atomic_add_return - add and return
71  * @i: integer value to add
72  * @v: pointer of type atomic_t
73  *
74  * Atomically adds @i to @v and returns @i + @v
75  */
76 static inline int atomic_add_return(int i, atomic_t *v)
77 {
78         unsigned long flags;
79         int val;
80
81         local_irq_save(flags);
82         val = v->counter;
83         v->counter = val += i;
84         local_irq_restore(flags);
85
86         return val;
87 }
88
89 static inline int atomic_sub_return(int i, atomic_t *v)
90 {
91         return atomic_add_return(-i, v);
92 }
93
94 /*
95  * Atomically test *v and decrement if it is greater than 0.
96  * The function returns the old value of *v minus 1.
97  */
98 static inline int atomic_dec_if_positive(atomic_t *v)
99 {
100         unsigned long flags;
101         int res;
102
103         local_irq_save(flags);
104         res = v->counter - 1;
105         if (res >= 0)
106                 v->counter = res;
107         local_irq_restore(flags);
108
109         return res;
110 }
111
112 #define atomic_add_negative(a, v)       (atomic_add_return((a), (v)) < 0)
113 #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
114
115 /* Atomic operations are already serializing */
116 #define smp_mb__before_atomic_dec()     barrier()
117 #define smp_mb__after_atomic_dec()      barrier()
118 #define smp_mb__before_atomic_inc()     barrier()
119 #define smp_mb__after_atomic_inc()      barrier()
120
121 #include <asm-generic/atomic.h>
122
123 #endif /* _ASM_MICROBLAZE_ATOMIC_H */