diff options
Diffstat (limited to 'arch/x86/include/asm/atomic_32.h')
-rw-r--r-- | arch/x86/include/asm/atomic_32.h | 185 |
1 files changed, 57 insertions, 128 deletions
diff --git a/arch/x86/include/asm/atomic_32.h b/arch/x86/include/asm/atomic_32.h index 2503d4e64c2a..dc5a667ff791 100644 --- a/arch/x86/include/asm/atomic_32.h +++ b/arch/x86/include/asm/atomic_32.h | |||
@@ -19,7 +19,10 @@ | |||
19 | * | 19 | * |
20 | * Atomically reads the value of @v. | 20 | * Atomically reads the value of @v. |
21 | */ | 21 | */ |
22 | #define atomic_read(v) ((v)->counter) | 22 | static inline int atomic_read(const atomic_t *v) |
23 | { | ||
24 | return v->counter; | ||
25 | } | ||
23 | 26 | ||
24 | /** | 27 | /** |
25 | * atomic_set - set atomic variable | 28 | * atomic_set - set atomic variable |
@@ -28,7 +31,10 @@ | |||
28 | * | 31 | * |
29 | * Atomically sets the value of @v to @i. | 32 | * Atomically sets the value of @v to @i. |
30 | */ | 33 | */ |
31 | #define atomic_set(v, i) (((v)->counter) = (i)) | 34 | static inline void atomic_set(atomic_t *v, int i) |
35 | { | ||
36 | v->counter = i; | ||
37 | } | ||
32 | 38 | ||
33 | /** | 39 | /** |
34 | * atomic_add - add integer to atomic variable | 40 | * atomic_add - add integer to atomic variable |
@@ -200,8 +206,15 @@ static inline int atomic_sub_return(int i, atomic_t *v) | |||
200 | return atomic_add_return(-i, v); | 206 | return atomic_add_return(-i, v); |
201 | } | 207 | } |
202 | 208 | ||
203 | #define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), (old), (new))) | 209 | static inline int atomic_cmpxchg(atomic_t *v, int old, int new) |
204 | #define atomic_xchg(v, new) (xchg(&((v)->counter), (new))) | 210 | { |
211 | return cmpxchg(&v->counter, old, new); | ||
212 | } | ||
213 | |||
214 | static inline int atomic_xchg(atomic_t *v, int new) | ||
215 | { | ||
216 | return xchg(&v->counter, new); | ||
217 | } | ||
205 | 218 | ||
206 | /** | 219 | /** |
207 | * atomic_add_unless - add unless the number is already a given value | 220 | * atomic_add_unless - add unless the number is already a given value |
@@ -250,45 +263,12 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u) | |||
250 | /* An 64bit atomic type */ | 263 | /* An 64bit atomic type */ |
251 | 264 | ||
252 | typedef struct { | 265 | typedef struct { |
253 | unsigned long long counter; | 266 | u64 __aligned(8) counter; |
254 | } atomic64_t; | 267 | } atomic64_t; |
255 | 268 | ||
256 | #define ATOMIC64_INIT(val) { (val) } | 269 | #define ATOMIC64_INIT(val) { (val) } |
257 | 270 | ||
258 | /** | 271 | extern u64 atomic64_cmpxchg(atomic64_t *ptr, u64 old_val, u64 new_val); |
259 | * atomic64_read - read atomic64 variable | ||
260 | * @ptr: pointer of type atomic64_t | ||
261 | * | ||
262 | * Atomically reads the value of @v. | ||
263 | * Doesn't imply a read memory barrier. | ||
264 | */ | ||
265 | #define __atomic64_read(ptr) ((ptr)->counter) | ||
266 | |||
267 | static inline unsigned long long | ||
268 | cmpxchg8b(unsigned long long *ptr, unsigned long long old, unsigned long long new) | ||
269 | { | ||
270 | asm volatile( | ||
271 | |||
272 | LOCK_PREFIX "cmpxchg8b (%[ptr])\n" | ||
273 | |||
274 | : "=A" (old) | ||
275 | |||
276 | : [ptr] "D" (ptr), | ||
277 | "A" (old), | ||
278 | "b" (ll_low(new)), | ||
279 | "c" (ll_high(new)) | ||
280 | |||
281 | : "memory"); | ||
282 | |||
283 | return old; | ||
284 | } | ||
285 | |||
286 | static inline unsigned long long | ||
287 | atomic64_cmpxchg(atomic64_t *ptr, unsigned long long old_val, | ||
288 | unsigned long long new_val) | ||
289 | { | ||
290 | return cmpxchg8b(&ptr->counter, old_val, new_val); | ||
291 | } | ||
292 | 272 | ||
293 | /** | 273 | /** |
294 | * atomic64_xchg - xchg atomic64 variable | 274 | * atomic64_xchg - xchg atomic64 variable |
@@ -298,18 +278,7 @@ atomic64_cmpxchg(atomic64_t *ptr, unsigned long long old_val, | |||
298 | * Atomically xchgs the value of @ptr to @new_val and returns | 278 | * Atomically xchgs the value of @ptr to @new_val and returns |
299 | * the old value. | 279 | * the old value. |
300 | */ | 280 | */ |
301 | 281 | extern u64 atomic64_xchg(atomic64_t *ptr, u64 new_val); | |
302 | static inline unsigned long long | ||
303 | atomic64_xchg(atomic64_t *ptr, unsigned long long new_val) | ||
304 | { | ||
305 | unsigned long long old_val; | ||
306 | |||
307 | do { | ||
308 | old_val = atomic_read(ptr); | ||
309 | } while (atomic64_cmpxchg(ptr, old_val, new_val) != old_val); | ||
310 | |||
311 | return old_val; | ||
312 | } | ||
313 | 282 | ||
314 | /** | 283 | /** |
315 | * atomic64_set - set atomic64 variable | 284 | * atomic64_set - set atomic64 variable |
@@ -318,10 +287,7 @@ atomic64_xchg(atomic64_t *ptr, unsigned long long new_val) | |||
318 | * | 287 | * |
319 | * Atomically sets the value of @ptr to @new_val. | 288 | * Atomically sets the value of @ptr to @new_val. |
320 | */ | 289 | */ |
321 | static inline void atomic64_set(atomic64_t *ptr, unsigned long long new_val) | 290 | extern void atomic64_set(atomic64_t *ptr, u64 new_val); |
322 | { | ||
323 | atomic64_xchg(ptr, new_val); | ||
324 | } | ||
325 | 291 | ||
326 | /** | 292 | /** |
327 | * atomic64_read - read atomic64 variable | 293 | * atomic64_read - read atomic64 variable |
@@ -329,17 +295,30 @@ static inline void atomic64_set(atomic64_t *ptr, unsigned long long new_val) | |||
329 | * | 295 | * |
330 | * Atomically reads the value of @ptr and returns it. | 296 | * Atomically reads the value of @ptr and returns it. |
331 | */ | 297 | */ |
332 | static inline unsigned long long atomic64_read(atomic64_t *ptr) | 298 | static inline u64 atomic64_read(atomic64_t *ptr) |
333 | { | 299 | { |
334 | unsigned long long curr_val; | 300 | u64 res; |
335 | 301 | ||
336 | do { | 302 | /* |
337 | curr_val = __atomic64_read(ptr); | 303 | * Note, we inline this atomic64_t primitive because |
338 | } while (atomic64_cmpxchg(ptr, curr_val, curr_val) != curr_val); | 304 | * it only clobbers EAX/EDX and leaves the others |
339 | 305 | * untouched. We also (somewhat subtly) rely on the | |
340 | return curr_val; | 306 | * fact that cmpxchg8b returns the current 64-bit value |
307 | * of the memory location we are touching: | ||
308 | */ | ||
309 | asm volatile( | ||
310 | "mov %%ebx, %%eax\n\t" | ||
311 | "mov %%ecx, %%edx\n\t" | ||
312 | LOCK_PREFIX "cmpxchg8b %1\n" | ||
313 | : "=&A" (res) | ||
314 | : "m" (*ptr) | ||
315 | ); | ||
316 | |||
317 | return res; | ||
341 | } | 318 | } |
342 | 319 | ||
320 | extern u64 atomic64_read(atomic64_t *ptr); | ||
321 | |||
343 | /** | 322 | /** |
344 | * atomic64_add_return - add and return | 323 | * atomic64_add_return - add and return |
345 | * @delta: integer value to add | 324 | * @delta: integer value to add |
@@ -347,34 +326,14 @@ static inline unsigned long long atomic64_read(atomic64_t *ptr) | |||
347 | * | 326 | * |
348 | * Atomically adds @delta to @ptr and returns @delta + *@ptr | 327 | * Atomically adds @delta to @ptr and returns @delta + *@ptr |
349 | */ | 328 | */ |
350 | static inline unsigned long long | 329 | extern u64 atomic64_add_return(u64 delta, atomic64_t *ptr); |
351 | atomic64_add_return(unsigned long long delta, atomic64_t *ptr) | ||
352 | { | ||
353 | unsigned long long old_val, new_val; | ||
354 | |||
355 | do { | ||
356 | old_val = atomic_read(ptr); | ||
357 | new_val = old_val + delta; | ||
358 | |||
359 | } while (atomic64_cmpxchg(ptr, old_val, new_val) != old_val); | ||
360 | |||
361 | return new_val; | ||
362 | } | ||
363 | |||
364 | static inline long atomic64_sub_return(unsigned long long delta, atomic64_t *ptr) | ||
365 | { | ||
366 | return atomic64_add_return(-delta, ptr); | ||
367 | } | ||
368 | 330 | ||
369 | static inline long atomic64_inc_return(atomic64_t *ptr) | 331 | /* |
370 | { | 332 | * Other variants with different arithmetic operators: |
371 | return atomic64_add_return(1, ptr); | 333 | */ |
372 | } | 334 | extern u64 atomic64_sub_return(u64 delta, atomic64_t *ptr); |
373 | 335 | extern u64 atomic64_inc_return(atomic64_t *ptr); | |
374 | static inline long atomic64_dec_return(atomic64_t *ptr) | 336 | extern u64 atomic64_dec_return(atomic64_t *ptr); |
375 | { | ||
376 | return atomic64_sub_return(1, ptr); | ||
377 | } | ||
378 | 337 | ||
379 | /** | 338 | /** |
380 | * atomic64_add - add integer to atomic64 variable | 339 | * atomic64_add - add integer to atomic64 variable |
@@ -383,10 +342,7 @@ static inline long atomic64_dec_return(atomic64_t *ptr) | |||
383 | * | 342 | * |
384 | * Atomically adds @delta to @ptr. | 343 | * Atomically adds @delta to @ptr. |
385 | */ | 344 | */ |
386 | static inline void atomic64_add(unsigned long long delta, atomic64_t *ptr) | 345 | extern void atomic64_add(u64 delta, atomic64_t *ptr); |
387 | { | ||
388 | atomic64_add_return(delta, ptr); | ||
389 | } | ||
390 | 346 | ||
391 | /** | 347 | /** |
392 | * atomic64_sub - subtract the atomic64 variable | 348 | * atomic64_sub - subtract the atomic64 variable |
@@ -395,10 +351,7 @@ static inline void atomic64_add(unsigned long long delta, atomic64_t *ptr) | |||
395 | * | 351 | * |
396 | * Atomically subtracts @delta from @ptr. | 352 | * Atomically subtracts @delta from @ptr. |
397 | */ | 353 | */ |
398 | static inline void atomic64_sub(unsigned long long delta, atomic64_t *ptr) | 354 | extern void atomic64_sub(u64 delta, atomic64_t *ptr); |
399 | { | ||
400 | atomic64_add(-delta, ptr); | ||
401 | } | ||
402 | 355 | ||
403 | /** | 356 | /** |
404 | * atomic64_sub_and_test - subtract value from variable and test result | 357 | * atomic64_sub_and_test - subtract value from variable and test result |
@@ -409,13 +362,7 @@ static inline void atomic64_sub(unsigned long long delta, atomic64_t *ptr) | |||
409 | * true if the result is zero, or false for all | 362 | * true if the result is zero, or false for all |
410 | * other cases. | 363 | * other cases. |
411 | */ | 364 | */ |
412 | static inline int | 365 | extern int atomic64_sub_and_test(u64 delta, atomic64_t *ptr); |
413 | atomic64_sub_and_test(unsigned long long delta, atomic64_t *ptr) | ||
414 | { | ||
415 | unsigned long long old_val = atomic64_sub_return(delta, ptr); | ||
416 | |||
417 | return old_val == 0; | ||
418 | } | ||
419 | 366 | ||
420 | /** | 367 | /** |
421 | * atomic64_inc - increment atomic64 variable | 368 | * atomic64_inc - increment atomic64 variable |
@@ -423,10 +370,7 @@ atomic64_sub_and_test(unsigned long long delta, atomic64_t *ptr) | |||
423 | * | 370 | * |
424 | * Atomically increments @ptr by 1. | 371 | * Atomically increments @ptr by 1. |
425 | */ | 372 | */ |
426 | static inline void atomic64_inc(atomic64_t *ptr) | 373 | extern void atomic64_inc(atomic64_t *ptr); |
427 | { | ||
428 | atomic64_add(1, ptr); | ||
429 | } | ||
430 | 374 | ||
431 | /** | 375 | /** |
432 | * atomic64_dec - decrement atomic64 variable | 376 | * atomic64_dec - decrement atomic64 variable |
@@ -434,10 +378,7 @@ static inline void atomic64_inc(atomic64_t *ptr) | |||
434 | * | 378 | * |
435 | * Atomically decrements @ptr by 1. | 379 | * Atomically decrements @ptr by 1. |
436 | */ | 380 | */ |
437 | static inline void atomic64_dec(atomic64_t *ptr) | 381 | extern void atomic64_dec(atomic64_t *ptr); |
438 | { | ||
439 | atomic64_sub(1, ptr); | ||
440 | } | ||
441 | 382 | ||
442 | /** | 383 | /** |
443 | * atomic64_dec_and_test - decrement and test | 384 | * atomic64_dec_and_test - decrement and test |
@@ -447,10 +388,7 @@ static inline void atomic64_dec(atomic64_t *ptr) | |||
447 | * returns true if the result is 0, or false for all other | 388 | * returns true if the result is 0, or false for all other |
448 | * cases. | 389 | * cases. |
449 | */ | 390 | */ |
450 | static inline int atomic64_dec_and_test(atomic64_t *ptr) | 391 | extern int atomic64_dec_and_test(atomic64_t *ptr); |
451 | { | ||
452 | return atomic64_sub_and_test(1, ptr); | ||
453 | } | ||
454 | 392 | ||
455 | /** | 393 | /** |
456 | * atomic64_inc_and_test - increment and test | 394 | * atomic64_inc_and_test - increment and test |
@@ -460,10 +398,7 @@ static inline int atomic64_dec_and_test(atomic64_t *ptr) | |||
460 | * and returns true if the result is zero, or false for all | 398 | * and returns true if the result is zero, or false for all |
461 | * other cases. | 399 | * other cases. |
462 | */ | 400 | */ |
463 | static inline int atomic64_inc_and_test(atomic64_t *ptr) | 401 | extern int atomic64_inc_and_test(atomic64_t *ptr); |
464 | { | ||
465 | return atomic64_sub_and_test(-1, ptr); | ||
466 | } | ||
467 | 402 | ||
468 | /** | 403 | /** |
469 | * atomic64_add_negative - add and test if negative | 404 | * atomic64_add_negative - add and test if negative |
@@ -474,13 +409,7 @@ static inline int atomic64_inc_and_test(atomic64_t *ptr) | |||
474 | * if the result is negative, or false when | 409 | * if the result is negative, or false when |
475 | * result is greater than or equal to zero. | 410 | * result is greater than or equal to zero. |
476 | */ | 411 | */ |
477 | static inline int | 412 | extern int atomic64_add_negative(u64 delta, atomic64_t *ptr); |
478 | atomic64_add_negative(unsigned long long delta, atomic64_t *ptr) | ||
479 | { | ||
480 | long long old_val = atomic64_add_return(delta, ptr); | ||
481 | |||
482 | return old_val < 0; | ||
483 | } | ||
484 | 413 | ||
485 | #include <asm-generic/atomic-long.h> | 414 | #include <asm-generic/atomic-long.h> |
486 | #endif /* _ASM_X86_ATOMIC_32_H */ | 415 | #endif /* _ASM_X86_ATOMIC_32_H */ |