Made c99 compatibility changes
[akaros.git] / kern / arch / sparc / atomic.h
1 #ifndef ROS_INCLUDE_ATOMIC_H
2 #define ROS_INCLUDE_ATOMIC_H
3
4 #include <ros/common.h>
5
6 #define mb() {rmb(); wmb();}
7 #define rmb()
8 #define wmb() ({ __asm__ __volatile__ ("stbar"); })
9 /* Force a wmb, used in cases where an IPI could beat a write, even though
10  * write-orderings are respected.  (Used by x86) */
11 #define wmb_f() wmb()
12
13 typedef struct
14 {
15         volatile uint32_t rlock;
16 } spinlock_t;
17
18 #define SPINLOCK_INITIALIZER {0}
19
20 // atomic_t is void*, so we can't accidentally dereference it
21 typedef void* atomic_t;
22
23 static inline void atomic_init(atomic_t* number, int32_t val);
24 static inline int32_t atomic_read(atomic_t* number);
25 static inline void atomic_set(atomic_t* number, int32_t val);
26 static inline void atomic_add(atomic_t* number, int32_t inc);
27 static inline void atomic_inc(atomic_t* number);
28 static inline void atomic_dec(atomic_t* number);
29 static inline uint32_t atomic_swap(uint32_t* addr, uint32_t val);
30 static inline uint32_t spin_trylock(spinlock_t*SAFE lock);
31 static inline uint32_t spin_locked(spinlock_t*SAFE lock);
32 static inline void spin_lock(spinlock_t*SAFE lock);
33 static inline void spin_unlock(spinlock_t*SAFE lock);
34
35 /* Inlined functions declared above */
36
37 static inline void atomic_init(atomic_t* number, int32_t val)
38 {
39         val <<= 8;
40         __asm__ __volatile__ ("st %0,[%1]" : : "r"(val), "r"(number) : "memory");
41 }
42
43 static inline int32_t atomic_read(atomic_t* number)
44 {
45         int32_t val;
46         __asm__ __volatile__ ("ld [%1],%0" : "=r"(val) : "r"(number));
47         return val >> 8;
48 }
49
50 static inline void atomic_add(atomic_t* number, int32_t inc)
51 {
52         // this is pretty clever.  the lower 8 bits (i.e byte 3)
53         // of the atomic_t serve as a spinlock.  let's acquire it.
54         { TRUSTEDBLOCK spin_lock((spinlock_t*)number); }
55
56         // compute new counter value.
57         inc += atomic_read(number);
58
59         // set the new counter value.  the lock is cleared (for free)
60         atomic_init(number,inc);
61 }
62
63 static inline void atomic_set(atomic_t* number, int32_t val)
64 {
65         // this works basically the same as atomic_add... but without the add
66         spin_lock((spinlock_t*)number);
67         atomic_init(number,val);
68 }
69
70 static inline void atomic_inc(atomic_t* number)
71 {
72         atomic_add(number,1);
73 }
74
75 static inline void atomic_dec(atomic_t* number)
76 {
77         atomic_add(number,-1);
78 }
79
80 static inline uint32_t atomic_swap(uint32_t* addr, uint32_t val)
81 {
82         __asm__ __volatile__ ("swap [%2],%0" : "=r"(val) : "0"(val),"r"(addr) : "memory");
83         return val;
84 }
85
86 static inline uint32_t spin_trylock(spinlock_t*SAFE lock)
87 {
88         uint32_t reg;
89         __asm__ __volatile__ ("ldstub [%1+3],%0" : "=r"(reg) : "r"(&lock->rlock) : "memory");
90         return reg;
91 }
92
93 static inline uint32_t spin_locked(spinlock_t*SAFE lock)
94 {
95         uint32_t reg;
96         __asm__ __volatile__ ("ldub [%1+3],%0" : "=r"(reg) : "r"(&lock->rlock));
97         return reg;
98 }
99
100 static inline void spin_lock(spinlock_t*SAFE lock)
101 {
102         while(spin_trylock(lock))
103                 while(spin_locked(lock));
104 }
105
106 static inline void spin_unlock(spinlock_t*SAFE lock)
107 {
108         wmb();
109         __asm__ __volatile__ ("stub %%g0,[%0+3]" : : "r"(&lock->rlock) : "memory");
110 }
111
112 static inline void spinlock_init(spinlock_t* lock)
113 {
114         lock->rlock = 0;
115 }
116
117 static inline void spinlock_debug(spinlock_t* lock)
118 {
119 }
120
121 #endif /* !ROS_INCLUDE_ATOMIC_H */