Merge branch 'upstream' of git://ftp.linux-mips.org/pub/scm/upstream-linus
[linux-2.6] / arch / x86 / include / asm / atomic_64.h
1 #ifndef _ASM_X86_ATOMIC_64_H
2 #define _ASM_X86_ATOMIC_64_H
3
4 #include <linux/types.h>
5 #include <asm/alternative.h>
6 #include <asm/cmpxchg.h>
7
8 /*
9  * Atomic operations that C can't guarantee us.  Useful for
10  * resource counting etc..
11  */
12
13 #define ATOMIC_INIT(i)  { (i) }
14
15 /**
16  * atomic_read - read atomic variable
17  * @v: pointer of type atomic_t
18  *
19  * Atomically reads the value of @v.
20  */
21 #define atomic_read(v)          ((v)->counter)
22
23 /**
24  * atomic_set - set atomic variable
25  * @v: pointer of type atomic_t
26  * @i: required value
27  *
28  * Atomically sets the value of @v to @i.
29  */
30 #define atomic_set(v, i)                (((v)->counter) = (i))
31
32 /**
33  * atomic_add - add integer to atomic variable
34  * @i: integer value to add
35  * @v: pointer of type atomic_t
36  *
37  * Atomically adds @i to @v.
38  */
39 static inline void atomic_add(int i, atomic_t *v)
40 {
41         asm volatile(LOCK_PREFIX "addl %1,%0"
42                      : "=m" (v->counter)
43                      : "ir" (i), "m" (v->counter));
44 }
45
46 /**
47  * atomic_sub - subtract the atomic variable
48  * @i: integer value to subtract
49  * @v: pointer of type atomic_t
50  *
51  * Atomically subtracts @i from @v.
52  */
53 static inline void atomic_sub(int i, atomic_t *v)
54 {
55         asm volatile(LOCK_PREFIX "subl %1,%0"
56                      : "=m" (v->counter)
57                      : "ir" (i), "m" (v->counter));
58 }
59
60 /**
61  * atomic_sub_and_test - subtract value from variable and test result
62  * @i: integer value to subtract
63  * @v: pointer of type atomic_t
64  *
65  * Atomically subtracts @i from @v and returns
66  * true if the result is zero, or false for all
67  * other cases.
68  */
69 static inline int atomic_sub_and_test(int i, atomic_t *v)
70 {
71         unsigned char c;
72
73         asm volatile(LOCK_PREFIX "subl %2,%0; sete %1"
74                      : "=m" (v->counter), "=qm" (c)
75                      : "ir" (i), "m" (v->counter) : "memory");
76         return c;
77 }
78
79 /**
80  * atomic_inc - increment atomic variable
81  * @v: pointer of type atomic_t
82  *
83  * Atomically increments @v by 1.
84  */
85 static inline void atomic_inc(atomic_t *v)
86 {
87         asm volatile(LOCK_PREFIX "incl %0"
88                      : "=m" (v->counter)
89                      : "m" (v->counter));
90 }
91
92 /**
93  * atomic_dec - decrement atomic variable
94  * @v: pointer of type atomic_t
95  *
96  * Atomically decrements @v by 1.
97  */
98 static inline void atomic_dec(atomic_t *v)
99 {
100         asm volatile(LOCK_PREFIX "decl %0"
101                      : "=m" (v->counter)
102                      : "m" (v->counter));
103 }
104
105 /**
106  * atomic_dec_and_test - decrement and test
107  * @v: pointer of type atomic_t
108  *
109  * Atomically decrements @v by 1 and
110  * returns true if the result is 0, or false for all other
111  * cases.
112  */
113 static inline int atomic_dec_and_test(atomic_t *v)
114 {
115         unsigned char c;
116
117         asm volatile(LOCK_PREFIX "decl %0; sete %1"
118                      : "=m" (v->counter), "=qm" (c)
119                      : "m" (v->counter) : "memory");
120         return c != 0;
121 }
122
123 /**
124  * atomic_inc_and_test - increment and test
125  * @v: pointer of type atomic_t
126  *
127  * Atomically increments @v by 1
128  * and returns true if the result is zero, or false for all
129  * other cases.
130  */
131 static inline int atomic_inc_and_test(atomic_t *v)
132 {
133         unsigned char c;
134
135         asm volatile(LOCK_PREFIX "incl %0; sete %1"
136                      : "=m" (v->counter), "=qm" (c)
137                      : "m" (v->counter) : "memory");
138         return c != 0;
139 }
140
141 /**
142  * atomic_add_negative - add and test if negative
143  * @i: integer value to add
144  * @v: pointer of type atomic_t
145  *
146  * Atomically adds @i to @v and returns true
147  * if the result is negative, or false when
148  * result is greater than or equal to zero.
149  */
150 static inline int atomic_add_negative(int i, atomic_t *v)
151 {
152         unsigned char c;
153
154         asm volatile(LOCK_PREFIX "addl %2,%0; sets %1"
155                      : "=m" (v->counter), "=qm" (c)
156                      : "ir" (i), "m" (v->counter) : "memory");
157         return c;
158 }
159
160 /**
161  * atomic_add_return - add and return
162  * @i: integer value to add
163  * @v: pointer of type atomic_t
164  *
165  * Atomically adds @i to @v and returns @i + @v
166  */
167 static inline int atomic_add_return(int i, atomic_t *v)
168 {
169         int __i = i;
170         asm volatile(LOCK_PREFIX "xaddl %0, %1"
171                      : "+r" (i), "+m" (v->counter)
172                      : : "memory");
173         return i + __i;
174 }
175
176 static inline int atomic_sub_return(int i, atomic_t *v)
177 {
178         return atomic_add_return(-i, v);
179 }
180
181 #define atomic_inc_return(v)  (atomic_add_return(1, v))
182 #define atomic_dec_return(v)  (atomic_sub_return(1, v))
183
184 /* The 64-bit atomic type */
185
186 #define ATOMIC64_INIT(i)        { (i) }
187
188 /**
189  * atomic64_read - read atomic64 variable
190  * @v: pointer of type atomic64_t
191  *
192  * Atomically reads the value of @v.
193  * Doesn't imply a read memory barrier.
194  */
195 #define atomic64_read(v)                ((v)->counter)
196
197 /**
198  * atomic64_set - set atomic64 variable
199  * @v: pointer to type atomic64_t
200  * @i: required value
201  *
202  * Atomically sets the value of @v to @i.
203  */
204 #define atomic64_set(v, i)              (((v)->counter) = (i))
205
206 /**
207  * atomic64_add - add integer to atomic64 variable
208  * @i: integer value to add
209  * @v: pointer to type atomic64_t
210  *
211  * Atomically adds @i to @v.
212  */
213 static inline void atomic64_add(long i, atomic64_t *v)
214 {
215         asm volatile(LOCK_PREFIX "addq %1,%0"
216                      : "=m" (v->counter)
217                      : "er" (i), "m" (v->counter));
218 }
219
220 /**
221  * atomic64_sub - subtract the atomic64 variable
222  * @i: integer value to subtract
223  * @v: pointer to type atomic64_t
224  *
225  * Atomically subtracts @i from @v.
226  */
227 static inline void atomic64_sub(long i, atomic64_t *v)
228 {
229         asm volatile(LOCK_PREFIX "subq %1,%0"
230                      : "=m" (v->counter)
231                      : "er" (i), "m" (v->counter));
232 }
233
234 /**
235  * atomic64_sub_and_test - subtract value from variable and test result
236  * @i: integer value to subtract
237  * @v: pointer to type atomic64_t
238  *
239  * Atomically subtracts @i from @v and returns
240  * true if the result is zero, or false for all
241  * other cases.
242  */
243 static inline int atomic64_sub_and_test(long i, atomic64_t *v)
244 {
245         unsigned char c;
246
247         asm volatile(LOCK_PREFIX "subq %2,%0; sete %1"
248                      : "=m" (v->counter), "=qm" (c)
249                      : "er" (i), "m" (v->counter) : "memory");
250         return c;
251 }
252
253 /**
254  * atomic64_inc - increment atomic64 variable
255  * @v: pointer to type atomic64_t
256  *
257  * Atomically increments @v by 1.
258  */
259 static inline void atomic64_inc(atomic64_t *v)
260 {
261         asm volatile(LOCK_PREFIX "incq %0"
262                      : "=m" (v->counter)
263                      : "m" (v->counter));
264 }
265
266 /**
267  * atomic64_dec - decrement atomic64 variable
268  * @v: pointer to type atomic64_t
269  *
270  * Atomically decrements @v by 1.
271  */
272 static inline void atomic64_dec(atomic64_t *v)
273 {
274         asm volatile(LOCK_PREFIX "decq %0"
275                      : "=m" (v->counter)
276                      : "m" (v->counter));
277 }
278
279 /**
280  * atomic64_dec_and_test - decrement and test
281  * @v: pointer to type atomic64_t
282  *
283  * Atomically decrements @v by 1 and
284  * returns true if the result is 0, or false for all other
285  * cases.
286  */
287 static inline int atomic64_dec_and_test(atomic64_t *v)
288 {
289         unsigned char c;
290
291         asm volatile(LOCK_PREFIX "decq %0; sete %1"
292                      : "=m" (v->counter), "=qm" (c)
293                      : "m" (v->counter) : "memory");
294         return c != 0;
295 }
296
297 /**
298  * atomic64_inc_and_test - increment and test
299  * @v: pointer to type atomic64_t
300  *
301  * Atomically increments @v by 1
302  * and returns true if the result is zero, or false for all
303  * other cases.
304  */
305 static inline int atomic64_inc_and_test(atomic64_t *v)
306 {
307         unsigned char c;
308
309         asm volatile(LOCK_PREFIX "incq %0; sete %1"
310                      : "=m" (v->counter), "=qm" (c)
311                      : "m" (v->counter) : "memory");
312         return c != 0;
313 }
314
315 /**
316  * atomic64_add_negative - add and test if negative
317  * @i: integer value to add
318  * @v: pointer to type atomic64_t
319  *
320  * Atomically adds @i to @v and returns true
321  * if the result is negative, or false when
322  * result is greater than or equal to zero.
323  */
324 static inline int atomic64_add_negative(long i, atomic64_t *v)
325 {
326         unsigned char c;
327
328         asm volatile(LOCK_PREFIX "addq %2,%0; sets %1"
329                      : "=m" (v->counter), "=qm" (c)
330                      : "er" (i), "m" (v->counter) : "memory");
331         return c;
332 }
333
334 /**
335  * atomic64_add_return - add and return
336  * @i: integer value to add
337  * @v: pointer to type atomic64_t
338  *
339  * Atomically adds @i to @v and returns @i + @v
340  */
341 static inline long atomic64_add_return(long i, atomic64_t *v)
342 {
343         long __i = i;
344         asm volatile(LOCK_PREFIX "xaddq %0, %1;"
345                      : "+r" (i), "+m" (v->counter)
346                      : : "memory");
347         return i + __i;
348 }
349
350 static inline long atomic64_sub_return(long i, atomic64_t *v)
351 {
352         return atomic64_add_return(-i, v);
353 }
354
355 #define atomic64_inc_return(v)  (atomic64_add_return(1, (v)))
356 #define atomic64_dec_return(v)  (atomic64_sub_return(1, (v)))
357
358 #define atomic64_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), (old), (new)))
359 #define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
360
361 #define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), (old), (new)))
362 #define atomic_xchg(v, new) (xchg(&((v)->counter), (new)))
363
364 /**
365  * atomic_add_unless - add unless the number is a given value
366  * @v: pointer of type atomic_t
367  * @a: the amount to add to v...
368  * @u: ...unless v is equal to u.
369  *
370  * Atomically adds @a to @v, so long as it was not @u.
371  * Returns non-zero if @v was not @u, and zero otherwise.
372  */
373 static inline int atomic_add_unless(atomic_t *v, int a, int u)
374 {
375         int c, old;
376         c = atomic_read(v);
377         for (;;) {
378                 if (unlikely(c == (u)))
379                         break;
380                 old = atomic_cmpxchg((v), c, c + (a));
381                 if (likely(old == c))
382                         break;
383                 c = old;
384         }
385         return c != (u);
386 }
387
388 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
389
390 /**
391  * atomic64_add_unless - add unless the number is a given value
392  * @v: pointer of type atomic64_t
393  * @a: the amount to add to v...
394  * @u: ...unless v is equal to u.
395  *
396  * Atomically adds @a to @v, so long as it was not @u.
397  * Returns non-zero if @v was not @u, and zero otherwise.
398  */
399 static inline int atomic64_add_unless(atomic64_t *v, long a, long u)
400 {
401         long c, old;
402         c = atomic64_read(v);
403         for (;;) {
404                 if (unlikely(c == (u)))
405                         break;
406                 old = atomic64_cmpxchg((v), c, c + (a));
407                 if (likely(old == c))
408                         break;
409                 c = old;
410         }
411         return c != (u);
412 }
413
414 /**
415  * atomic_inc_short - increment of a short integer
416  * @v: pointer to type int
417  *
418  * Atomically adds 1 to @v
419  * Returns the new value of @u
420  */
421 static inline short int atomic_inc_short(short int *v)
422 {
423         asm(LOCK_PREFIX "addw $1, %0" : "+m" (*v));
424         return *v;
425 }
426
427 /**
428  * atomic_or_long - OR of two long integers
429  * @v1: pointer to type unsigned long
430  * @v2: pointer to type unsigned long
431  *
432  * Atomically ORs @v1 and @v2
433  * Returns the result of the OR
434  */
435 static inline void atomic_or_long(unsigned long *v1, unsigned long v2)
436 {
437         asm(LOCK_PREFIX "orq %1, %0" : "+m" (*v1) : "r" (v2));
438 }
439
440 #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
441
442 /* These are x86-specific, used by some header files */
443 #define atomic_clear_mask(mask, addr)                                   \
444         asm volatile(LOCK_PREFIX "andl %0,%1"                           \
445                      : : "r" (~(mask)), "m" (*(addr)) : "memory")
446
447 #define atomic_set_mask(mask, addr)                                     \
448         asm volatile(LOCK_PREFIX "orl %0,%1"                            \
449                      : : "r" ((unsigned)(mask)), "m" (*(addr))          \
450                      : "memory")
451
452 /* Atomic operations are already serializing on x86 */
453 #define smp_mb__before_atomic_dec()     barrier()
454 #define smp_mb__after_atomic_dec()      barrier()
455 #define smp_mb__before_atomic_inc()     barrier()
456 #define smp_mb__after_atomic_inc()      barrier()
457
458 #include <asm-generic/atomic.h>
459 #endif /* _ASM_X86_ATOMIC_64_H */