@@ -20,10 +20,8 @@
#include <linux/compiler.h>
#include <linux/types.h>
-#define __HAVE_ARCH_CMPXCHG 1
-
-static inline unsigned long cmpxchg_u32(volatile void *ptr,
- unsigned long old, unsigned long new)
+/* cmpxchg */
+static inline u32 cmpxchg32(volatile void *ptr, u32 old, u32 new)
{
__asm__ __volatile__(
"1: l.lwa %0, 0(%1) \n"
@@ -41,8 +39,33 @@ static inline unsigned long cmpxchg_u32(volatile void *ptr,
return old;
}
-static inline unsigned long xchg_u32(volatile void *ptr,
- unsigned long val)
+#define __cmpxchg(ptr, old, new, size) \
+({ \
+ __typeof__(ptr) __ptr = (ptr); \
+ __typeof__(*(ptr)) __old = (old); \
+ __typeof__(*(ptr)) __new = (new); \
+ __typeof__(*(ptr)) __ret; \
+ switch (size) { \
+ case 4: \
+ __ret = (__typeof__(*(ptr))) \
+ cmpxchg32(__ptr, (u32)__old, (u32)__new); \
+ break; \
+ default: \
+ BUILD_BUG(); \
+ } \
+ __ret; \
+})
+
+#define arch_cmpxchg(ptr, o, n) \
+({ \
+ __typeof__(*(ptr)) _o_ = (o); \
+ __typeof__(*(ptr)) _n_ = (n); \
+ (__typeof__(*(ptr))) __cmpxchg((ptr), \
+ _o_, _n_, sizeof(*(ptr))); \
+})
+
+/* xchg */
+static inline u32 xchg32(volatile void *ptr, u32 val)
{
__asm__ __volatile__(
"1: l.lwa %0, 0(%1) \n"
@@ -56,116 +79,26 @@ static inline unsigned long xchg_u32(volatile void *ptr,
return val;
}
-static inline u32 cmpxchg_small(volatile void *ptr, u32 old, u32 new,
- int size)
-{
- int off = (unsigned long)ptr % sizeof(u32);
- volatile u32 *p = ptr - off;
-#ifdef __BIG_ENDIAN
- int bitoff = (sizeof(u32) - size - off) * BITS_PER_BYTE;
-#else
- int bitoff = off * BITS_PER_BYTE;
-#endif
- u32 bitmask = ((0x1 << size * BITS_PER_BYTE) - 1) << bitoff;
- u32 load32, old32, new32;
- u32 ret;
-
- load32 = READ_ONCE(*p);
-
- while (true) {
- ret = (load32 & bitmask) >> bitoff;
- if (old != ret)
- return ret;
-
- old32 = (load32 & ~bitmask) | (old << bitoff);
- new32 = (load32 & ~bitmask) | (new << bitoff);
-
- /* Do 32 bit cmpxchg */
- load32 = cmpxchg_u32(p, old32, new32);
- if (load32 == old32)
- return old;
- }
-}
-
-/* xchg */
-
-static inline u32 xchg_small(volatile void *ptr, u32 x, int size)
-{
- int off = (unsigned long)ptr % sizeof(u32);
- volatile u32 *p = ptr - off;
-#ifdef __BIG_ENDIAN
- int bitoff = (sizeof(u32) - size - off) * BITS_PER_BYTE;
-#else
- int bitoff = off * BITS_PER_BYTE;
-#endif
- u32 bitmask = ((0x1 << size * BITS_PER_BYTE) - 1) << bitoff;
- u32 oldv, newv;
- u32 ret;
-
- do {
- oldv = READ_ONCE(*p);
- ret = (oldv & bitmask) >> bitoff;
- newv = (oldv & ~bitmask) | (x << bitoff);
- } while (cmpxchg_u32(p, oldv, newv) != oldv);
-
- return ret;
-}
-
-/*
- * This function doesn't exist, so you'll get a linker error
- * if something tries to do an invalid cmpxchg().
- */
-extern unsigned long __cmpxchg_called_with_bad_pointer(void)
- __compiletime_error("Bad argument size for cmpxchg");
-
-static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
- unsigned long new, int size)
-{
- switch (size) {
- case 1:
- case 2:
- return cmpxchg_small(ptr, old, new, size);
- case 4:
- return cmpxchg_u32(ptr, old, new);
- default:
- return __cmpxchg_called_with_bad_pointer();
- }
-}
-
-#define arch_cmpxchg(ptr, o, n) \
- ({ \
- (__typeof__(*(ptr))) __cmpxchg((ptr), \
- (unsigned long)(o), \
- (unsigned long)(n), \
- sizeof(*(ptr))); \
- })
-
-/*
- * This function doesn't exist, so you'll get a linker error if
- * something tries to do an invalidly-sized xchg().
- */
-extern unsigned long __xchg_called_with_bad_pointer(void)
- __compiletime_error("Bad argument size for xchg");
-
-static inline unsigned long __xchg(volatile void *ptr, unsigned long with,
- int size)
-{
- switch (size) {
- case 1:
- case 2:
- return xchg_small(ptr, with, size);
- case 4:
- return xchg_u32(ptr, with);
- default:
- return __xchg_called_with_bad_pointer();
- }
-}
-
-#define arch_xchg(ptr, with) \
- ({ \
- (__typeof__(*(ptr))) __xchg((ptr), \
- (unsigned long)(with), \
- sizeof(*(ptr))); \
- })
+#define __xchg(ptr, new, size) \
+({ \
+ __typeof__(ptr) __ptr = (ptr); \
+ __typeof__(new) __new = (new); \
+ __typeof__(*(ptr)) __ret; \
+ switch (size) { \
+ case 4: \
+ __ret = (__typeof__(*(ptr))) \
+ xchg32(__ptr, (u32)__new); \
+ break; \
+ default: \
+ BUILD_BUG(); \
+ } \
+ __ret; \
+})
+
+#define arch_xchg(ptr, x) \
+({ \
+ __typeof__(*(ptr)) _x_ = (x); \
+ (__typeof__(*(ptr))) __xchg((ptr), _x_, sizeof(*(ptr))); \
+})
#endif /* __ASM_OPENRISC_CMPXCHG_H */