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