summaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorTom Rini <trini@kernel.crashing.org>2006-09-27 11:28:20 +0900
committerPaul Mundt <lethal@linux-sh.org>2006-09-27 11:28:20 +0900
commite4e3b5ccd77226c9c4dbb0737106b868dfc182d9 (patch)
tree8401beac23ca03f79c52094ea10139658661769d /include
parent0c91c1a7012911e4b0180a1c1ae258e2b706f987 (diff)
sh: Add a simple cmpxchg().
We didn't have one of these before, a simple implementation borrowed from MIPS as well as the __HAVE_ARCH_CMPXCHG bits. Signed-off-by: Tom Rini <trini@kernel.crashing.org> Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'include')
-rw-r--r--include/asm-sh/system.h40
1 files changed, 40 insertions, 0 deletions
diff --git a/include/asm-sh/system.h b/include/asm-sh/system.h
index ad35ad4958f..e89728d405d 100644
--- a/include/asm-sh/system.h
+++ b/include/asm-sh/system.h
@@ -6,6 +6,7 @@
* Copyright (C) 2002 Paul Mundt
*/
+#include <asm/types.h>
/*
* switch_to() should switch tasks to task nr n, first
@@ -260,6 +261,45 @@ static __inline__ unsigned long __xchg(unsigned long x, volatile void * ptr, int
return x;
}
+static inline unsigned long __cmpxchg_u32(volatile int * m, unsigned long old,
+ unsigned long new)
+{
+ __u32 retval;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ retval = *m;
+ if (retval == old)
+ *m = new;
+ local_irq_restore(flags); /* implies memory barrier */
+ return retval;
+}
+
+/* This function doesn't exist, so you'll get a linker error
+ * if something tries to do an invalid cmpxchg(). */
+extern void __cmpxchg_called_with_bad_pointer(void);
+
+#define __HAVE_ARCH_CMPXCHG 1
+
+static inline unsigned long __cmpxchg(volatile void * ptr, unsigned long old,
+ unsigned long new, int size)
+{
+ switch (size) {
+ case 4:
+ return __cmpxchg_u32(ptr, old, new);
+ }
+ __cmpxchg_called_with_bad_pointer();
+ return old;
+}
+
+#define cmpxchg(ptr,o,n) \
+ ({ \
+ __typeof__(*(ptr)) _o_ = (o); \
+ __typeof__(*(ptr)) _n_ = (n); \
+ (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_, \
+ (unsigned long)_n_, sizeof(*(ptr))); \
+ })
+
/* XXX
* disable hlt during certain critical i/o operations
*/