8ef54dbc5e0ce87664177d6d9a4581e94ff88996
[akaros.git] / user / parlib / include / riscv / atomic.h
1 #ifndef PARLIB_ARCH_ATOMIC_H
2 #define PARLIB_ARCH_ATOMIC_H
3
4 #include <ros/common.h>
5 #include <ros/atomic.h>
6 #include <ros/arch/membar.h>
7
8 #define SPINLOCK_INITIALIZER {0}
9
10 static inline void atomic_init(atomic_t *number, long val);
11 static inline long atomic_read(atomic_t *number);
12 static inline void atomic_set(atomic_t *number, long val);
13 static inline void atomic_inc(atomic_t *number);
14 static inline void atomic_dec(atomic_t *number);
15 static inline long atomic_fetch_and_add(atomic_t *number, long val);
16 static inline long atomic_swap(atomic_t *addr, long val);
17 static inline void *atomic_swap_ptr(void **addr, void *val);
18 static inline uint32_t atomic_swap_u32(uint32_t *addr, uint32_t val);
19 static inline bool atomic_cas(atomic_t *addr, long exp_val, long new_val);
20 static inline bool atomic_cas_ptr(void **addr, void *exp_val, void *new_val);
21 static inline bool atomic_cas_u32(uint32_t *addr, uint32_t exp_val,
22                                   uint32_t new_val);
23 static inline void atomic_or_int(volatile int *number, int mask);
24
25 /* Inlined functions declared above */
26
27 static inline void atomic_init(atomic_t *number, long val)
28 {
29         *(volatile long*)number = val;
30 }
31
32 static inline long atomic_read(atomic_t *number)
33 {
34         return *(volatile long*)number;
35 }
36
37 static inline void ros_atomic_add(atomic_t *number, long inc)
38 {
39         atomic_fetch_and_add(number, inc);
40 }
41
42 static inline void atomic_set(atomic_t *number, long val)
43 {
44         atomic_init(number, val);
45 }
46
47 static inline void atomic_inc(atomic_t *number)
48 {
49         ros_atomic_add(number, 1);
50 }
51
52 static inline void atomic_dec(atomic_t *number)
53 {
54         ros_atomic_add(number, -1);
55 }
56
57 /* Adds val to number, returning number's original value */
58 static inline long atomic_fetch_and_add(atomic_t *number, long val)
59 {
60         return __sync_fetch_and_add((long*)number, val);
61 }
62
63 static inline long atomic_swap(atomic_t *addr, long val)
64 {
65         return __sync_lock_test_and_set((long*)addr, val);
66 }
67
68 static inline void *atomic_swap_ptr(void **addr, void *val)
69 {
70         return __sync_lock_test_and_set(addr, val);
71 }
72
73 static inline uint32_t atomic_swap_u32(uint32_t *addr, uint32_t val)
74 {
75         return __sync_lock_test_and_set(addr, val);
76 }
77
78 // RISC-V has atomic word ops, not byte ops, so we must manipulate addresses
79 static inline void atomic_andb(volatile uint8_t* number, uint8_t mask)
80 {
81         uintptr_t offset = (uintptr_t)number & 3;
82         uint32_t wmask = (1<<(8*offset+8)) - (1<<(8*offset));
83         wmask = ~wmask | ((uint32_t)mask << (8*offset));
84
85         __sync_fetch_and_and((uint32_t*)((uintptr_t)number & ~3), wmask);
86 }
87
88 static inline void atomic_orb(volatile uint8_t* number, uint8_t mask)
89 {
90         uintptr_t offset = (uintptr_t)number & 3;
91         uint32_t wmask = (uint32_t)mask << (8*offset);
92
93         __sync_fetch_and_or((uint32_t*)((uintptr_t)number & ~3), wmask);
94 }
95
96 static inline bool atomic_cas(atomic_t *addr, long exp_val, long new_val)
97 {
98         return __sync_bool_compare_and_swap(addr, exp_val, new_val);
99 }
100
101 static inline bool atomic_cas_ptr(void **addr, void *exp_val, void *new_val)
102 {
103         return __sync_bool_compare_and_swap(addr, exp_val, new_val);
104 }
105
106 static inline bool atomic_cas_u32(uint32_t *addr, uint32_t exp_val,
107                                   uint32_t new_val)
108 {
109         return __sync_bool_compare_and_swap(addr, exp_val, new_val);
110 }
111
112 static inline void atomic_or_int(volatile int *number, int mask)
113 {
114         __sync_fetch_and_or(number, mask);
115 }
116
117 #endif /* !PARLIB_ARCH_ATOMIC_H */