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