improve risc-v console
[akaros.git] / kern / arch / riscv / atomic.c
1 #include <atomic.h>
2
3 // This emulates compare and swap by hashing the address into one of
4 // K buckets, acquiring the lock for that bucket, then performing the
5 // operation during the critical section.  :-(
6 bool atomic_cas(atomic_t *addr, long exp_val, long new_val)
7 {
8         if ((long)*addr != exp_val)
9                 return 0;
10         
11   #define K 17
12         static spinlock_t cas_locks[K*HW_CACHE_ALIGN/sizeof(spinlock_t)];
13
14   uintptr_t bucket = (uintptr_t)addr / sizeof(uintptr_t) % K;
15         spinlock_t* lock = &cas_locks[bucket*HW_CACHE_ALIGN/sizeof(spinlock_t)];
16         
17         bool retval = 0;
18         spin_lock_irqsave(lock);
19         if ((long)*addr == exp_val) {
20                 atomic_swap(addr, new_val);
21                 retval = 1;
22         }
23         spin_unlock_irqsave(lock);
24         return retval;
25 }
26
27 bool atomic_cas_ptr(void **addr, void *exp_val, void *new_val)
28 {
29         return atomic_cas((atomic_t*)addr, (long)exp_val, (long)new_val);
30 }
31
32 /* Ghetto, copied the regular CAS code... */
33 bool atomic_cas_u32(uint32_t *addr, uint32_t exp_val, uint32_t new_val)
34 {
35         if (*addr != exp_val)
36                 return 0;
37         
38   #define K 17
39         static spinlock_t cas_locks[K*HW_CACHE_ALIGN/sizeof(spinlock_t)];
40
41   uintptr_t bucket = (uintptr_t)addr / sizeof(uintptr_t) % K;
42         spinlock_t* lock = &cas_locks[bucket*HW_CACHE_ALIGN/sizeof(spinlock_t)];
43         
44         bool retval = 0;
45         spin_lock_irqsave(lock);
46         if (*addr == exp_val) {
47                 atomic_swap_u32(addr, new_val);
48                 retval = 1;
49         }
50         spin_unlock_irqsave(lock);
51         return retval;
52 }