Merge nommu tree
[pandora-kernel.git] / include / asm-i386 / atomic.h
1 #ifndef __ARCH_I386_ATOMIC__
2 #define __ARCH_I386_ATOMIC__
3
4 #include <linux/config.h>
5 #include <linux/compiler.h>
6 #include <asm/processor.h>
7
8 /*
9  * Atomic operations that C can't guarantee us.  Useful for
10  * resource counting etc..
11  */
12
13 /*
14  * Make sure gcc doesn't try to be clever and move things around
15  * on us. We need to use _exactly_ the address the user gave us,
16  * not some alias that contains the same information.
17  */
18 typedef struct { volatile int counter; } atomic_t;
19
20 #define ATOMIC_INIT(i)  { (i) }
21
22 /**
23  * atomic_read - read atomic variable
24  * @v: pointer of type atomic_t
25  * 
26  * Atomically reads the value of @v.
27  */ 
28 #define atomic_read(v)          ((v)->counter)
29
30 /**
31  * atomic_set - set atomic variable
32  * @v: pointer of type atomic_t
33  * @i: required value
34  * 
35  * Atomically sets the value of @v to @i.
36  */ 
37 #define atomic_set(v,i)         (((v)->counter) = (i))
38
39 /**
40  * atomic_add - add integer to atomic variable
41  * @i: integer value to add
42  * @v: pointer of type atomic_t
43  * 
44  * Atomically adds @i to @v.
45  */
46 static __inline__ void atomic_add(int i, atomic_t *v)
47 {
48         __asm__ __volatile__(
49                 LOCK_PREFIX "addl %1,%0"
50                 :"=m" (v->counter)
51                 :"ir" (i), "m" (v->counter));
52 }
53
54 /**
55  * atomic_sub - subtract the atomic variable
56  * @i: integer value to subtract
57  * @v: pointer of type atomic_t
58  * 
59  * Atomically subtracts @i from @v.
60  */
61 static __inline__ void atomic_sub(int i, atomic_t *v)
62 {
63         __asm__ __volatile__(
64                 LOCK_PREFIX "subl %1,%0"
65                 :"=m" (v->counter)
66                 :"ir" (i), "m" (v->counter));
67 }
68
69 /**
70  * atomic_sub_and_test - subtract value from variable and test result
71  * @i: integer value to subtract
72  * @v: pointer of type atomic_t
73  * 
74  * Atomically subtracts @i from @v and returns
75  * true if the result is zero, or false for all
76  * other cases.
77  */
78 static __inline__ int atomic_sub_and_test(int i, atomic_t *v)
79 {
80         unsigned char c;
81
82         __asm__ __volatile__(
83                 LOCK_PREFIX "subl %2,%0; sete %1"
84                 :"=m" (v->counter), "=qm" (c)
85                 :"ir" (i), "m" (v->counter) : "memory");
86         return c;
87 }
88
89 /**
90  * atomic_inc - increment atomic variable
91  * @v: pointer of type atomic_t
92  * 
93  * Atomically increments @v by 1.
94  */ 
95 static __inline__ void atomic_inc(atomic_t *v)
96 {
97         __asm__ __volatile__(
98                 LOCK_PREFIX "incl %0"
99                 :"=m" (v->counter)
100                 :"m" (v->counter));
101 }
102
103 /**
104  * atomic_dec - decrement atomic variable
105  * @v: pointer of type atomic_t
106  * 
107  * Atomically decrements @v by 1.
108  */ 
109 static __inline__ void atomic_dec(atomic_t *v)
110 {
111         __asm__ __volatile__(
112                 LOCK_PREFIX "decl %0"
113                 :"=m" (v->counter)
114                 :"m" (v->counter));
115 }
116
117 /**
118  * atomic_dec_and_test - decrement and test
119  * @v: pointer of type atomic_t
120  * 
121  * Atomically decrements @v by 1 and
122  * returns true if the result is 0, or false for all other
123  * cases.
124  */ 
125 static __inline__ int atomic_dec_and_test(atomic_t *v)
126 {
127         unsigned char c;
128
129         __asm__ __volatile__(
130                 LOCK_PREFIX "decl %0; sete %1"
131                 :"=m" (v->counter), "=qm" (c)
132                 :"m" (v->counter) : "memory");
133         return c != 0;
134 }
135
136 /**
137  * atomic_inc_and_test - increment and test 
138  * @v: pointer of type atomic_t
139  * 
140  * Atomically increments @v by 1
141  * and returns true if the result is zero, or false for all
142  * other cases.
143  */ 
144 static __inline__ int atomic_inc_and_test(atomic_t *v)
145 {
146         unsigned char c;
147
148         __asm__ __volatile__(
149                 LOCK_PREFIX "incl %0; sete %1"
150                 :"=m" (v->counter), "=qm" (c)
151                 :"m" (v->counter) : "memory");
152         return c != 0;
153 }
154
155 /**
156  * atomic_add_negative - add and test if negative
157  * @v: pointer of type atomic_t
158  * @i: integer value to add
159  * 
160  * Atomically adds @i to @v and returns true
161  * if the result is negative, or false when
162  * result is greater than or equal to zero.
163  */ 
164 static __inline__ int atomic_add_negative(int i, atomic_t *v)
165 {
166         unsigned char c;
167
168         __asm__ __volatile__(
169                 LOCK_PREFIX "addl %2,%0; sets %1"
170                 :"=m" (v->counter), "=qm" (c)
171                 :"ir" (i), "m" (v->counter) : "memory");
172         return c;
173 }
174
175 /**
176  * atomic_add_return - add and return
177  * @v: pointer of type atomic_t
178  * @i: integer value to add
179  *
180  * Atomically adds @i to @v and returns @i + @v
181  */
182 static __inline__ int atomic_add_return(int i, atomic_t *v)
183 {
184         int __i;
185 #ifdef CONFIG_M386
186         if(unlikely(boot_cpu_data.x86==3))
187                 goto no_xadd;
188 #endif
189         /* Modern 486+ processor */
190         __i = i;
191         __asm__ __volatile__(
192                 LOCK_PREFIX "xaddl %0, %1;"
193                 :"=r"(i)
194                 :"m"(v->counter), "0"(i));
195         return i + __i;
196
197 #ifdef CONFIG_M386
198 no_xadd: /* Legacy 386 processor */
199         local_irq_disable();
200         __i = atomic_read(v);
201         atomic_set(v, i + __i);
202         local_irq_enable();
203         return i + __i;
204 #endif
205 }
206
207 static __inline__ int atomic_sub_return(int i, atomic_t *v)
208 {
209         return atomic_add_return(-i,v);
210 }
211
212 #define atomic_cmpxchg(v, old, new) ((int)cmpxchg(&((v)->counter), old, new))
213 #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
214
215 /**
216  * atomic_add_unless - add unless the number is a given value
217  * @v: pointer of type atomic_t
218  * @a: the amount to add to v...
219  * @u: ...unless v is equal to u.
220  *
221  * Atomically adds @a to @v, so long as it was not @u.
222  * Returns non-zero if @v was not @u, and zero otherwise.
223  */
224 #define atomic_add_unless(v, a, u)                              \
225 ({                                                              \
226         int c, old;                                             \
227         c = atomic_read(v);                                     \
228         for (;;) {                                              \
229                 if (unlikely(c == (u)))                         \
230                         break;                                  \
231                 old = atomic_cmpxchg((v), c, c + (a));          \
232                 if (likely(old == c))                           \
233                         break;                                  \
234                 c = old;                                        \
235         }                                                       \
236         c != (u);                                               \
237 })
238 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
239
240 #define atomic_inc_return(v)  (atomic_add_return(1,v))
241 #define atomic_dec_return(v)  (atomic_sub_return(1,v))
242
243 /* These are x86-specific, used by some header files */
244 #define atomic_clear_mask(mask, addr) \
245 __asm__ __volatile__(LOCK_PREFIX "andl %0,%1" \
246 : : "r" (~(mask)),"m" (*addr) : "memory")
247
248 #define atomic_set_mask(mask, addr) \
249 __asm__ __volatile__(LOCK_PREFIX "orl %0,%1" \
250 : : "r" (mask),"m" (*(addr)) : "memory")
251
252 /* Atomic operations are already serializing on x86 */
253 #define smp_mb__before_atomic_dec()     barrier()
254 #define smp_mb__after_atomic_dec()      barrier()
255 #define smp_mb__before_atomic_inc()     barrier()
256 #define smp_mb__after_atomic_inc()      barrier()
257
258 #include <asm-generic/atomic.h>
259 #endif