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