[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




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.