summaryrefslogtreecommitdiff
path: root/arch/tile/include/asm/cmpxchg.h
diff options
context:
space:
mode:
Diffstat (limited to 'arch/tile/include/asm/cmpxchg.h')
-rw-r--r--arch/tile/include/asm/cmpxchg.h134
1 files changed, 134 insertions, 0 deletions
diff --git a/arch/tile/include/asm/cmpxchg.h b/arch/tile/include/asm/cmpxchg.h
new file mode 100644
index 000000000..0ccda3c42
--- /dev/null
+++ b/arch/tile/include/asm/cmpxchg.h
@@ -0,0 +1,134 @@
+/*
+ * cmpxchg.h -- forked from asm/atomic.h with this copyright:
+ *
+ * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef _ASM_TILE_CMPXCHG_H
+#define _ASM_TILE_CMPXCHG_H
+
+#ifndef __ASSEMBLY__
+
+#include <asm/barrier.h>
+
+/* Nonexistent functions intended to cause compile errors. */
+extern void __xchg_called_with_bad_pointer(void)
+ __compiletime_error("Bad argument size for xchg");
+extern void __cmpxchg_called_with_bad_pointer(void)
+ __compiletime_error("Bad argument size for cmpxchg");
+
+#ifndef __tilegx__
+
+/* Note the _atomic_xxx() routines include a final mb(). */
+int _atomic_xchg(int *ptr, int n);
+int _atomic_xchg_add(int *v, int i);
+int _atomic_xchg_add_unless(int *v, int a, int u);
+int _atomic_cmpxchg(int *ptr, int o, int n);
+long long _atomic64_xchg(long long *v, long long n);
+long long _atomic64_xchg_add(long long *v, long long i);
+long long _atomic64_xchg_add_unless(long long *v, long long a, long long u);
+long long _atomic64_cmpxchg(long long *v, long long o, long long n);
+
+#define xchg(ptr, n) \
+ ({ \
+ if (sizeof(*(ptr)) != 4) \
+ __xchg_called_with_bad_pointer(); \
+ smp_mb(); \
+ (typeof(*(ptr)))_atomic_xchg((int *)(ptr), (int)(n)); \
+ })
+
+#define cmpxchg(ptr, o, n) \
+ ({ \
+ if (sizeof(*(ptr)) != 4) \
+ __cmpxchg_called_with_bad_pointer(); \
+ smp_mb(); \
+ (typeof(*(ptr)))_atomic_cmpxchg((int *)ptr, (int)o, \
+ (int)n); \
+ })
+
+#define xchg64(ptr, n) \
+ ({ \
+ if (sizeof(*(ptr)) != 8) \
+ __xchg_called_with_bad_pointer(); \
+ smp_mb(); \
+ (typeof(*(ptr)))_atomic64_xchg((long long *)(ptr), \
+ (long long)(n)); \
+ })
+
+#define cmpxchg64(ptr, o, n) \
+ ({ \
+ if (sizeof(*(ptr)) != 8) \
+ __cmpxchg_called_with_bad_pointer(); \
+ smp_mb(); \
+ (typeof(*(ptr)))_atomic64_cmpxchg((long long *)ptr, \
+ (long long)o, (long long)n); \
+ })
+
+#else
+
+#define xchg(ptr, n) \
+ ({ \
+ typeof(*(ptr)) __x; \
+ smp_mb(); \
+ switch (sizeof(*(ptr))) { \
+ case 4: \
+ __x = (typeof(__x))(unsigned long) \
+ __insn_exch4((ptr), \
+ (u32)(unsigned long)(n)); \
+ break; \
+ case 8: \
+ __x = (typeof(__x)) \
+ __insn_exch((ptr), (unsigned long)(n)); \
+ break; \
+ default: \
+ __xchg_called_with_bad_pointer(); \
+ break; \
+ } \
+ smp_mb(); \
+ __x; \
+ })
+
+#define cmpxchg(ptr, o, n) \
+ ({ \
+ typeof(*(ptr)) __x; \
+ __insn_mtspr(SPR_CMPEXCH_VALUE, (unsigned long)(o)); \
+ smp_mb(); \
+ switch (sizeof(*(ptr))) { \
+ case 4: \
+ __x = (typeof(__x))(unsigned long) \
+ __insn_cmpexch4((ptr), \
+ (u32)(unsigned long)(n)); \
+ break; \
+ case 8: \
+ __x = (typeof(__x))__insn_cmpexch((ptr), \
+ (long long)(n)); \
+ break; \
+ default: \
+ __cmpxchg_called_with_bad_pointer(); \
+ break; \
+ } \
+ smp_mb(); \
+ __x; \
+ })
+
+#define xchg64 xchg
+#define cmpxchg64 cmpxchg
+
+#endif
+
+#define tas(ptr) xchg((ptr), 1)
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_TILE_CMPXCHG_H */