diff options
Diffstat (limited to 'include/asm-generic/atomic.h')
| -rw-r--r-- | include/asm-generic/atomic.h | 343 |
1 files changed, 136 insertions, 207 deletions
diff --git a/include/asm-generic/atomic.h b/include/asm-generic/atomic.h index 85fd0aa27a8..9c79e760345 100644 --- a/include/asm-generic/atomic.h +++ b/include/asm-generic/atomic.h @@ -1,258 +1,187 @@ -#ifndef _ASM_GENERIC_ATOMIC_H -#define _ASM_GENERIC_ATOMIC_H /* - * Copyright (C) 2005 Silicon Graphics, Inc. - * Christoph Lameter <clameter@sgi.com> + * Generic C implementation of atomic counter operations. Usable on + * UP systems only. Do not include in machine independent code. * - * Allows to provide arch independent atomic definitions without the need to - * edit all arch specific atomic.h files. - */ - -#include <asm/types.h> - -/* - * Suppport for atomic_long_t + * Originally implemented for MN10300. * - * Casts for parameters are avoided for existing atomic functions in order to - * avoid issues with cast-as-lval under gcc 4.x and other limitations that the - * macros of a platform may have. + * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. */ +#ifndef __ASM_GENERIC_ATOMIC_H +#define __ASM_GENERIC_ATOMIC_H -#if BITS_PER_LONG == 64 - -typedef atomic64_t atomic_long_t; - -#define ATOMIC_LONG_INIT(i) ATOMIC64_INIT(i) - -static inline long atomic_long_read(atomic_long_t *l) -{ - atomic64_t *v = (atomic64_t *)l; - - return (long)atomic64_read(v); -} - -static inline void atomic_long_set(atomic_long_t *l, long i) -{ - atomic64_t *v = (atomic64_t *)l; - - atomic64_set(v, i); -} - -static inline void atomic_long_inc(atomic_long_t *l) -{ - atomic64_t *v = (atomic64_t *)l; - - atomic64_inc(v); -} - -static inline void atomic_long_dec(atomic_long_t *l) -{ - atomic64_t *v = (atomic64_t *)l; - - atomic64_dec(v); -} - -static inline void atomic_long_add(long i, atomic_long_t *l) -{ - atomic64_t *v = (atomic64_t *)l; - - atomic64_add(i, v); -} - -static inline void atomic_long_sub(long i, atomic_long_t *l) -{ - atomic64_t *v = (atomic64_t *)l; - - atomic64_sub(i, v); -} - -static inline int atomic_long_sub_and_test(long i, atomic_long_t *l) -{ - atomic64_t *v = (atomic64_t *)l; - - return atomic64_sub_and_test(i, v); -} - -static inline int atomic_long_dec_and_test(atomic_long_t *l) -{ - atomic64_t *v = (atomic64_t *)l; - - return atomic64_dec_and_test(v); -} +#include <asm/cmpxchg.h> +#include <asm/barrier.h> -static inline int atomic_long_inc_and_test(atomic_long_t *l) -{ - atomic64_t *v = (atomic64_t *)l; - - return atomic64_inc_and_test(v); -} - -static inline int atomic_long_add_negative(long i, atomic_long_t *l) -{ - atomic64_t *v = (atomic64_t *)l; - - return atomic64_add_negative(i, v); -} - -static inline long atomic_long_add_return(long i, atomic_long_t *l) -{ - atomic64_t *v = (atomic64_t *)l; - - return (long)atomic64_add_return(i, v); -} - -static inline long atomic_long_sub_return(long i, atomic_long_t *l) -{ - atomic64_t *v = (atomic64_t *)l; +#ifdef CONFIG_SMP +/* 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 - return (long)atomic64_sub_return(i, v); -} - -static inline long atomic_long_inc_return(atomic_long_t *l) -{ - atomic64_t *v = (atomic64_t *)l; - - return (long)atomic64_inc_return(v); -} - -static inline long atomic_long_dec_return(atomic_long_t *l) -{ - atomic64_t *v = (atomic64_t *)l; - - return (long)atomic64_dec_return(v); -} - -static inline long atomic_long_add_unless(atomic_long_t *l, long a, long u) -{ - atomic64_t *v = (atomic64_t *)l; - - return (long)atomic64_add_unless(v, a, u); -} +/* + * Atomic operations that C can't guarantee us. Useful for + * resource counting etc.. + */ -#define atomic_long_inc_not_zero(l) atomic64_inc_not_zero((atomic64_t *)(l)) +#define ATOMIC_INIT(i) { (i) } -#define atomic_long_cmpxchg(l, old, new) \ - (atomic_cmpxchg((atomic64_t *)(l), (old), (new))) -#define atomic_long_xchg(v, new) \ - (atomic_xchg((atomic64_t *)(l), (new))) +#ifdef __KERNEL__ -#else /* BITS_PER_LONG == 64 */ +/** + * atomic_read - read atomic variable + * @v: pointer of type atomic_t + * + * Atomically reads the value of @v. + */ +#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. + */ +#define atomic_set(v, i) (((v)->counter) = (i)) -typedef atomic_t atomic_long_t; +#include <linux/irqflags.h> -#define ATOMIC_LONG_INIT(i) ATOMIC_INIT(i) -static inline long atomic_long_read(atomic_long_t *l) +/** + * atomic_add_return - add integer to atomic variable + * @i: integer value to add + * @v: pointer of type atomic_t + * + * Atomically adds @i to @v and returns the result + */ +#ifndef atomic_add_return +static inline int atomic_add_return(int i, atomic_t *v) { - atomic_t *v = (atomic_t *)l; - - return (long)atomic_read(v); -} + unsigned long flags; + int temp; -static inline void atomic_long_set(atomic_long_t *l, long i) -{ - atomic_t *v = (atomic_t *)l; + raw_local_irq_save(flags); /* Don't trace it in an irqsoff handler */ + temp = v->counter; + temp += i; + v->counter = temp; + raw_local_irq_restore(flags); - atomic_set(v, i); + return temp; } +#endif -static inline void atomic_long_inc(atomic_long_t *l) -{ - atomic_t *v = (atomic_t *)l; - - atomic_inc(v); -} - -static inline void atomic_long_dec(atomic_long_t *l) +/** + * atomic_sub_return - subtract integer from atomic variable + * @i: integer value to subtract + * @v: pointer of type atomic_t + * + * Atomically subtracts @i from @v and returns the result + */ +#ifndef atomic_sub_return +static inline int atomic_sub_return(int i, atomic_t *v) { - atomic_t *v = (atomic_t *)l; + unsigned long flags; + int temp; - atomic_dec(v); -} - -static inline void atomic_long_add(long i, atomic_long_t *l) -{ - atomic_t *v = (atomic_t *)l; + raw_local_irq_save(flags); /* Don't trace it in an irqsoff handler */ + temp = v->counter; + temp -= i; + v->counter = temp; + raw_local_irq_restore(flags); - atomic_add(i, v); + return temp; } +#endif -static inline void atomic_long_sub(long i, atomic_long_t *l) +static inline int atomic_add_negative(int i, atomic_t *v) { - atomic_t *v = (atomic_t *)l; - - atomic_sub(i, v); + return atomic_add_return(i, v) < 0; } -static inline int atomic_long_sub_and_test(long i, atomic_long_t *l) +static inline void atomic_add(int i, atomic_t *v) { - atomic_t *v = (atomic_t *)l; - - return atomic_sub_and_test(i, v); + atomic_add_return(i, v); } -static inline int atomic_long_dec_and_test(atomic_long_t *l) +static inline void atomic_sub(int i, atomic_t *v) { - atomic_t *v = (atomic_t *)l; - - return atomic_dec_and_test(v); + atomic_sub_return(i, v); } -static inline int atomic_long_inc_and_test(atomic_long_t *l) +static inline void atomic_inc(atomic_t *v) { - atomic_t *v = (atomic_t *)l; - - return atomic_inc_and_test(v); + atomic_add_return(1, v); } -static inline int atomic_long_add_negative(long i, atomic_long_t *l) +static inline void atomic_dec(atomic_t *v) { - atomic_t *v = (atomic_t *)l; - - return atomic_add_negative(i, v); + atomic_sub_return(1, v); } -static inline long atomic_long_add_return(long i, atomic_long_t *l) -{ - atomic_t *v = (atomic_t *)l; +#define atomic_dec_return(v) atomic_sub_return(1, (v)) +#define atomic_inc_return(v) atomic_add_return(1, (v)) - return (long)atomic_add_return(i, v); -} - -static inline long atomic_long_sub_return(long i, atomic_long_t *l) -{ - atomic_t *v = (atomic_t *)l; +#define atomic_sub_and_test(i, v) (atomic_sub_return((i), (v)) == 0) +#define atomic_dec_and_test(v) (atomic_dec_return(v) == 0) +#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0) - return (long)atomic_sub_return(i, v); -} +#define atomic_xchg(ptr, v) (xchg(&(ptr)->counter, (v))) +#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), (old), (new))) -static inline long atomic_long_inc_return(atomic_long_t *l) +static inline int __atomic_add_unless(atomic_t *v, int a, int u) { - atomic_t *v = (atomic_t *)l; - - return (long)atomic_inc_return(v); + int c, old; + c = atomic_read(v); + while (c != u && (old = atomic_cmpxchg(v, c, c + a)) != c) + c = old; + return c; } -static inline long atomic_long_dec_return(atomic_long_t *l) +/** + * 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) { - atomic_t *v = (atomic_t *)l; + unsigned long flags; - return (long)atomic_dec_return(v); + mask = ~mask; + raw_local_irq_save(flags); /* Don't trace it in a irqsoff handler */ + v->counter &= mask; + raw_local_irq_restore(flags); } +#endif -static inline long atomic_long_add_unless(atomic_long_t *l, long a, long u) +/** + * 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) { - atomic_t *v = (atomic_t *)l; + unsigned long flags; - return (long)atomic_add_unless(v, a, u); + raw_local_irq_save(flags); /* Don't trace it in a irqsoff handler */ + v->counter |= mask; + raw_local_irq_restore(flags); } +#endif -#define atomic_long_inc_not_zero(l) atomic_inc_not_zero((atomic_t *)(l)) - -#define atomic_long_cmpxchg(l, old, new) \ - (atomic_cmpxchg((atomic_t *)(l), (old), (new))) -#define atomic_long_xchg(v, new) \ - (atomic_xchg((atomic_t *)(l), (new))) - -#endif /* BITS_PER_LONG == 64 */ - -#endif /* _ASM_GENERIC_ATOMIC_H */ +#endif /* __KERNEL__ */ +#endif /* __ASM_GENERIC_ATOMIC_H */ |
