diff options
Diffstat (limited to 'arch/riscv/include/asm/atomic.h')
-rw-r--r-- | arch/riscv/include/asm/atomic.h | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/arch/riscv/include/asm/atomic.h b/arch/riscv/include/asm/atomic.h new file mode 100644 index 00000000..b79e1f89 --- /dev/null +++ b/arch/riscv/include/asm/atomic.h @@ -0,0 +1,53 @@ +#ifndef _ASM_RISCV_ATOMIC_H +#define _ASM_RISCV_ATOMIC_H + +#include <linux/types.h> +#include <asm/barrier.h> + +typedef struct { + volatile long counter; +} atomic_t; + +#define ATOMIC_INIT(_lptr, val) (_lptr)->counter = (val) + +#define ATOMIC_INITIALIZER(val) \ + { \ + .counter = (val), \ + } + +long atomic_read(atomic_t *atom) +{ + long ret = atom->counter; + rmb(); + return ret; +} + +void atomic_write(atomic_t *atom, long value) +{ + atom->counter = value; + wmb(); +} + +long atomic_add_return(atomic_t *atom, long value) +{ + long ret; +#if __SIZEOF_LONG__ == 4 + __asm__ __volatile__(" amoadd.w.aqrl %1, %2, %0" + : "+A"(atom->counter), "=r"(ret) + : "r"(value) + : "memory"); +#elif __SIZEOF_LONG__ == 8 + __asm__ __volatile__(" amoadd.d.aqrl %1, %2, %0" + : "+A"(atom->counter), "=r"(ret) + : "r"(value) + : "memory"); +#endif + return ret + value; +} + +long atomic_sub_return(atomic_t *atom, long value) +{ + return atomic_add_return(atom, -value); +} + +#endif /* _ASM_RISCV_ATOMIC_H */ |