diff options
Diffstat (limited to 'include/asm-generic/atomic.h')
| -rw-r--r-- | include/asm-generic/atomic.h | 110 |
1 files changed, 66 insertions, 44 deletions
diff --git a/include/asm-generic/atomic.h b/include/asm-generic/atomic.h index c99c64dc5f3..9c79e760345 100644 --- a/include/asm-generic/atomic.h +++ b/include/asm-generic/atomic.h @@ -1,5 +1,7 @@ /* - * Generic C implementation of atomic counter operations + * Generic C implementation of atomic counter operations. Usable on + * UP systems only. Do not include in machine independent code. + * * Originally implemented for MN10300. * * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. @@ -13,8 +15,15 @@ #ifndef __ASM_GENERIC_ATOMIC_H #define __ASM_GENERIC_ATOMIC_H +#include <asm/cmpxchg.h> +#include <asm/barrier.h> + #ifdef CONFIG_SMP -#error not SMP safe +/* Force people to define core atomics */ +# if !defined(atomic_add_return) || !defined(atomic_sub_return) || \ + !defined(atomic_clear_mask) || !defined(atomic_set_mask) +# error "SMP requires a little arch-specific magic" +# endif #endif /* @@ -30,22 +39,22 @@ * atomic_read - read atomic variable * @v: pointer of type atomic_t * - * Atomically reads the value of @v. Note that the guaranteed - * useful range of an atomic_t is only 24 bits. + * Atomically reads the value of @v. */ -#define atomic_read(v) ((v)->counter) +#ifndef atomic_read +#define atomic_read(v) (*(volatile int *)&(v)->counter) +#endif /** * atomic_set - set atomic variable * @v: pointer of type atomic_t * @i: required value * - * Atomically sets the value of @v to @i. Note that the guaranteed - * useful range of an atomic_t is only 24 bits. + * Atomically sets the value of @v to @i. */ #define atomic_set(v, i) (((v)->counter) = (i)) -#include <asm/system.h> +#include <linux/irqflags.h> /** * atomic_add_return - add integer to atomic variable @@ -53,21 +62,22 @@ * @v: pointer of type atomic_t * * Atomically adds @i to @v and returns the result - * Note that the guaranteed useful range of an atomic_t is only 24 bits. */ +#ifndef atomic_add_return static inline int atomic_add_return(int i, atomic_t *v) { unsigned long flags; int temp; - local_irq_save(flags); + raw_local_irq_save(flags); /* Don't trace it in an irqsoff handler */ temp = v->counter; temp += i; v->counter = temp; - local_irq_restore(flags); + raw_local_irq_restore(flags); return temp; } +#endif /** * atomic_sub_return - subtract integer from atomic variable @@ -75,21 +85,22 @@ static inline int atomic_add_return(int i, atomic_t *v) * @v: pointer of type atomic_t * * Atomically subtracts @i from @v and returns the result - * Note that the guaranteed useful range of an atomic_t is only 24 bits. */ +#ifndef atomic_sub_return static inline int atomic_sub_return(int i, atomic_t *v) { unsigned long flags; int temp; - local_irq_save(flags); + raw_local_irq_save(flags); /* Don't trace it in an irqsoff handler */ temp = v->counter; temp -= i; v->counter = temp; - local_irq_restore(flags); + raw_local_irq_restore(flags); return temp; } +#endif static inline int atomic_add_negative(int i, atomic_t *v) { @@ -120,46 +131,57 @@ static inline void atomic_dec(atomic_t *v) #define atomic_inc_return(v) atomic_add_return(1, (v)) #define atomic_sub_and_test(i, v) (atomic_sub_return((i), (v)) == 0) -#define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0) -#define atomic_inc_and_test(v) (atomic_add_return(1, (v)) == 0) +#define atomic_dec_and_test(v) (atomic_dec_return(v) == 0) +#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0) -#define atomic_add_unless(v, a, u) \ -({ \ - int c, old; \ - c = atomic_read(v); \ - while (c != (u) && (old = atomic_cmpxchg((v), c, c + (a))) != c) \ - c = old; \ - c != (u); \ -}) +#define atomic_xchg(ptr, v) (xchg(&(ptr)->counter, (v))) +#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), (old), (new))) -#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) +static inline int __atomic_add_unless(atomic_t *v, int a, int u) +{ + int c, old; + c = atomic_read(v); + while (c != u && (old = atomic_cmpxchg(v, c, c + a)) != c) + c = old; + return c; +} -static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr) +/** + * atomic_clear_mask - Atomically clear bits in atomic variable + * @mask: Mask of the bits to be cleared + * @v: pointer of type atomic_t + * + * Atomically clears the bits set in @mask from @v + */ +#ifndef atomic_clear_mask +static inline void atomic_clear_mask(unsigned long mask, atomic_t *v) { unsigned long flags; mask = ~mask; - local_irq_save(flags); - *addr &= mask; - local_irq_restore(flags); + raw_local_irq_save(flags); /* Don't trace it in a irqsoff handler */ + v->counter &= mask; + raw_local_irq_restore(flags); } +#endif -#define atomic_xchg(ptr, v) (xchg(&(ptr)->counter, (v))) -#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), (old), (new))) - -#define cmpxchg_local(ptr, o, n) \ - ((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\ - (unsigned long)(n), sizeof(*(ptr)))) - -#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n)) - -/* Assume that atomic operations are already serializing */ -#define smp_mb__before_atomic_dec() barrier() -#define smp_mb__after_atomic_dec() barrier() -#define smp_mb__before_atomic_inc() barrier() -#define smp_mb__after_atomic_inc() barrier() +/** + * atomic_set_mask - Atomically set bits in atomic variable + * @mask: Mask of the bits to be set + * @v: pointer of type atomic_t + * + * Atomically sets the bits set in @mask in @v + */ +#ifndef atomic_set_mask +static inline void atomic_set_mask(unsigned int mask, atomic_t *v) +{ + unsigned long flags; -#include <asm-generic/atomic-long.h> + raw_local_irq_save(flags); /* Don't trace it in a irqsoff handler */ + v->counter |= mask; + raw_local_irq_restore(flags); +} +#endif #endif /* __KERNEL__ */ #endif /* __ASM_GENERIC_ATOMIC_H */ |
