aboutsummaryrefslogtreecommitdiff
path: root/include/asm-generic/atomic.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/asm-generic/atomic.h')
-rw-r--r--include/asm-generic/atomic.h343
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 */