|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v3 13/34] xen/riscv: introduce cmpxchg.h
The header was taken from Linux kernl 6.4.0-rc1.
Addionally, were updated:
* add emulation of {cmp}xchg for 1/2 byte types
* replace tabs with spaces
* replace __* varialbed with *__
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@xxxxxxxxx>
---
Changes in V3:
- update the commit message
- add emulation of {cmp}xchg_... for 1 and 2 bytes types
---
Changes in V2:
- update the comment at the top of the header.
- change xen/lib.h to xen/bug.h.
- sort inclusion of headers properly.
---
xen/arch/riscv/include/asm/cmpxchg.h | 496 +++++++++++++++++++++++++++
1 file changed, 496 insertions(+)
create mode 100644 xen/arch/riscv/include/asm/cmpxchg.h
diff --git a/xen/arch/riscv/include/asm/cmpxchg.h
b/xen/arch/riscv/include/asm/cmpxchg.h
new file mode 100644
index 0000000000..916776c403
--- /dev/null
+++ b/xen/arch/riscv/include/asm/cmpxchg.h
@@ -0,0 +1,496 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/* Copyright (C) 2014 Regents of the University of California */
+
+#ifndef _ASM_RISCV_CMPXCHG_H
+#define _ASM_RISCV_CMPXCHG_H
+
+#include <xen/compiler.h>
+#include <xen/lib.h>
+
+#include <asm/fence.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#define __xchg_relaxed(ptr, new, size) \
+({ \
+ __typeof__(ptr) ptr__ = (ptr); \
+ __typeof__(new) new__ = (new); \
+ __typeof__(*(ptr)) ret__; \
+ switch (size) \
+ { \
+ case 4: \
+ asm volatile( \
+ " amoswap.w %0, %2, %1\n" \
+ : "=r" (ret__), "+A" (*ptr__) \
+ : "r" (new__) \
+ : "memory" ); \
+ break; \
+ case 8: \
+ asm volatile( \
+ " amoswap.d %0, %2, %1\n" \
+ : "=r" (ret__), "+A" (*ptr__) \
+ : "r" (new__) \
+ : "memory" ); \
+ break; \
+ default: \
+ ASSERT_UNREACHABLE(); \
+ } \
+ ret__; \
+})
+
+#define xchg_relaxed(ptr, x) \
+({ \
+ __typeof__(*(ptr)) x_ = (x); \
+ (__typeof__(*(ptr))) __xchg_relaxed((ptr), x_, sizeof(*(ptr))); \
+})
+
+#define __xchg_acquire(ptr, new, size) \
+({ \
+ __typeof__(ptr) ptr__ = (ptr); \
+ __typeof__(new) new__ = (new); \
+ __typeof__(*(ptr)) ret__; \
+ switch (size) \
+ { \
+ case 4: \
+ asm volatile( \
+ " amoswap.w %0, %2, %1\n" \
+ RISCV_ACQUIRE_BARRIER \
+ : "=r" (ret__), "+A" (*ptr__) \
+ : "r" (new__) \
+ : "memory" ); \
+ break; \
+ case 8: \
+ asm volatile( \
+ " amoswap.d %0, %2, %1\n" \
+ RISCV_ACQUIRE_BARRIER \
+ : "=r" (ret__), "+A" (*ptr__) \
+ : "r" (new__) \
+ : "memory" ); \
+ break; \
+ default: \
+ ASSERT_UNREACHABLE(); \
+ } \
+ ret__; \
+})
+
+#define xchg_acquire(ptr, x) \
+({ \
+ __typeof__(*(ptr)) x_ = (x); \
+ (__typeof__(*(ptr))) __xchg_acquire((ptr), x_, sizeof(*(ptr))); \
+})
+
+#define __xchg_release(ptr, new, size) \
+({ \
+ __typeof__(ptr) ptr__ = (ptr); \
+ __typeof__(new) new__ = (new); \
+ __typeof__(*(ptr)) ret__; \
+ switch (size) \
+ { \
+ case 4: \
+ asm volatile ( \
+ RISCV_RELEASE_BARRIER \
+ " amoswap.w %0, %2, %1\n" \
+ : "=r" (ret__), "+A" (*ptr__) \
+ : "r" (new__) \
+ : "memory"); \
+ break; \
+ case 8: \
+ asm volatile ( \
+ RISCV_RELEASE_BARRIER \
+ " amoswap.d %0, %2, %1\n" \
+ : "=r" (ret__), "+A" (*ptr__) \
+ : "r" (new__) \
+ : "memory"); \
+ break; \
+ default: \
+ ASSERT_UNREACHABLE(); \
+ } \
+ ret__; \
+})
+
+#define xchg_release(ptr, x) \
+({ \
+ __typeof__(*(ptr)) x_ = (x); \
+ (__typeof__(*(ptr))) __xchg_release((ptr), x_, sizeof(*(ptr))); \
+})
+
+static always_inline uint32_t __xchg_case_4(volatile uint32_t *ptr,
+ uint32_t new)
+{
+ __typeof__(*(ptr)) ret;
+
+ asm volatile (
+ " amoswap.w.aqrl %0, %2, %1\n"
+ : "=r" (ret), "+A" (*ptr)
+ : "r" (new)
+ : "memory" );
+
+ return ret;
+}
+
+static always_inline uint64_t __xchg_case_8(volatile uint64_t *ptr,
+ uint64_t new)
+{
+ __typeof__(*(ptr)) ret;
+
+ asm volatile( \
+ " amoswap.d.aqrl %0, %2, %1\n" \
+ : "=r" (ret), "+A" (*ptr) \
+ : "r" (new) \
+ : "memory" ); \
+
+ return ret;
+}
+
+static always_inline unsigned short __cmpxchg_case_2(volatile uint32_t *ptr,
+ uint32_t old,
+ uint32_t new);
+
+static always_inline unsigned short __cmpxchg_case_1(volatile uint32_t *ptr,
+ uint32_t old,
+ uint32_t new);
+
+static inline unsigned long __xchg(volatile void *ptr, unsigned long x, int
size)
+{
+ switch (size) {
+ case 1:
+ return __cmpxchg_case_1(ptr, (uint32_t)-1, x);
+ case 2:
+ return __cmpxchg_case_2(ptr, (uint32_t)-1, x);
+ case 4:
+ return __xchg_case_4(ptr, x);
+ case 8:
+ return __xchg_case_8(ptr, x);
+ default:
+ ASSERT_UNREACHABLE();
+ }
+
+ return -1;
+}
+
+#define xchg(ptr,x) \
+({ \
+ __typeof__(*(ptr)) ret__; \
+ ret__ = (__typeof__(*(ptr))) \
+ __xchg((ptr), (unsigned long)(x), sizeof(*(ptr))); \
+ ret__; \
+})
+
+#define xchg32(ptr, x) \
+({ \
+ BUILD_BUG_ON(sizeof(*(ptr)) != 4); \
+ xchg((ptr), (x)); \
+})
+
+#define xchg64(ptr, x) \
+({ \
+ BUILD_BUG_ON(sizeof(*(ptr)) != 8); \
+ xchg((ptr), (x)); \
+})
+
+/*
+ * Atomic compare and exchange. Compare OLD with MEM, if identical,
+ * store NEW in MEM. Return the initial value in MEM. Success is
+ * indicated by comparing RETURN with OLD.
+ */
+#define __cmpxchg_relaxed(ptr, old, new, size) \
+({ \
+ __typeof__(ptr) ptr__ = (ptr); \
+ __typeof__(*(ptr)) __old = (old); \
+ __typeof__(*(ptr)) new__ = (new); \
+ __typeof__(*(ptr)) ret__; \
+ register unsigned int __rc; \
+ switch (size) \
+ { \
+ case 4: \
+ asm volatile( \
+ "0: lr.w %0, %2\n" \
+ " bne %0, %z3, 1f\n" \
+ " sc.w %1, %z4, %2\n" \
+ " bnez %1, 0b\n" \
+ "1:\n" \
+ : "=&r" (ret__), "=&r" (__rc), "+A" (*ptr__) \
+ : "rJ" (__old), "rJ" (new__) \
+ : "memory"); \
+ break; \
+ case 8: \
+ asm volatile( \
+ "0: lr.d %0, %2\n" \
+ " bne %0, %z3, 1f\n" \
+ " sc.d %1, %z4, %2\n" \
+ " bnez %1, 0b\n" \
+ "1:\n" \
+ : "=&r" (ret__), "=&r" (__rc), "+A" (*ptr__) \
+ : "rJ" (__old), "rJ" (new__) \
+ : "memory"); \
+ break; \
+ default: \
+ ASSERT_UNREACHABLE(); \
+ } \
+ ret__; \
+})
+
+#define cmpxchg_relaxed(ptr, o, n) \
+({ \
+ __typeof__(*(ptr)) o_ = (o); \
+ __typeof__(*(ptr)) n_ = (n); \
+ (__typeof__(*(ptr))) __cmpxchg_relaxed((ptr), \
+ o_, n_, sizeof(*(ptr))); \
+})
+
+#define __cmpxchg_acquire(ptr, old, new, size) \
+({ \
+ __typeof__(ptr) ptr__ = (ptr); \
+ __typeof__(*(ptr)) __old = (old); \
+ __typeof__(*(ptr)) new__ = (new); \
+ __typeof__(*(ptr)) ret__; \
+ register unsigned int __rc; \
+ switch (size) \
+ { \
+ case 4: \
+ asm volatile( \
+ "0: lr.w %0, %2\n" \
+ " bne %0, %z3, 1f\n" \
+ " sc.w %1, %z4, %2\n" \
+ " bnez %1, 0b\n" \
+ RISCV_ACQUIRE_BARRIER \
+ "1:\n" \
+ : "=&r" (ret__), "=&r" (__rc), "+A" (*ptr__) \
+ : "rJ" (__old), "rJ" (new__) \
+ : "memory"); \
+ break; \
+ case 8: \
+ asm volatile( \
+ "0: lr.d %0, %2\n" \
+ " bne %0, %z3, 1f\n" \
+ " sc.d %1, %z4, %2\n" \
+ " bnez %1, 0b\n" \
+ RISCV_ACQUIRE_BARRIER \
+ "1:\n" \
+ : "=&r" (ret__), "=&r" (__rc), "+A" (*ptr__) \
+ : "rJ" (__old), "rJ" (new__) \
+ : "memory"); \
+ break; \
+ default: \
+ ASSERT_UNREACHABLE(); \
+ } \
+ ret__; \
+})
+
+#define cmpxchg_acquire(ptr, o, n) \
+({ \
+ __typeof__(*(ptr)) o_ = (o); \
+ __typeof__(*(ptr)) n_ = (n); \
+ (__typeof__(*(ptr))) __cmpxchg_acquire((ptr), o_, n_, sizeof(*(ptr))); \
+})
+
+#define __cmpxchg_release(ptr, old, new, size) \
+({ \
+ __typeof__(ptr) ptr__ = (ptr); \
+ __typeof__(*(ptr)) __old = (old); \
+ __typeof__(*(ptr)) new__ = (new); \
+ __typeof__(*(ptr)) ret__; \
+ register unsigned int __rc; \
+ switch (size) \
+ { \
+ case 4: \
+ asm volatile ( \
+ RISCV_RELEASE_BARRIER \
+ "0: lr.w %0, %2\n" \
+ " bne %0, %z3, 1f\n" \
+ " sc.w %1, %z4, %2\n" \
+ " bnez %1, 0b\n" \
+ "1:\n" \
+ : "=&r" (ret__), "=&r" (__rc), "+A" (*ptr__) \
+ : "rJ" (__old), "rJ" (new__) \
+ : "memory" ); \
+ break; \
+ case 8: \
+ asm volatile ( \
+ RISCV_RELEASE_BARRIER \
+ "0: lr.d %0, %2\n" \
+ " bne %0, %z3, 1f\n" \
+ " sc.d %1, %z4, %2\n" \
+ " bnez %1, 0b\n" \
+ "1:\n" \
+ : "=&r" (ret__), "=&r" (__rc), "+A" (*ptr__) \
+ : "rJ" (__old), "rJ" (new__) \
+ : "memory" ); \
+ break; \
+ default: \
+ ASSERT_UNREACHABLE(); \
+ } \
+ ret__; \
+})
+
+#define cmpxchg_release(ptr, o, n) \
+({ \
+ __typeof__(*(ptr)) _o_ = (o); \
+ __typeof__(*(ptr)) _n_ = (n); \
+ (__typeof__(*(ptr))) __cmpxchg_release((ptr), _o_, _n_, sizeof(*(ptr))); \
+})
+
+static always_inline uint32_t __cmpxchg_case_4(volatile uint32_t *ptr,
+ uint32_t old,
+ uint32_t new)
+{
+ uint32_t ret;
+ register uint32_t rc;
+
+ asm volatile (
+ "0: lr.w %0, %2\n"
+ " bne %0, %z3, 1f\n"
+ " sc.w.rl %1, %z4, %2\n"
+ " bnez %1, 0b\n"
+ " fence rw, rw\n"
+ "1:\n"
+ : "=&r" (ret), "=&r" (rc), "+A" (*ptr)
+ : "rJ" (old), "rJ" (new)
+ : "memory" );
+
+ return ret;
+}
+
+static always_inline uint64_t __cmpxchg_case_8(volatile uint64_t *ptr,
+ uint64_t old,
+ uint64_t new)
+{
+ uint64_t ret;
+ register uint32_t rc;
+
+ asm volatile(
+ "0: lr.d %0, %2\n"
+ " bne %0, %z3, 1f\n"
+ " sc.d.rl %1, %z4, %2\n"
+ " bnez %1, 0b\n"
+ " fence rw, rw\n"
+ "1:\n"
+ : "=&r" (ret), "=&r" (rc), "+A" (*ptr)
+ : "rJ" (old), "rJ" (new)
+ : "memory");
+
+ return ret;
+}
+
+#define __emulate_cmpxchg_case1_2(ptr, new, read_func, cmpxchg_func,
swap_byte_mask_base)\
+({
\
+ __typeof__(*(ptr)) read_val;
\
+ __typeof__(*(ptr)) swapped_new;
\
+ __typeof__(*(ptr)) ret;
\
+ __typeof__(*(ptr)) new_ = (__typeof__(*(ptr)))new;
\
+
\
+ __typeof__(ptr) aligned_ptr = (__typeof__(ptr))((unsigned long)ptr & ~3);
\
+ __typeof__(*(ptr)) mask_off = ((unsigned long)ptr & 3) * 8;
\
+ __typeof__(*(ptr)) mask =
\
+ (__typeof__(*(ptr)))swap_byte_mask_base << mask_off;
\
+ __typeof__(*(ptr)) masked_new = (new_ << mask_off) & mask;
\
+
\
+ do {
\
+ read_val = read_func(aligned_ptr);
\
+ swapped_new = read_val & ~mask;
\
+ swapped_new |= masked_new;
\
+ ret = cmpxchg_func(aligned_ptr, read_val, swapped_new);
\
+ } while ( ret != read_val );
\
+
\
+ ret = MASK_EXTR(swapped_new, mask);
\
+ ret;
\
+})
+
+static always_inline unsigned short __cmpxchg_case_2(volatile uint32_t *ptr,
+ uint32_t old,
+ uint32_t new)
+{
+ (void) old;
+
+ if (((unsigned long)ptr & 3) == 3)
+ {
+#ifdef CONFIG_64BIT
+ return __emulate_cmpxchg_case1_2((uint64_t *)ptr, new,
+ readq, __cmpxchg_case_8, 0xffffU);
+#else
+ #error "add emulation support of cmpxchg for CONFIG_32BIT"
+#endif
+ }
+ else
+ return __emulate_cmpxchg_case1_2((uint32_t *)ptr, new,
+ readl, __cmpxchg_case_4, 0xffffU);
+}
+
+static always_inline unsigned short __cmpxchg_case_1(volatile uint32_t *ptr,
+ uint32_t old,
+ uint32_t new)
+{
+ (void) old;
+
+ return __emulate_cmpxchg_case1_2((uint32_t *)ptr, new,
+ readl, __cmpxchg_case_4, 0xffU);
+}
+
+static always_inline unsigned long __cmpxchg(volatile void *ptr,
+ unsigned long old,
+ unsigned long new,
+ int size)
+{
+ switch (size)
+ {
+ case 1:
+ return __cmpxchg_case_1(ptr, old, new);
+ case 2:
+ return __cmpxchg_case_2(ptr, old, new);
+ case 4:
+ return __cmpxchg_case_4(ptr, old, new);
+ case 8:
+ return __cmpxchg_case_8(ptr, old, new);
+ default:
+ ASSERT_UNREACHABLE();
+ }
+
+ return old;
+}
+
+#define cmpxchg(ptr, o, n) \
+({ \
+ __typeof__(*(ptr)) ret__; \
+ ret__ = (__typeof__(*(ptr))) \
+ __cmpxchg((ptr), (unsigned long)(o), (unsigned long)(n), \
+ sizeof(*(ptr))); \
+ ret__; \
+})
+
+#define cmpxchg_local(ptr, o, n) \
+ (__cmpxchg_relaxed((ptr), (o), (n), sizeof(*(ptr))))
+
+#define cmpxchg32(ptr, o, n) \
+({ \
+ BUILD_BUG_ON(sizeof(*(ptr)) != 4); \
+ cmpxchg((ptr), (o), (n)); \
+})
+
+#define cmpxchg32_local(ptr, o, n) \
+({ \
+ BUILD_BUG_ON(sizeof(*(ptr)) != 4); \
+ cmpxchg_relaxed((ptr), (o), (n)) \
+})
+
+#define cmpxchg64(ptr, o, n) \
+({ \
+ BUILD_BUG_ON(sizeof(*(ptr)) != 8); \
+ cmpxchg((ptr), (o), (n)); \
+})
+
+#define cmpxchg64_local(ptr, o, n) \
+({ \
+ BUILD_BUG_ON(sizeof(*(ptr)) != 8); \
+ cmpxchg_relaxed((ptr), (o), (n)); \
+})
+
+#endif /* _ASM_RISCV_CMPXCHG_H */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
--
2.43.0
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |