1 #ifndef _SPARC_SEMAPHORE_H
2 #define _SPARC_SEMAPHORE_H
3
4 /* Dinky, good for nothing, just barely irq safe, Sparc semaphores. */
5
6 #ifdef __KERNEL__
7
8 #include <asm/atomic.h>
9 #include <linux/wait.h>
10
11 struct semaphore {
12 atomic_t count;
13 int sleepers;
14 wait_queue_head_t wait;
15 #if WAITQUEUE_DEBUG
16 long __magic;
17 #endif
18 };
19
20 #if WAITQUEUE_DEBUG
21 # define __SEM_DEBUG_INIT(name) \
22 , (long)&(name).__magic
23 #else
24 # define __SEM_DEBUG_INIT(name)
25 #endif
26
27 #define __SEMAPHORE_INITIALIZER(name,count) \
28 { ATOMIC_INIT(count), 0, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
29 __SEM_DEBUG_INIT(name) }
30
31 #define __MUTEX_INITIALIZER(name) \
32 __SEMAPHORE_INITIALIZER(name,1)
33
34 #define __DECLARE_SEMAPHORE_GENERIC(name,count) \
35 struct semaphore name = __SEMAPHORE_INITIALIZER(name,count)
36
37 #define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1)
38 #define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0)
39
40 static inline void sema_init (struct semaphore *sem, int val)
41 {
42 atomic_set(&sem->count, val);
43 sem->sleepers = 0;
44 init_waitqueue_head(&sem->wait);
45 #if WAITQUEUE_DEBUG
46 sem->__magic = (long)&sem->__magic;
47 #endif
48 }
49
50 static inline void init_MUTEX (struct semaphore *sem)
51 {
52 sema_init(sem, 1);
53 }
54
55 static inline void init_MUTEX_LOCKED (struct semaphore *sem)
56 {
57 sema_init(sem, 0);
58 }
59
60 extern void __down(struct semaphore * sem);
61 extern int __down_interruptible(struct semaphore * sem);
62 extern int __down_trylock(struct semaphore * sem);
63 extern void __up(struct semaphore * sem);
64
65 static inline void down(struct semaphore * sem)
66 {
67 register atomic_t *ptr asm("g1");
68 register int increment asm("g2");
69
70 #if WAITQUEUE_DEBUG
71 CHECK_MAGIC(sem->__magic);
72 #endif
73
74 ptr = (atomic_t *) __atomic_fool_gcc(sem);
75 increment = 1;
76
77 __asm__ __volatile__("
78 mov %%o7, %%g4
79 call ___atomic_sub
80 add %%o7, 8, %%o7
81 tst %%g2
82 bl 2f
83 nop
84 1:
85 .subsection 2
86 2: save %%sp, -64, %%sp
87 mov %%g1, %%l1
88 mov %%g5, %%l5
89 call %3
90 mov %%g1, %%o0
91 mov %%l1, %%g1
92 ba 1b
93 restore %%l5, %%g0, %%g5
94 .previous\n"
95 : "=&r" (increment)
96 : "" (increment), "r" (ptr), "i" (__down)
97 : "g3", "g4", "g7", "memory", "cc");
98 }
99
100 static inline int down_interruptible(struct semaphore * sem)
101 {
102 register atomic_t *ptr asm("g1");
103 register int increment asm("g2");
104
105 #if WAITQUEUE_DEBUG
106 CHECK_MAGIC(sem->__magic);
107 #endif
108
109 ptr = (atomic_t *) __atomic_fool_gcc(sem);
110 increment = 1;
111
112 __asm__ __volatile__("
113 mov %%o7, %%g4
114 call ___atomic_sub
115 add %%o7, 8, %%o7
116 tst %%g2
117 bl 2f
118 clr %%g2
119 1:
120 .subsection 2
121 2: save %%sp, -64, %%sp
122 mov %%g1, %%l1
123 mov %%g5, %%l5
124 call %3
125 mov %%g1, %%o0
126 mov %%l1, %%g1
127 mov %%l5, %%g5
128 ba 1b
129 restore %%o0, %%g0, %%g2
130 .previous\n"
131 : "=&r" (increment)
132 : "" (increment), "r" (ptr), "i" (__down_interruptible)
133 : "g3", "g4", "g7", "memory", "cc");
134
135 return increment;
136 }
137
138 static inline int down_trylock(struct semaphore * sem)
139 {
140 register atomic_t *ptr asm("g1");
141 register int increment asm("g2");
142
143 #if WAITQUEUE_DEBUG
144 CHECK_MAGIC(sem->__magic);
145 #endif
146
147 ptr = (atomic_t *) __atomic_fool_gcc(sem);
148 increment = 1;
149
150 __asm__ __volatile__("
151 mov %%o7, %%g4
152 call ___atomic_sub
153 add %%o7, 8, %%o7
154 tst %%g2
155 bl 2f
156 clr %%g2
157 1:
158 .subsection 2
159 2: save %%sp, -64, %%sp
160 mov %%g1, %%l1
161 mov %%g5, %%l5
162 call %3
163 mov %%g1, %%o0
164 mov %%l1, %%g1
165 mov %%l5, %%g5
166 ba 1b
167 restore %%o0, %%g0, %%g2
168 .previous\n"
169 : "=&r" (increment)
170 : "" (increment), "r" (ptr), "i" (__down_trylock)
171 : "g3", "g4", "g7", "memory", "cc");
172
173 return increment;
174 }
175
176 static inline void up(struct semaphore * sem)
177 {
178 register atomic_t *ptr asm("g1");
179 register int increment asm("g2");
180
181 #if WAITQUEUE_DEBUG
182 CHECK_MAGIC(sem->__magic);
183 #endif
184
185 ptr = (atomic_t *) __atomic_fool_gcc(sem);
186 increment = 1;
187
188 __asm__ __volatile__("
189 mov %%o7, %%g4
190 call ___atomic_add
191 add %%o7, 8, %%o7
192 tst %%g2
193 ble 2f
194 nop
195 1:
196 .subsection 2
197 2: save %%sp, -64, %%sp
198 mov %%g1, %%l1
199 mov %%g5, %%l5
200 call %3
201 mov %%g1, %%o0
202 mov %%l1, %%g1
203 ba 1b
204 restore %%l5, %%g0, %%g5
205 .previous\n"
206 : "=&r" (increment)
207 : "" (increment), "r" (ptr), "i" (__up)
208 : "g3", "g4", "g7", "memory", "cc");
209 }
210
211 /* rw mutexes (should that be mutices? =) -- throw rw
212 * spinlocks and semaphores together, and this is what we
213 * end up with...
214 *
215 * The lock is initialized to BIAS. This way, a writer
216 * subtracts BIAS ands gets 0 for the case of an uncontended
217 * lock. Readers decrement by 1 and see a positive value
218 * when uncontended, negative if there are writers waiting
219 * (in which case it goes to sleep).
220 *
221 * The value 0x01000000 supports up to 128 processors and
222 * lots of processes. BIAS must be chosen such that subtracting
223 * BIAS once per CPU will result in the int remaining
224 * negative.
225 * In terms of fairness, this should result in the lock
226 * flopping back and forth between readers and writers
227 * under heavy use.
228 *
229 * -ben
230 */
231 #define RW_LOCK_BIAS 0x01000000
232
233 struct rw_semaphore {
234 int count;
235 unsigned char lock;
236 unsigned char read_not_granted;
237 unsigned char write_not_granted;
238 wait_queue_head_t wait;
239 wait_queue_head_t write_bias_wait;
240 #if WAITQUEUE_DEBUG
241 long __magic;
242 atomic_t readers;
243 atomic_t writers;
244 #endif
245 };
246
247 #if WAITQUEUE_DEBUG
248 #define __RWSEM_DEBUG_INIT , ATOMIC_INIT(0), ATOMIC_INIT(0)
249 #else
250 #define __RWSEM_DEBUG_INIT /* */
251 #endif
252
253 #define __RWSEM_INITIALIZER(name,count) \
254 { (count), 0, 0xff, 0xff, __WAIT_QUEUE_HEAD_INITIALIZER((name).wait), \
255 __WAIT_QUEUE_HEAD_INITIALIZER((name).write_bias_wait) \
256 __SEM_DEBUG_INIT(name) __RWSEM_DEBUG_INIT }
257
258 #define __DECLARE_RWSEM_GENERIC(name,count) \
259 struct rw_semaphore name = __RWSEM_INITIALIZER(name,count)
260
261 #define DECLARE_RWSEM(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS)
262 #define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1)
263 #define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0)
264
265 static inline void init_rwsem(struct rw_semaphore *sem)
266 {
267 sem->count = RW_LOCK_BIAS;
268 sem->lock = 0;
269 sem->read_not_granted = 0xff;
270 sem->write_not_granted = 0xff;
271 init_waitqueue_head(&sem->wait);
272 init_waitqueue_head(&sem->write_bias_wait);
273 #if WAITQUEUE_DEBUG
274 sem->__magic = (long)&sem->__magic;
275 atomic_set(&sem->readers, 0);
276 atomic_set(&sem->writers, 0);
277 #endif
278 }
279
280 extern void ___down_read(/* Special calling convention */ void);
281 extern void ___down_write(/* Special calling convention */ void);
282 extern void ___up_read(/* Special calling convention */ void);
283 extern void ___up_write(/* Special calling convention */ void);
284
285 static inline void down_read(struct rw_semaphore *sem)
286 {
287 register atomic_t *ptr asm("g1");
288
289 #if WAITQUEUE_DEBUG
290 CHECK_MAGIC(sem->__magic);
291 #endif
292
293 ptr = (atomic_t *) __atomic_fool_gcc(sem);
294
295 __asm__ __volatile__("
296 mov %%o7, %%g4
297 call %1
298 add %%o7, 8, %%o7
299 "
300 :: "r" (ptr), "i" (___down_read)
301 : "g2", "g3", "g4", "g7", "memory", "cc");
302 #if WAITQUEUE_DEBUG
303 if (!sem->write_not_granted)
304 BUG();
305 if (atomic_read(&sem->writers))
306 BUG();
307 atomic_inc(&sem->readers);
308 #endif
309 }
310
311 static inline void down_write(struct rw_semaphore *sem)
312 {
313 register atomic_t *ptr asm("g1");
314
315 #if WAITQUEUE_DEBUG
316 CHECK_MAGIC(sem->__magic);
317 #endif
318
319 ptr = (atomic_t *) __atomic_fool_gcc(sem);
320
321 __asm__ __volatile__("
322 mov %%o7, %%g4
323 call %1
324 add %%o7, 8, %%o7
325 "
326 :: "r" (ptr), "i" (___down_write)
327 : "g2", "g3", "g4", "g7", "memory", "cc");
328 #if WAITQUEUE_DEBUG
329 if (atomic_read(&sem->writers))
330 BUG();
331 if (atomic_read(&sem->readers))
332 BUG();
333 if (!sem->read_not_granted)
334 BUG();
335 if (!sem->write_not_granted)
336 BUG();
337 atomic_inc(&sem->writers);
338 #endif
339 }
340
341 /* When a reader does a release, the only significant
342 * case is when there was a writer waiting, and we've
343 * bumped the count to 0: we must wake the writer up.
344 */
345 static inline void __up_read(struct rw_semaphore *sem)
346 {
347 register atomic_t *ptr asm("g1");
348
349 ptr = (atomic_t *) __atomic_fool_gcc(sem);
350
351 __asm__ __volatile__("
352 mov %%o7, %%g4
353 call %1
354 add %%o7, 8, %%o7
355 "
356 :: "r" (ptr), "i" (___up_read)
357 : "g2", "g3", "g4", "g7", "memory", "cc");
358 }
359
360 /* releasing the writer is easy -- just release it and
361 * wake up any sleepers.
362 */
363 static inline void __up_write(struct rw_semaphore *sem)
364 {
365 register atomic_t *ptr asm("g1");
366
367 ptr = (atomic_t *) __atomic_fool_gcc(sem);
368
369 __asm__ __volatile__("
370 mov %%o7, %%g4
371 call %1
372 add %%o7, 8, %%o7
373 "
374 :: "r" (ptr), "i" (___up_write)
375 : "g2", "g3", "g4", "g7", "memory", "cc");
376 }
377
378 static inline void up_read(struct rw_semaphore *sem)
379 {
380 #if WAITQUEUE_DEBUG
381 if (!sem->write_not_granted)
382 BUG();
383 if (atomic_read(&sem->writers))
384 BUG();
385 atomic_dec(&sem->readers);
386 #endif
387 __up_read(sem);
388 }
389
390 static inline void up_write(struct rw_semaphore *sem)
391 {
392 #if WAITQUEUE_DEBUG
393 if (!sem->read_not_granted)
394 BUG();
395 if (!sem->write_not_granted)
396 BUG();
397 if (atomic_read(&sem->readers))
398 BUG();
399 if (atomic_read(&sem->writers) != 1)
400 BUG();
401 atomic_dec(&sem->writers);
402 #endif
403 __up_write(sem);
404 }
405
406 #endif /* __KERNEL__ */
407
408 #endif /* !(_SPARC_SEMAPHORE_H) */
409
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.