diff options
author | hselasky <hselasky@FreeBSD.org> | 2018-02-25 10:38:42 +0000 |
---|---|---|
committer | hselasky <hselasky@FreeBSD.org> | 2018-02-25 10:38:42 +0000 |
commit | f2bfceaf42ebb90232ed43f51b91537e9b77c713 (patch) | |
tree | 072baf95b50878479a18633dbece17ce9ddf7e57 | |
parent | 75626e186f3c6ade1b1b9cdaba457ca863674856 (diff) | |
download | FreeBSD-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.h | 41 |
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) \ |