summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhselasky <hselasky@FreeBSD.org>2018-02-25 10:38:42 +0000
committerhselasky <hselasky@FreeBSD.org>2018-02-25 10:38:42 +0000
commitf2bfceaf42ebb90232ed43f51b91537e9b77c713 (patch)
tree072baf95b50878479a18633dbece17ce9ddf7e57
parent75626e186f3c6ade1b1b9cdaba457ca863674856 (diff)
downloadFreeBSD-src-f2bfceaf42ebb90232ed43f51b91537e9b77c713.zip
FreeBSD-src-f2bfceaf42ebb90232ed43f51b91537e9b77c713.tar.gz
MFC r329523 and r329524:
Fix implementation of xchg() function macro in the LinuxKPI. The exchange operation must be atomic. Sponsored by: Mellanox Technologies
-rw-r--r--sys/compat/linuxkpi/common/include/asm/atomic.h41
1 files changed, 35 insertions, 6 deletions
diff --git a/sys/compat/linuxkpi/common/include/asm/atomic.h b/sys/compat/linuxkpi/common/include/asm/atomic.h
index 3323e7d..4b2610c 100644
--- a/sys/compat/linuxkpi/common/include/asm/atomic.h
+++ b/sys/compat/linuxkpi/common/include/asm/atomic.h
@@ -198,12 +198,41 @@ atomic_cmpxchg(atomic_t *v, int old, int new)
#define cmpxchg_relaxed(...) cmpxchg(__VA_ARGS__)
-#define xchg(ptr, v) ({ \
- __typeof(*(ptr)) __ret; \
- \
- __ret = *(ptr); \
- *(ptr) = v; \
- __ret; \
+#define xchg(ptr, new) ({ \
+ union { \
+ __typeof(*(ptr)) val; \
+ u8 u8[0]; \
+ u16 u16[0]; \
+ u32 u32[0]; \
+ u64 u64[0]; \
+ } __ret, __new = { .val = (new) }; \
+ \
+ CTASSERT(sizeof(__ret.val) == 1 || sizeof(__ret.val) == 2 || \
+ sizeof(__ret.val) == 4 || sizeof(__ret.val) == 8); \
+ \
+ switch (sizeof(__ret.val)) { \
+ case 1: \
+ __ret.val = READ_ONCE(*ptr); \
+ while (!atomic_fcmpset_8((volatile u8 *)(ptr), \
+ __ret.u8, __new.u8[0])) \
+ ; \
+ break; \
+ case 2: \
+ __ret.val = READ_ONCE(*ptr); \
+ while (!atomic_fcmpset_16((volatile u16 *)(ptr), \
+ __ret.u16, __new.u16[0])) \
+ ; \
+ break; \
+ case 4: \
+ __ret.u32[0] = atomic_swap_32((volatile u32 *)(ptr), \
+ __new.u32[0]); \
+ break; \
+ case 8: \
+ __ret.u64[0] = atomic_swap_64((volatile u64 *)(ptr), \
+ __new.u64[0]); \
+ break; \
+ } \
+ __ret.val; \
})
#define LINUX_ATOMIC_OP(op, c_op) \
OpenPOWER on IntegriCloud