Warning clean up
[akaros.git] / kern / arch / riscv / atomic.h
1 #ifndef ROS_KERN_ARCH_ATOMIC_H
2 #define ROS_KERN_ARCH_ATOMIC_H
3
4 #include <ros/common.h>
5 #include <arch/arch.h>
6
7 #ifdef __riscv64
8 # define LR_P "lr.d"
9 # define SC_P "sc.d"
10 #else
11 # define LR_P "lr.w"
12 # define SC_P "sc.w"
13 #endif
14
15 static bool atomic_cas(atomic_t *addr, long exp_val, long new_val)
16 {
17   return __sync_bool_compare_and_swap(addr, exp_val, new_val);
18 }
19
20 static bool atomic_cas_ptr(void** addr, void* exp_val, void* new_val)
21 {
22   return __sync_bool_compare_and_swap(addr, exp_val, new_val);
23 }
24
25 static bool atomic_cas_u32(uint32_t *addr, uint32_t exp_val, uint32_t new_val)
26 {
27   return __sync_bool_compare_and_swap(addr, exp_val, new_val);
28 }
29
30 static inline void atomic_init(atomic_t *number, long val)
31 {
32   *(volatile long*)number = val;
33 }
34
35 static inline long atomic_read(atomic_t *number)
36 {
37   return *(volatile long*)number;
38 }
39
40 static inline void atomic_set(atomic_t *number, long val)
41 {
42   *(volatile long*)number = val;
43 }
44
45 /* Adds val to number, returning number's original value */
46 static inline long atomic_fetch_and_add(atomic_t *number, long val)
47 {
48         return __sync_fetch_and_add((long*)number, val);
49 }
50
51 static inline void atomic_add(atomic_t *number, long val)
52 {
53         atomic_fetch_and_add(number, val);
54 }
55
56 static inline void atomic_inc(atomic_t *number)
57 {
58         atomic_add(number, 1);
59 }
60
61 static inline void atomic_dec(atomic_t *number)
62 {
63         atomic_add(number, -1);
64 }
65
66 /* Adds val to number, so long as number was not zero.  Returns TRUE if the
67  * operation succeeded (added, not zero), returns FALSE if number is zero. */
68 static inline bool atomic_add_not_zero(atomic_t *num, long inc)
69 {
70         long res, tmp;
71         asm volatile ("1:\n"
72                       LR_P " %0, 0(%2)\n"     // tmp = *num; lock line
73                       "li    %1, 1\n"         // res = 1
74                       "beqz  %0, 2f\n"        // if (val == 0) goto fail
75                       "add   %0, %0, %3\n"    // tmp += inc
76                       SC_P " %1, %0, 0(%2)\n" // if (locked) *num = tmp
77                       "bnez  %1, 1b\n"        // else goto retry
78                                   "2:\n"
79                       : "=&r"(tmp), "=&r"(res) : "r"(num), "r"(inc) : "memory");
80         return res == 0;
81 }
82
83 /* Subtraces val from number, returning True if the new value is 0. */
84 static inline bool atomic_sub_and_test(atomic_t *number, long val)
85 {
86         return __sync_fetch_and_sub((long*)number, val) == val;
87 }
88
89 static inline void atomic_and(atomic_t *number, long mask)
90 {
91         __sync_fetch_and_and(number, mask);
92 }
93
94 static inline void atomic_or(atomic_t *number, long mask)
95 {
96         __sync_fetch_and_or(number, mask);
97 }
98
99 static inline long atomic_swap(atomic_t *addr, long val)
100 {
101         return (long)__sync_lock_test_and_set(addr, val); // yes, really
102 }
103
104 static inline uint32_t atomic_swap_u32(uint32_t *addr, uint32_t val)
105 {
106         return __sync_lock_test_and_set(addr, val); // yes, really
107 }
108
109 // RISC-V has atomic word ops, not byte ops, so we must manipulate addresses
110 static inline void atomic_andb(volatile uint8_t* number, uint8_t mask)
111 {
112         uintptr_t offset = (uintptr_t)number & 3;
113         uint32_t wmask = (1<<(8*offset+8)) - (1<<(8*offset));
114         wmask = ~wmask | ((uint32_t)mask << (8*offset));
115
116         __sync_fetch_and_and((uint32_t*)((uintptr_t)number & ~3), wmask);
117 }
118
119 static inline void atomic_orb(volatile uint8_t* number, uint8_t mask)
120 {
121         uintptr_t offset = (uintptr_t)number & 3;
122         uint32_t wmask = (uint32_t)mask << (8*offset);
123
124         __sync_fetch_and_or((uint32_t*)((uintptr_t)number & ~3), wmask);
125 }
126
127 static inline bool spin_locked(spinlock_t* lock)
128 {
129         return lock->rlock;
130 }
131
132 static inline bool __spin_trylock(spinlock_t *lock)
133 {
134         return !__sync_fetch_and_or(&lock->rlock, 1);
135 }
136
137 static inline void __spin_lock(spinlock_t *lock)
138 {
139         do
140         {
141                 while (lock->rlock)
142                         ;
143         } while (!__spin_trylock(lock));
144         mb();
145 }
146
147 static inline void __spin_unlock(spinlock_t *lock)
148 {
149         mb();
150         lock->rlock = 0;
151 }
152
153 static inline void __spinlock_init(spinlock_t *lock)
154 {
155         lock->rlock = 0;
156 }
157
158 #endif /* ROS_KERN_ARCH_ATOMIC_H */