Merge /spare/repo/linux-2.6/
[linux-2.6] / include / asm-alpha / spinlock.h
1 #ifndef _ALPHA_SPINLOCK_H
2 #define _ALPHA_SPINLOCK_H
3
4 #include <linux/config.h>
5 #include <asm/system.h>
6 #include <linux/kernel.h>
7 #include <asm/current.h>
8
9
10 /*
11  * Simple spin lock operations.  There are two variants, one clears IRQ's
12  * on the local processor, one does not.
13  *
14  * We make no fairness assumptions. They have a cost.
15  */
16
17 typedef struct {
18         volatile unsigned int lock;
19 #ifdef CONFIG_DEBUG_SPINLOCK
20         int on_cpu;
21         int line_no;
22         void *previous;
23         struct task_struct * task;
24         const char *base_file;
25 #endif
26 } spinlock_t;
27
28 #ifdef CONFIG_DEBUG_SPINLOCK
29 #define SPIN_LOCK_UNLOCKED      (spinlock_t){ 0, -1, 0, NULL, NULL, NULL }
30 #else
31 #define SPIN_LOCK_UNLOCKED      (spinlock_t){ 0 }
32 #endif
33
34 #define spin_lock_init(x)       do { *(x) = SPIN_LOCK_UNLOCKED; } while(0)
35 #define spin_is_locked(x)       ((x)->lock != 0)
36 #define spin_unlock_wait(x)     do { barrier(); } while ((x)->lock)
37
38 #ifdef CONFIG_DEBUG_SPINLOCK
39 extern void _raw_spin_unlock(spinlock_t * lock);
40 extern void debug_spin_lock(spinlock_t * lock, const char *, int);
41 extern int debug_spin_trylock(spinlock_t * lock, const char *, int);
42 #define _raw_spin_lock(LOCK) \
43         debug_spin_lock(LOCK, __BASE_FILE__, __LINE__)
44 #define _raw_spin_trylock(LOCK) \
45         debug_spin_trylock(LOCK, __BASE_FILE__, __LINE__)
46 #else
47 static inline void _raw_spin_unlock(spinlock_t * lock)
48 {
49         mb();
50         lock->lock = 0;
51 }
52
53 static inline void _raw_spin_lock(spinlock_t * lock)
54 {
55         long tmp;
56
57         __asm__ __volatile__(
58         "1:     ldl_l   %0,%1\n"
59         "       bne     %0,2f\n"
60         "       lda     %0,1\n"
61         "       stl_c   %0,%1\n"
62         "       beq     %0,2f\n"
63         "       mb\n"
64         ".subsection 2\n"
65         "2:     ldl     %0,%1\n"
66         "       bne     %0,2b\n"
67         "       br      1b\n"
68         ".previous"
69         : "=&r" (tmp), "=m" (lock->lock)
70         : "m"(lock->lock) : "memory");
71 }
72
73 static inline int _raw_spin_trylock(spinlock_t *lock)
74 {
75         return !test_and_set_bit(0, &lock->lock);
76 }
77 #endif /* CONFIG_DEBUG_SPINLOCK */
78
79 #define _raw_spin_lock_flags(lock, flags) _raw_spin_lock(lock)
80
81 /***********************************************************/
82
83 typedef struct {
84         volatile unsigned int lock;
85 } rwlock_t;
86
87 #define RW_LOCK_UNLOCKED        (rwlock_t){ 0 }
88
89 #define rwlock_init(x)          do { *(x) = RW_LOCK_UNLOCKED; } while(0)
90
91 static inline int read_can_lock(rwlock_t *lock)
92 {
93         return (lock->lock & 1) == 0;
94 }
95
96 static inline int write_can_lock(rwlock_t *lock)
97 {
98         return lock->lock == 0;
99 }
100
101 #ifdef CONFIG_DEBUG_RWLOCK
102 extern void _raw_write_lock(rwlock_t * lock);
103 extern void _raw_read_lock(rwlock_t * lock);
104 #else
105 static inline void _raw_write_lock(rwlock_t * lock)
106 {
107         long regx;
108
109         __asm__ __volatile__(
110         "1:     ldl_l   %1,%0\n"
111         "       bne     %1,6f\n"
112         "       lda     %1,1\n"
113         "       stl_c   %1,%0\n"
114         "       beq     %1,6f\n"
115         "       mb\n"
116         ".subsection 2\n"
117         "6:     ldl     %1,%0\n"
118         "       bne     %1,6b\n"
119         "       br      1b\n"
120         ".previous"
121         : "=m" (*lock), "=&r" (regx)
122         : "m" (*lock) : "memory");
123 }
124
125 static inline void _raw_read_lock(rwlock_t * lock)
126 {
127         long regx;
128
129         __asm__ __volatile__(
130         "1:     ldl_l   %1,%0\n"
131         "       blbs    %1,6f\n"
132         "       subl    %1,2,%1\n"
133         "       stl_c   %1,%0\n"
134         "       beq     %1,6f\n"
135         "       mb\n"
136         ".subsection 2\n"
137         "6:     ldl     %1,%0\n"
138         "       blbs    %1,6b\n"
139         "       br      1b\n"
140         ".previous"
141         : "=m" (*lock), "=&r" (regx)
142         : "m" (*lock) : "memory");
143 }
144 #endif /* CONFIG_DEBUG_RWLOCK */
145
146 static inline int _raw_read_trylock(rwlock_t * lock)
147 {
148         long regx;
149         int success;
150
151         __asm__ __volatile__(
152         "1:     ldl_l   %1,%0\n"
153         "       lda     %2,0\n"
154         "       blbs    %1,2f\n"
155         "       subl    %1,2,%2\n"
156         "       stl_c   %2,%0\n"
157         "       beq     %2,6f\n"
158         "2:     mb\n"
159         ".subsection 2\n"
160         "6:     br      1b\n"
161         ".previous"
162         : "=m" (*lock), "=&r" (regx), "=&r" (success)
163         : "m" (*lock) : "memory");
164
165         return success;
166 }
167
168 static inline int _raw_write_trylock(rwlock_t * lock)
169 {
170         long regx;
171         int success;
172
173         __asm__ __volatile__(
174         "1:     ldl_l   %1,%0\n"
175         "       lda     %2,0\n"
176         "       bne     %1,2f\n"
177         "       lda     %2,1\n"
178         "       stl_c   %2,%0\n"
179         "       beq     %2,6f\n"
180         "2:     mb\n"
181         ".subsection 2\n"
182         "6:     br      1b\n"
183         ".previous"
184         : "=m" (*lock), "=&r" (regx), "=&r" (success)
185         : "m" (*lock) : "memory");
186
187         return success;
188 }
189
190 static inline void _raw_write_unlock(rwlock_t * lock)
191 {
192         mb();
193         lock->lock = 0;
194 }
195
196 static inline void _raw_read_unlock(rwlock_t * lock)
197 {
198         long regx;
199         __asm__ __volatile__(
200         "       mb\n"
201         "1:     ldl_l   %1,%0\n"
202         "       addl    %1,2,%1\n"
203         "       stl_c   %1,%0\n"
204         "       beq     %1,6f\n"
205         ".subsection 2\n"
206         "6:     br      1b\n"
207         ".previous"
208         : "=m" (*lock), "=&r" (regx)
209         : "m" (*lock) : "memory");
210 }
211
212 #endif /* _ALPHA_SPINLOCK_H */