Changeset View
Changeset View
Standalone View
Standalone View
head/sys/arm64/include/atomic.h
Show First 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | |||||
#define rmb() dmb(ld) /* Full system memory barrier load */ | #define rmb() dmb(ld) /* Full system memory barrier load */ | ||||
#if defined(KCSAN) && !defined(KCSAN_RUNTIME) | #if defined(KCSAN) && !defined(KCSAN_RUNTIME) | ||||
#include <sys/_cscan_atomic.h> | #include <sys/_cscan_atomic.h> | ||||
#else | #else | ||||
#include <sys/atomic_common.h> | #include <sys/atomic_common.h> | ||||
#define _ATOMIC_OP_IMPL(t, w, s, op, asm_op, bar, a, l) \ | #define _ATOMIC_OP_PROTO(t, op, bar, flav) \ | ||||
static __inline void \ | static __inline void \ | ||||
atomic_##op##_##bar##t(volatile uint##t##_t *p, uint##t##_t val) \ | atomic_##op##_##bar##t##flav(volatile uint##t##_t *p, uint##t##_t val) | ||||
#define _ATOMIC_OP_IMPL(t, w, s, op, asm_op, bar, a, l) \ | |||||
_ATOMIC_OP_PROTO(t, op, bar, _llsc) \ | |||||
{ \ | { \ | ||||
uint##t##_t tmp; \ | uint##t##_t tmp; \ | ||||
int res; \ | int res; \ | ||||
\ | \ | ||||
__asm __volatile( \ | __asm __volatile( \ | ||||
"1: ld"#a"xr"#s" %"#w"0, [%2]\n" \ | "1: ld"#a"xr"#s" %"#w"0, [%2]\n" \ | ||||
" "#asm_op" %"#w"0, %"#w"0, %"#w"3\n" \ | " "#asm_op" %"#w"0, %"#w"0, %"#w"3\n" \ | ||||
" st"#l"xr"#s" %w1, %"#w"0, [%2]\n" \ | " st"#l"xr"#s" %w1, %"#w"0, [%2]\n" \ | ||||
" cbnz %w1, 1b\n" \ | " cbnz %w1, 1b\n" \ | ||||
: "=&r"(tmp), "=&r"(res) \ | : "=&r"(tmp), "=&r"(res) \ | ||||
: "r" (p), "r" (val) \ | : "r" (p), "r" (val) \ | ||||
: "memory" \ | : "memory" \ | ||||
); \ | ); \ | ||||
} \ | |||||
\ | |||||
_ATOMIC_OP_PROTO(t, op, bar, ) \ | |||||
{ \ | |||||
atomic_##op##_##bar##t##_llsc(p, val); \ | |||||
} | } | ||||
#define __ATOMIC_OP(op, asm_op, bar, a, l) \ | #define __ATOMIC_OP(op, asm_op, bar, a, l) \ | ||||
_ATOMIC_OP_IMPL(8, w, b, op, asm_op, bar, a, l) \ | _ATOMIC_OP_IMPL(8, w, b, op, asm_op, bar, a, l) \ | ||||
_ATOMIC_OP_IMPL(16, w, h, op, asm_op, bar, a, l) \ | _ATOMIC_OP_IMPL(16, w, h, op, asm_op, bar, a, l) \ | ||||
_ATOMIC_OP_IMPL(32, w, , op, asm_op, bar, a, l) \ | _ATOMIC_OP_IMPL(32, w, , op, asm_op, bar, a, l) \ | ||||
_ATOMIC_OP_IMPL(64, , , op, asm_op, bar, a, l) | _ATOMIC_OP_IMPL(64, , , op, asm_op, bar, a, l) | ||||
#define _ATOMIC_OP(op, asm_op) \ | #define _ATOMIC_OP(op, asm_op) \ | ||||
__ATOMIC_OP(op, asm_op, , , ) \ | __ATOMIC_OP(op, asm_op, , , ) \ | ||||
__ATOMIC_OP(op, asm_op, acq_, a, ) \ | __ATOMIC_OP(op, asm_op, acq_, a, ) \ | ||||
__ATOMIC_OP(op, asm_op, rel_, , l) | __ATOMIC_OP(op, asm_op, rel_, , l) | ||||
_ATOMIC_OP(add, add) | _ATOMIC_OP(add, add) | ||||
_ATOMIC_OP(clear, bic) | _ATOMIC_OP(clear, bic) | ||||
_ATOMIC_OP(set, orr) | _ATOMIC_OP(set, orr) | ||||
_ATOMIC_OP(subtract, sub) | _ATOMIC_OP(subtract, sub) | ||||
#define _ATOMIC_CMPSET_IMPL(t, w, s, bar, a, l) \ | #define _ATOMIC_CMPSET_PROTO(t, bar, flav) \ | ||||
static __inline int \ | static __inline int \ | ||||
atomic_cmpset_##bar##t(volatile uint##t##_t *p, uint##t##_t cmpval, \ | atomic_cmpset_##bar##t##flav(volatile uint##t##_t *p, \ | ||||
uint##t##_t newval) \ | uint##t##_t cmpval, uint##t##_t newval) | ||||
#define _ATOMIC_FCMPSET_PROTO(t, bar, flav) \ | |||||
static __inline int \ | |||||
atomic_fcmpset_##bar##t##flav(volatile uint##t##_t *p, \ | |||||
uint##t##_t *cmpval, uint##t##_t newval) | |||||
#define _ATOMIC_CMPSET_IMPL(t, w, s, bar, a, l) \ | |||||
_ATOMIC_CMPSET_PROTO(t, bar, _llsc) \ | |||||
{ \ | { \ | ||||
uint##t##_t tmp; \ | uint##t##_t tmp; \ | ||||
int res; \ | int res; \ | ||||
\ | \ | ||||
__asm __volatile( \ | __asm __volatile( \ | ||||
"1: mov %w1, #1\n" \ | "1: mov %w1, #1\n" \ | ||||
" ld"#a"xr"#s" %"#w"0, [%2]\n" \ | " ld"#a"xr"#s" %"#w"0, [%2]\n" \ | ||||
" cmp %"#w"0, %"#w"3\n" \ | " cmp %"#w"0, %"#w"3\n" \ | ||||
" b.ne 2f\n" \ | " b.ne 2f\n" \ | ||||
" st"#l"xr"#s" %w1, %"#w"4, [%2]\n" \ | " st"#l"xr"#s" %w1, %"#w"4, [%2]\n" \ | ||||
" cbnz %w1, 1b\n" \ | " cbnz %w1, 1b\n" \ | ||||
"2:" \ | "2:" \ | ||||
: "=&r"(tmp), "=&r"(res) \ | : "=&r"(tmp), "=&r"(res) \ | ||||
: "r" (p), "r" (cmpval), "r" (newval) \ | : "r" (p), "r" (cmpval), "r" (newval) \ | ||||
: "cc", "memory" \ | : "cc", "memory" \ | ||||
); \ | ); \ | ||||
\ | \ | ||||
return (!res); \ | return (!res); \ | ||||
} \ | } \ | ||||
\ | \ | ||||
static __inline int \ | _ATOMIC_CMPSET_PROTO(t, bar, ) \ | ||||
atomic_fcmpset_##bar##t(volatile uint##t##_t *p, uint##t##_t *cmpval, \ | |||||
uint##t##_t newval) \ | |||||
{ \ | { \ | ||||
return (atomic_cmpset_##bar##t##_llsc(p, cmpval, newval)); \ | |||||
} \ | |||||
\ | |||||
_ATOMIC_FCMPSET_PROTO(t, bar, _llsc) \ | |||||
{ \ | |||||
uint##t##_t _cmpval, tmp; \ | uint##t##_t _cmpval, tmp; \ | ||||
int res; \ | int res; \ | ||||
\ | \ | ||||
_cmpval = *cmpval; \ | _cmpval = *cmpval; \ | ||||
__asm __volatile( \ | __asm __volatile( \ | ||||
" mov %w1, #1\n" \ | " mov %w1, #1\n" \ | ||||
" ld"#a"xr"#s" %"#w"0, [%2]\n" \ | " ld"#a"xr"#s" %"#w"0, [%2]\n" \ | ||||
" cmp %"#w"0, %"#w"3\n" \ | " cmp %"#w"0, %"#w"3\n" \ | ||||
" b.ne 1f\n" \ | " b.ne 1f\n" \ | ||||
" st"#l"xr"#s" %w1, %"#w"4, [%2]\n" \ | " st"#l"xr"#s" %w1, %"#w"4, [%2]\n" \ | ||||
"1:" \ | "1:" \ | ||||
: "=&r"(tmp), "=&r"(res) \ | : "=&r"(tmp), "=&r"(res) \ | ||||
: "r" (p), "r" (_cmpval), "r" (newval) \ | : "r" (p), "r" (_cmpval), "r" (newval) \ | ||||
: "cc", "memory" \ | : "cc", "memory" \ | ||||
); \ | ); \ | ||||
*cmpval = tmp; \ | *cmpval = tmp; \ | ||||
\ | \ | ||||
return (!res); \ | return (!res); \ | ||||
} \ | |||||
\ | |||||
_ATOMIC_FCMPSET_PROTO(t, bar, ) \ | |||||
{ \ | |||||
return (atomic_fcmpset_##bar##t##_llsc(p, cmpval, newval)); \ | |||||
} | } | ||||
#define _ATOMIC_CMPSET(bar, a, l) \ | #define _ATOMIC_CMPSET(bar, a, l) \ | ||||
_ATOMIC_CMPSET_IMPL(8, w, b, bar, a, l) \ | _ATOMIC_CMPSET_IMPL(8, w, b, bar, a, l) \ | ||||
_ATOMIC_CMPSET_IMPL(16, w, h, bar, a, l) \ | _ATOMIC_CMPSET_IMPL(16, w, h, bar, a, l) \ | ||||
_ATOMIC_CMPSET_IMPL(32, w, , bar, a, l) \ | _ATOMIC_CMPSET_IMPL(32, w, , bar, a, l) \ | ||||
_ATOMIC_CMPSET_IMPL(64, , , bar, a, l) | _ATOMIC_CMPSET_IMPL(64, , , bar, a, l) | ||||
_ATOMIC_CMPSET( , , ) | _ATOMIC_CMPSET( , , ) | ||||
_ATOMIC_CMPSET(acq_, a, ) | _ATOMIC_CMPSET(acq_, a, ) | ||||
_ATOMIC_CMPSET(rel_, ,l) | _ATOMIC_CMPSET(rel_, ,l) | ||||
#define _ATOMIC_FETCHADD_IMPL(t, w) \ | #define _ATOMIC_FETCHADD_PROTO(t, flav) \ | ||||
static __inline uint##t##_t \ | static __inline uint##t##_t \ | ||||
atomic_fetchadd_##t(volatile uint##t##_t *p, uint##t##_t val) \ | atomic_fetchadd_##t##flav(volatile uint##t##_t *p, uint##t##_t val) | ||||
#define _ATOMIC_FETCHADD_IMPL(t, w) \ | |||||
_ATOMIC_FETCHADD_PROTO(t, _llsc) \ | |||||
{ \ | { \ | ||||
uint##t##_t tmp, ret; \ | uint##t##_t tmp, ret; \ | ||||
int res; \ | int res; \ | ||||
\ | \ | ||||
__asm __volatile( \ | __asm __volatile( \ | ||||
"1: ldxr %"#w"2, [%3]\n" \ | "1: ldxr %"#w"2, [%3]\n" \ | ||||
" add %"#w"0, %"#w"2, %"#w"4\n" \ | " add %"#w"0, %"#w"2, %"#w"4\n" \ | ||||
" stxr %w1, %"#w"0, [%3]\n" \ | " stxr %w1, %"#w"0, [%3]\n" \ | ||||
" cbnz %w1, 1b\n" \ | " cbnz %w1, 1b\n" \ | ||||
: "=&r" (tmp), "=&r" (res), "=&r" (ret) \ | : "=&r" (tmp), "=&r" (res), "=&r" (ret) \ | ||||
: "r" (p), "r" (val) \ | : "r" (p), "r" (val) \ | ||||
: "memory" \ | : "memory" \ | ||||
); \ | ); \ | ||||
\ | \ | ||||
return (ret); \ | return (ret); \ | ||||
} \ | |||||
\ | |||||
_ATOMIC_FETCHADD_PROTO(t, ) \ | |||||
{ \ | |||||
return (atomic_fetchadd_##t##_llsc(p, val)); \ | |||||
} | } | ||||
_ATOMIC_FETCHADD_IMPL(32, w) | _ATOMIC_FETCHADD_IMPL(32, w) | ||||
_ATOMIC_FETCHADD_IMPL(64, ) | _ATOMIC_FETCHADD_IMPL(64, ) | ||||
#define _ATOMIC_SWAP_IMPL(t, w, zreg) \ | #define _ATOMIC_SWAP_PROTO(t, flav) \ | ||||
static __inline uint##t##_t \ | static __inline uint##t##_t \ | ||||
atomic_swap_##t(volatile uint##t##_t *p, uint##t##_t val) \ | atomic_swap_##t##flav(volatile uint##t##_t *p, uint##t##_t val) | ||||
#define _ATOMIC_READANDCLEAR_PROTO(t, flav) \ | |||||
static __inline uint##t##_t \ | |||||
atomic_readandclear_##t##flav(volatile uint##t##_t *p) | |||||
#define _ATOMIC_SWAP_IMPL(t, w, zreg) \ | |||||
_ATOMIC_SWAP_PROTO(t, _llsc) \ | |||||
{ \ | { \ | ||||
uint##t##_t ret; \ | uint##t##_t ret; \ | ||||
int res; \ | int res; \ | ||||
\ | \ | ||||
__asm __volatile( \ | __asm __volatile( \ | ||||
"1: ldxr %"#w"1, [%2]\n" \ | "1: ldxr %"#w"1, [%2]\n" \ | ||||
" stxr %w0, %"#w"3, [%2]\n" \ | " stxr %w0, %"#w"3, [%2]\n" \ | ||||
" cbnz %w0, 1b\n" \ | " cbnz %w0, 1b\n" \ | ||||
: "=&r" (res), "=&r" (ret) \ | : "=&r" (res), "=&r" (ret) \ | ||||
: "r" (p), "r" (val) \ | : "r" (p), "r" (val) \ | ||||
: "memory" \ | : "memory" \ | ||||
); \ | ); \ | ||||
\ | \ | ||||
return (ret); \ | return (ret); \ | ||||
} \ | } \ | ||||
\ | \ | ||||
static __inline uint##t##_t \ | _ATOMIC_SWAP_PROTO(t, ) \ | ||||
atomic_readandclear_##t(volatile uint##t##_t *p) \ | |||||
{ \ | { \ | ||||
return (atomic_swap_##t##_llsc(p, val)); \ | |||||
} \ | |||||
\ | |||||
_ATOMIC_READANDCLEAR_PROTO(t, _llsc) \ | |||||
{ \ | |||||
uint##t##_t ret; \ | uint##t##_t ret; \ | ||||
int res; \ | int res; \ | ||||
\ | \ | ||||
__asm __volatile( \ | __asm __volatile( \ | ||||
"1: ldxr %"#w"1, [%2]\n" \ | "1: ldxr %"#w"1, [%2]\n" \ | ||||
" stxr %w0, "#zreg", [%2]\n" \ | " stxr %w0, "#zreg", [%2]\n" \ | ||||
" cbnz %w0, 1b\n" \ | " cbnz %w0, 1b\n" \ | ||||
: "=&r" (res), "=&r" (ret) \ | : "=&r" (res), "=&r" (ret) \ | ||||
: "r" (p) \ | : "r" (p) \ | ||||
: "memory" \ | : "memory" \ | ||||
); \ | ); \ | ||||
\ | \ | ||||
return (ret); \ | return (ret); \ | ||||
} \ | |||||
\ | |||||
_ATOMIC_READANDCLEAR_PROTO(t, ) \ | |||||
{ \ | |||||
return (atomic_readandclear_##t##_llsc(p)); \ | |||||
} | } | ||||
_ATOMIC_SWAP_IMPL(32, w, wzr) | _ATOMIC_SWAP_IMPL(32, w, wzr) | ||||
_ATOMIC_SWAP_IMPL(64, , xzr) | _ATOMIC_SWAP_IMPL(64, , xzr) | ||||
#define _ATOMIC_TEST_OP_IMPL(t, w, op, asm_op) \ | #define _ATOMIC_TEST_OP_PROTO(t, op, flav) \ | ||||
static __inline int \ | static __inline int \ | ||||
atomic_testand##op##_##t(volatile uint##t##_t *p, u_int val) \ | atomic_testand##op##_##t##flav(volatile uint##t##_t *p, u_int val) | ||||
#define _ATOMIC_TEST_OP_IMPL(t, w, op, asm_op) \ | |||||
_ATOMIC_TEST_OP_PROTO(t, op, _llsc) \ | |||||
{ \ | { \ | ||||
uint##t##_t mask, old, tmp; \ | uint##t##_t mask, old, tmp; \ | ||||
int res; \ | int res; \ | ||||
\ | \ | ||||
mask = 1u << (val & 0x1f); \ | mask = 1u << (val & 0x1f); \ | ||||
__asm __volatile( \ | __asm __volatile( \ | ||||
"1: ldxr %"#w"2, [%3]\n" \ | "1: ldxr %"#w"2, [%3]\n" \ | ||||
" "#asm_op" %"#w"0, %"#w"2, %"#w"4\n" \ | " "#asm_op" %"#w"0, %"#w"2, %"#w"4\n" \ | ||||
" stxr %w1, %"#w"0, [%3]\n" \ | " stxr %w1, %"#w"0, [%3]\n" \ | ||||
" cbnz %w1, 1b\n" \ | " cbnz %w1, 1b\n" \ | ||||
: "=&r" (tmp), "=&r" (res), "=&r" (old) \ | : "=&r" (tmp), "=&r" (res), "=&r" (old) \ | ||||
: "r" (p), "r" (mask) \ | : "r" (p), "r" (mask) \ | ||||
: "memory" \ | : "memory" \ | ||||
); \ | ); \ | ||||
\ | \ | ||||
return ((old & mask) != 0); \ | return ((old & mask) != 0); \ | ||||
} \ | |||||
\ | |||||
_ATOMIC_TEST_OP_PROTO(t, op, ) \ | |||||
{ \ | |||||
return (atomic_testand##op##_##t##_llsc(p, val)); \ | |||||
} | } | ||||
#define _ATOMIC_TEST_OP(op, asm_op) \ | #define _ATOMIC_TEST_OP(op, asm_op) \ | ||||
_ATOMIC_TEST_OP_IMPL(32, w, op, asm_op) \ | _ATOMIC_TEST_OP_IMPL(32, w, op, asm_op) \ | ||||
_ATOMIC_TEST_OP_IMPL(64, , op, asm_op) | _ATOMIC_TEST_OP_IMPL(64, , op, asm_op) | ||||
_ATOMIC_TEST_OP(clear, bic) | _ATOMIC_TEST_OP(clear, bic) | ||||
_ATOMIC_TEST_OP(set, orr) | _ATOMIC_TEST_OP(set, orr) | ||||
▲ Show 20 Lines • Show All 140 Lines • ▼ Show 20 Lines | |||||
static __inline void | static __inline void | ||||
atomic_thread_fence_seq_cst(void) | atomic_thread_fence_seq_cst(void) | ||||
{ | { | ||||
dmb(sy); | dmb(sy); | ||||
} | } | ||||
#endif /* KCSAN && !KCSAN_RUNTIME */ | #endif /* KCSAN && !KCSAN_RUNTIME */ | ||||
#endif /* _MACHINE_ATOMIC_H_ */ | #endif /* _MACHINE_ATOMIC_H_ */ |