1 #ifndef _ASM_X86_ATOMIC_64_H
2 #define _ASM_X86_ATOMIC_64_H
4 #include <linux/types.h>
5 #include <asm/alternative.h>
6 #include <asm/cmpxchg.h>
9 * Atomic operations that C can't guarantee us. Useful for
10 * resource counting etc..
13 #define ATOMIC_INIT(i) { (i) }
16 * atomic_read - read atomic variable
17 * @v: pointer of type atomic_t
19 * Atomically reads the value of @v.
21 #define atomic_read(v) ((v)->counter)
24 * atomic_set - set atomic variable
25 * @v: pointer of type atomic_t
28 * Atomically sets the value of @v to @i.
30 #define atomic_set(v, i) (((v)->counter) = (i))
33 * atomic_add - add integer to atomic variable
34 * @i: integer value to add
35 * @v: pointer of type atomic_t
37 * Atomically adds @i to @v.
39 static inline void atomic_add(int i, atomic_t *v)
41 asm volatile(LOCK_PREFIX "addl %1,%0"
43 : "ir" (i), "m" (v->counter));
47 * atomic_sub - subtract the atomic variable
48 * @i: integer value to subtract
49 * @v: pointer of type atomic_t
51 * Atomically subtracts @i from @v.
53 static inline void atomic_sub(int i, atomic_t *v)
55 asm volatile(LOCK_PREFIX "subl %1,%0"
57 : "ir" (i), "m" (v->counter));
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
65 * Atomically subtracts @i from @v and returns
66 * true if the result is zero, or false for all
69 static inline int atomic_sub_and_test(int i, atomic_t *v)
73 asm volatile(LOCK_PREFIX "subl %2,%0; sete %1"
74 : "=m" (v->counter), "=qm" (c)
75 : "ir" (i), "m" (v->counter) : "memory");
80 * atomic_inc - increment atomic variable
81 * @v: pointer of type atomic_t
83 * Atomically increments @v by 1.
85 static inline void atomic_inc(atomic_t *v)
87 asm volatile(LOCK_PREFIX "incl %0"
93 * atomic_dec - decrement atomic variable
94 * @v: pointer of type atomic_t
96 * Atomically decrements @v by 1.
98 static inline void atomic_dec(atomic_t *v)
100 asm volatile(LOCK_PREFIX "decl %0"
106 * atomic_dec_and_test - decrement and test
107 * @v: pointer of type atomic_t
109 * Atomically decrements @v by 1 and
110 * returns true if the result is 0, or false for all other
113 static inline int atomic_dec_and_test(atomic_t *v)
117 asm volatile(LOCK_PREFIX "decl %0; sete %1"
118 : "=m" (v->counter), "=qm" (c)
119 : "m" (v->counter) : "memory");
124 * atomic_inc_and_test - increment and test
125 * @v: pointer of type atomic_t
127 * Atomically increments @v by 1
128 * and returns true if the result is zero, or false for all
131 static inline int atomic_inc_and_test(atomic_t *v)
135 asm volatile(LOCK_PREFIX "incl %0; sete %1"
136 : "=m" (v->counter), "=qm" (c)
137 : "m" (v->counter) : "memory");
142 * atomic_add_negative - add and test if negative
143 * @i: integer value to add
144 * @v: pointer of type atomic_t
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.
150 static inline int atomic_add_negative(int i, atomic_t *v)
154 asm volatile(LOCK_PREFIX "addl %2,%0; sets %1"
155 : "=m" (v->counter), "=qm" (c)
156 : "ir" (i), "m" (v->counter) : "memory");
161 * atomic_add_return - add and return
162 * @i: integer value to add
163 * @v: pointer of type atomic_t
165 * Atomically adds @i to @v and returns @i + @v
167 static inline int atomic_add_return(int i, atomic_t *v)
170 asm volatile(LOCK_PREFIX "xaddl %0, %1"
171 : "+r" (i), "+m" (v->counter)
176 static inline int atomic_sub_return(int i, atomic_t *v)
178 return atomic_add_return(-i, v);
181 #define atomic_inc_return(v) (atomic_add_return(1, v))
182 #define atomic_dec_return(v) (atomic_sub_return(1, v))
184 /* The 64-bit atomic type */
186 #define ATOMIC64_INIT(i) { (i) }
189 * atomic64_read - read atomic64 variable
190 * @v: pointer of type atomic64_t
192 * Atomically reads the value of @v.
193 * Doesn't imply a read memory barrier.
195 #define atomic64_read(v) ((v)->counter)
198 * atomic64_set - set atomic64 variable
199 * @v: pointer to type atomic64_t
202 * Atomically sets the value of @v to @i.
204 #define atomic64_set(v, i) (((v)->counter) = (i))
207 * atomic64_add - add integer to atomic64 variable
208 * @i: integer value to add
209 * @v: pointer to type atomic64_t
211 * Atomically adds @i to @v.
213 static inline void atomic64_add(long i, atomic64_t *v)
215 asm volatile(LOCK_PREFIX "addq %1,%0"
217 : "er" (i), "m" (v->counter));
221 * atomic64_sub - subtract the atomic64 variable
222 * @i: integer value to subtract
223 * @v: pointer to type atomic64_t
225 * Atomically subtracts @i from @v.
227 static inline void atomic64_sub(long i, atomic64_t *v)
229 asm volatile(LOCK_PREFIX "subq %1,%0"
231 : "er" (i), "m" (v->counter));
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
239 * Atomically subtracts @i from @v and returns
240 * true if the result is zero, or false for all
243 static inline int atomic64_sub_and_test(long i, atomic64_t *v)
247 asm volatile(LOCK_PREFIX "subq %2,%0; sete %1"
248 : "=m" (v->counter), "=qm" (c)
249 : "er" (i), "m" (v->counter) : "memory");
254 * atomic64_inc - increment atomic64 variable
255 * @v: pointer to type atomic64_t
257 * Atomically increments @v by 1.
259 static inline void atomic64_inc(atomic64_t *v)
261 asm volatile(LOCK_PREFIX "incq %0"
267 * atomic64_dec - decrement atomic64 variable
268 * @v: pointer to type atomic64_t
270 * Atomically decrements @v by 1.
272 static inline void atomic64_dec(atomic64_t *v)
274 asm volatile(LOCK_PREFIX "decq %0"
280 * atomic64_dec_and_test - decrement and test
281 * @v: pointer to type atomic64_t
283 * Atomically decrements @v by 1 and
284 * returns true if the result is 0, or false for all other
287 static inline int atomic64_dec_and_test(atomic64_t *v)
291 asm volatile(LOCK_PREFIX "decq %0; sete %1"
292 : "=m" (v->counter), "=qm" (c)
293 : "m" (v->counter) : "memory");
298 * atomic64_inc_and_test - increment and test
299 * @v: pointer to type atomic64_t
301 * Atomically increments @v by 1
302 * and returns true if the result is zero, or false for all
305 static inline int atomic64_inc_and_test(atomic64_t *v)
309 asm volatile(LOCK_PREFIX "incq %0; sete %1"
310 : "=m" (v->counter), "=qm" (c)
311 : "m" (v->counter) : "memory");
316 * atomic64_add_negative - add and test if negative
317 * @i: integer value to add
318 * @v: pointer to type atomic64_t
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.
324 static inline int atomic64_add_negative(long i, atomic64_t *v)
328 asm volatile(LOCK_PREFIX "addq %2,%0; sets %1"
329 : "=m" (v->counter), "=qm" (c)
330 : "er" (i), "m" (v->counter) : "memory");
335 * atomic64_add_return - add and return
336 * @i: integer value to add
337 * @v: pointer to type atomic64_t
339 * Atomically adds @i to @v and returns @i + @v
341 static inline long atomic64_add_return(long i, atomic64_t *v)
344 asm volatile(LOCK_PREFIX "xaddq %0, %1;"
345 : "+r" (i), "+m" (v->counter)
350 static inline long atomic64_sub_return(long i, atomic64_t *v)
352 return atomic64_add_return(-i, v);
355 #define atomic64_inc_return(v) (atomic64_add_return(1, (v)))
356 #define atomic64_dec_return(v) (atomic64_sub_return(1, (v)))
358 #define atomic64_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), (old), (new)))
359 #define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
361 #define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), (old), (new)))
362 #define atomic_xchg(v, new) (xchg(&((v)->counter), (new)))
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.
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.
373 static inline int atomic_add_unless(atomic_t *v, int a, int u)
378 if (unlikely(c == (u)))
380 old = atomic_cmpxchg((v), c, c + (a));
381 if (likely(old == c))
388 #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
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.
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.
399 static inline int atomic64_add_unless(atomic64_t *v, long a, long u)
402 c = atomic64_read(v);
404 if (unlikely(c == (u)))
406 old = atomic64_cmpxchg((v), c, c + (a));
407 if (likely(old == c))
415 * atomic_inc_short - increment of a short integer
416 * @v: pointer to type int
418 * Atomically adds 1 to @v
419 * Returns the new value of @u
421 static inline short int atomic_inc_short(short int *v)
423 asm(LOCK_PREFIX "addw $1, %0" : "+m" (*v));
428 * atomic_or_long - OR of two long integers
429 * @v1: pointer to type unsigned long
430 * @v2: pointer to type unsigned long
432 * Atomically ORs @v1 and @v2
433 * Returns the result of the OR
435 static inline void atomic_or_long(unsigned long *v1, unsigned long v2)
437 asm(LOCK_PREFIX "orq %1, %0" : "+m" (*v1) : "r" (v2));
440 #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0)
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")
447 #define atomic_set_mask(mask, addr) \
448 asm volatile(LOCK_PREFIX "orl %0,%1" \
449 : : "r" ((unsigned)(mask)), "m" (*(addr)) \
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()
458 #include <asm-generic/atomic.h>
459 #endif /* _ASM_X86_ATOMIC_64_H */