x86: add cmpxchg16b support
authorFeng Wu <feng.wu@intel.com>
Tue, 17 Nov 2015 12:21:33 +0000 (13:21 +0100)
committerJan Beulich <jbeulich@suse.com>
Tue, 17 Nov 2015 12:21:33 +0000 (13:21 +0100)
This patch adds cmpxchg16b support for x86-64, so software
can perform 128-bit atomic write/read.

Signed-off-by: Feng Wu <feng.wu@intel.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
xen/include/asm-x86/x86_64/system.h

index 662813ad8c3376395943ef035b3cb58e91ea241f..7026c05a258c2da1c4d99a3b41d93b04d377f092 100644 (file)
@@ -5,6 +5,39 @@
     ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),            \
                                    (unsigned long)(n),sizeof(*(ptr))))
 
+/*
+ * Atomic 16 bytes 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.
+ *
+ * This function can only be called when cpu_has_cx16 is true.
+ */
+
+static always_inline __uint128_t __cmpxchg16b(
+    volatile void *ptr, const __uint128_t *old, const __uint128_t *new)
+{
+    __uint128_t prev;
+    uint64_t new_high = *new >> 64;
+    uint64_t new_low = *new;
+
+    ASSERT(cpu_has_cx16);
+
+    asm volatile ( "lock; cmpxchg16b %1"
+                   : "=A" (prev), "+m" (*__xg(ptr))
+                   : "c" (new_high), "b" (new_low),
+                     "0" (*old) );
+
+    return prev;
+}
+
+#define cmpxchg16b(ptr, o, n) ({                           \
+    volatile void *_p = (ptr);                             \
+    ASSERT(!((unsigned long)_p & 0xf));                    \
+    BUILD_BUG_ON(sizeof(*(o)) != sizeof(__uint128_t));     \
+    BUILD_BUG_ON(sizeof(*(n)) != sizeof(__uint128_t));     \
+    __cmpxchg16b(_p, (void *)(o), (void *)(n));            \
+})
+
 /*
  * This function causes value _o to be changed to _n at location _p.
  * If this access causes a fault then we return 1, otherwise we return 0.