ARM: 7404/1: cmpxchg64: use atomic64 and local64 routines for cmpxchg64
authorWill Deacon <will.deacon@arm.com>
Fri, 27 Apr 2012 11:49:16 +0000 (12:49 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Sat, 28 Apr 2012 16:32:44 +0000 (17:32 +0100)
The cmpxchg64 routines for ARMv6+ CPUs replicate inline assembly that
already exists for atomic64 operations. Furthermore, the cmpxchg64 code
uses the "memory" constraint in the clobber list rather than identifying
the region of memory that is actually modified.

This patch replaces the ARMv6+ cmpxchg64 code with macros that expand to
the atomic64_ and local64_ variants, casting the pointer parameter to
the appropriate container type.

Cc: Nicolas Pitre <nico@linaro.org>
Signed-off-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
arch/arm/include/asm/cmpxchg.h

index d41d7cbf0ada6620b9830867b6434a1284116dd4..7eb18c1d8d6cbce723b9f62c77746dad81aa11ec 100644 (file)
@@ -229,66 +229,19 @@ static inline unsigned long __cmpxchg_local(volatile void *ptr,
                                       (unsigned long)(n),              \
                                       sizeof(*(ptr))))
 
-#ifndef CONFIG_CPU_V6  /* min ARCH >= ARMv6K */
-
-/*
- * Note : ARMv7-M (currently unsupported by Linux) does not support
- * ldrexd/strexd. If ARMv7-M is ever supported by the Linux kernel, it should
- * not be allowed to use __cmpxchg64.
- */
-static inline unsigned long long __cmpxchg64(volatile void *ptr,
-                                            unsigned long long old,
-                                            unsigned long long new)
-{
-       register unsigned long long oldval asm("r0");
-       register unsigned long long __old asm("r2") = old;
-       register unsigned long long __new asm("r4") = new;
-       unsigned long res;
-
-       do {
-               asm volatile(
-               "       @ __cmpxchg8\n"
-               "       ldrexd  %1, %H1, [%2]\n"
-               "       mov     %0, #0\n"
-               "       teq     %1, %3\n"
-               "       teqeq   %H1, %H3\n"
-               "       strexdeq %0, %4, %H4, [%2]\n"
-                       : "=&r" (res), "=&r" (oldval)
-                       : "r" (ptr), "Ir" (__old), "r" (__new)
-                       : "memory", "cc");
-       } while (res);
-
-       return oldval;
-}
-
-static inline unsigned long long __cmpxchg64_mb(volatile void *ptr,
-                                               unsigned long long old,
-                                               unsigned long long new)
-{
-       unsigned long long ret;
-
-       smp_mb();
-       ret = __cmpxchg64(ptr, old, new);
-       smp_mb();
-
-       return ret;
-}
-
-#define cmpxchg64(ptr,o,n)                                             \
-       ((__typeof__(*(ptr)))__cmpxchg64_mb((ptr),                      \
-                                           (unsigned long long)(o),    \
-                                           (unsigned long long)(n)))
-
-#define cmpxchg64_local(ptr,o,n)                                       \
-       ((__typeof__(*(ptr)))__cmpxchg64((ptr),                         \
-                                        (unsigned long long)(o),       \
-                                        (unsigned long long)(n)))
-
-#else /* min ARCH = ARMv6 */
-
-#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
-
-#endif
+#define cmpxchg64(ptr, o, n)                                           \
+       ((__typeof__(*(ptr)))atomic64_cmpxchg(container_of((ptr),       \
+                                               atomic64_t,             \
+                                               counter),               \
+                                             (unsigned long)(o),       \
+                                             (unsigned long)(n)))
+
+#define cmpxchg64_local(ptr, o, n)                                     \
+       ((__typeof__(*(ptr)))local64_cmpxchg(container_of((ptr),        \
+                                               local64_t,              \
+                                               a),                     \
+                                            (unsigned long)(o),        \
+                                            (unsigned long)(n)))
 
 #endif /* __LINUX_ARM_ARCH__ >= 6 */