diff options
| author | Atish Patra <[email protected]> | 2019-08-29 15:19:12 -0700 |
|---|---|---|
| committer | Anup Patel <[email protected]> | 2019-08-31 13:13:47 +0530 |
| commit | 6bd1512024c84250a248dea37f30b71a2c4c260f (patch) | |
| tree | 9a7d0545d0f10eb85b1c3d39d68a85e64ee9cbce | |
| parent | 2e5cc9051b5daf0b164f0454e28e08c2b952089a (diff) | |
lib: Support atomic swap instructions
If compiler supports riscv atomic instructions, we should
use them instead of legacy gcc built-in macros
__sync_lock_test_and_set in atomic exchange functions.
Signed-off-by: Atish Patra <[email protected]>
Reviewed-by: Anup Patel <[email protected]>
| -rw-r--r-- | lib/sbi/riscv_atomic.c | 54 |
1 files changed, 36 insertions, 18 deletions
diff --git a/lib/sbi/riscv_atomic.c b/lib/sbi/riscv_atomic.c index 996e893e..43318640 100644 --- a/lib/sbi/riscv_atomic.c +++ b/lib/sbi/riscv_atomic.c @@ -50,6 +50,39 @@ long atomic_sub_return(atomic_t *atom, long value) return ret - value; } +#define __axchg(ptr, new, size) \ + ({ \ + __typeof__(ptr) __ptr = (ptr); \ + __typeof__(new) __new = (new); \ + __typeof__(*(ptr)) __ret; \ + switch (size) { \ + case 4: \ + __asm__ __volatile__ ( \ + " amoswap.w.aqrl %0, %2, %1\n" \ + : "=r" (__ret), "+A" (*__ptr) \ + : "r" (__new) \ + : "memory"); \ + break; \ + case 8: \ + __asm__ __volatile__ ( \ + " amoswap.d.aqrl %0, %2, %1\n" \ + : "=r" (__ret), "+A" (*__ptr) \ + : "r" (__new) \ + : "memory"); \ + break; \ + default: \ + break; \ + } \ + __ret; \ + }) + +#define axchg(ptr, x) \ + ({ \ + __typeof__(*(ptr)) _x_ = (x); \ + (__typeof__(*(ptr))) __xchg((ptr), _x_, sizeof(*(ptr))); \ + }) + + #define __xchg(ptr, new, size) \ ({ \ __typeof__(ptr) __ptr = (ptr); \ @@ -148,12 +181,7 @@ long arch_atomic_xchg(atomic_t *atom, long newval) { /* Atomically set new value and return old value. */ #ifdef __riscv_atomic - /* - * The name of GCC built-in macro __sync_lock_test_and_set() - * is misleading. A more appropriate name for GCC built-in - * macro would be __sync_val_exchange(). - */ - return __sync_lock_test_and_set(&atom->counter, newval); + return axchg(&atom->counter, newval); #else return xchg(&atom->counter, newval); #endif @@ -164,12 +192,7 @@ unsigned int atomic_raw_xchg_uint(volatile unsigned int *ptr, { /* Atomically set new value and return old value. */ #ifdef __riscv_atomic - /* - * The name of GCC built-in macro __sync_lock_test_and_set() - * is misleading. A more appropriate name for GCC built-in - * macro would be __sync_val_exchange(). - */ - return __sync_lock_test_and_set(ptr, newval); + return axchg(ptr, newval); #else return xchg(ptr, newval); #endif @@ -180,12 +203,7 @@ unsigned long atomic_raw_xchg_ulong(volatile unsigned long *ptr, { /* Atomically set new value and return old value. */ #ifdef __riscv_atomic - /* - * The name of GCC built-in macro __sync_lock_test_and_set() - * is misleading. A more appropriate name for GCC built-in - * macro would be __sync_val_exchange(). - */ - return __sync_lock_test_and_set(ptr, newval); + return axchg(ptr, newval); #else return xchg(ptr, newval); #endif |
