fixed sparc atomics; added sparc newlib
[akaros.git] / kern / arch / sparc / atomic.h
1 #ifndef ROS_INCLUDE_ATOMIC_H
2 #define ROS_INCLUDE_ATOMIC_H
3
4 #include <arch/types.h>
5
6 #define mb() {rmb(); wmb();}
7 #define rmb()
8 #define wmb() ({ asm volatile("stbar"); })
9
10 typedef volatile uint32_t spinlock_t;
11
12 // atomic_t is void*, so we can't accidentally dereference it
13 typedef void* atomic_t;
14
15 static inline void atomic_init(atomic_t* number, int32_t val);
16 static inline int32_t atomic_read(atomic_t* number);
17 static inline void atomic_set(atomic_t* number, int32_t val);
18 static inline void atomic_add(atomic_t* number, int32_t inc);
19 static inline void atomic_inc(atomic_t* number);
20 static inline void atomic_dec(atomic_t* number);
21 static inline uint32_t spin_trylock(spinlock_t*SAFE lock);
22 static inline void spin_lock(spinlock_t*SAFE lock);
23 static inline void spin_unlock(spinlock_t*SAFE lock);
24
25 /* Inlined functions declared above */
26
27 static inline void atomic_init(atomic_t* number, int32_t val)
28 {
29         val <<= 8;
30         asm volatile ("st %0,[%1]" : : "r"(val), "r"(number) : "memory");
31 }
32
33 static inline int32_t atomic_read(atomic_t* number)
34 {
35         int32_t val;
36         asm volatile ("ld [%1],%0" : "=r"(val) : "r"(number));
37         return val >> 8;
38 }
39
40 static inline void atomic_add(atomic_t* number, int32_t inc)
41 {
42         // this is pretty clever.  the lower 8 bits (i.e byte 3)
43         // of the atomic_t serve as a spinlock.  let's acquire it.
44         { TRUSTEDBLOCK spin_lock((spinlock_t*)number); }
45
46         // compute new counter value.
47         inc += atomic_read(number);
48
49         // set the new counter value.  the lock is cleared (for free)
50         atomic_init(number,inc);
51 }
52
53 static inline void atomic_set(atomic_t* number, uint32_t val)
54 {
55         // this works basically the same as atomic_add... but without the add
56         spin_lock((spinlock_t*)number);
57         atomic_init(number,val);
58 }
59
60 static inline void atomic_inc(atomic_t* number)
61 {
62         atomic_add(number,1);
63 }
64
65 static inline void atomic_dec(atomic_t* number)
66 {
67         atomic_add(number,-1);
68 }
69
70 static inline uint32_t spin_trylock(spinlock_t*SAFE lock)
71 {
72         uint32_t reg;
73         asm volatile("ldstub [%1+3],%0" : "=r"(reg) : "r"(lock) : "memory");
74         return reg;
75 }
76
77 static inline uint32_t spin_locked(spinlock_t*SAFE lock)
78 {
79         uint32_t reg;
80         asm volatile("ldub [%1+3],%0" : "=r"(reg) : "r"(lock));
81         return reg;
82 }
83
84 static inline void spin_lock(spinlock_t*SAFE lock)
85 {
86         while(spin_trylock(lock))
87                 while(spin_locked(lock));
88 }
89
90 static inline void spin_unlock(spinlock_t*SAFE lock)
91 {
92         wmb();
93         asm volatile("stub %%g0,[%0+3]" : : "r"(lock) : "memory");
94 }
95
96 #endif /* !ROS_INCLUDE_ATOMIC_H */