ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / include / asm-sh / spinlock.h
1 /*
2  * include/asm-sh/spinlock.h
3  *
4  * Copyright (C) 2002, 2003 Paul Mundt
5  *
6  * This file is subject to the terms and conditions of the GNU General Public
7  * License.  See the file "COPYING" in the main directory of this archive
8  * for more details.
9  */
10 #ifndef __ASM_SH_SPINLOCK_H
11 #define __ASM_SH_SPINLOCK_H
12
13 #include <asm/atomic.h>
14
15 /*
16  * Your basic SMP spinlocks, allowing only a single CPU anywhere
17  */
18 typedef struct {
19         volatile unsigned long lock;
20 } spinlock_t;
21
22 #define SPIN_LOCK_UNLOCKED      (spinlock_t) { 0 }
23
24 #define spin_lock_init(x)       do { *(x) = SPIN_LOCK_UNLOCKED; } while(0)
25
26 #define spin_is_locked(x)       ((x)->lock != 0)
27 #define spin_unlock_wait(x)     do { barrier(); } while (spin_is_locked(x))
28
29 /*
30  * Simple spin lock operations.  There are two variants, one clears IRQ's
31  * on the local processor, one does not.
32  *
33  * We make no fairness assumptions.  They have a cost.
34  */
35 static inline void _raw_spin_lock(spinlock_t *lock)
36 {
37         __asm__ __volatile__ (
38                 "1:\n\t"
39                 "tas.b @%0\n\t"
40                 "bf/s 1b\n\t"
41                 "nop\n\t"
42                 : "=r" (lock->lock)
43                 : "r" (&lock->lock)
44                 : "t", "memory"
45         );
46 }
47
48 static inline void _raw_spin_unlock(spinlock_t *lock)
49 {
50 #ifdef CONFIG_DEBUG_SPINLOCK
51         BUG_ON(!spin_is_locked(lock));
52 #endif
53
54         lock->lock = 0;
55 }
56
57 #define _raw_spin_trylock(x) (!test_and_set_bit(0, &(x)->lock))
58
59 /*
60  * Read-write spinlocks, allowing multiple readers but only one writer.
61  *
62  * NOTE! it is quite common to have readers in interrupts but no interrupt
63  * writers. For those circumstances we can "mix" irq-safe locks - any writer
64  * needs to get a irq-safe write-lock, but readers can get non-irqsafe
65  * read-locks.
66  */
67 typedef struct {
68         spinlock_t lock;
69         atomic_t counter;
70 } rwlock_t;
71
72 #define RW_LOCK_BIAS            0x01000000
73 #define RW_LOCK_UNLOCKED        (rwlock_t) { { 0 }, { RW_LOCK_BIAS } }
74 #define rwlock_init(x)          do { *(x) = RW_LOCK_UNLOCKED; } while (0)
75 #define rwlock_is_locked(x)     (atomic_read(&(x)->counter) != RW_LOCK_BIAS)
76
77 static inline void _raw_read_lock(rwlock_t *rw)
78 {
79         _raw_spin_lock(&rw->lock);
80
81         atomic_inc(&rw->counter);
82
83         _raw_spin_unlock(&rw->lock);
84 }
85
86 static inline void _raw_read_unlock(rwlock_t *rw)
87 {
88         _raw_spin_lock(&rw->lock);
89
90         atomic_dec(&rw->counter);
91
92         _raw_spin_unlock(&rw->lock);
93 }
94
95 static inline void _raw_write_lock(rwlock_t *rw)
96 {
97         _raw_spin_lock(&rw->lock);
98         atomic_set(&rw->counter, -1);
99 }
100
101 static inline void _raw_write_unlock(rwlock_t *rw)
102 {
103         atomic_set(&rw->counter, 0);
104         _raw_spin_unlock(&rw->lock);
105 }
106
107 static inline int _raw_write_trylock(rwlock_t *rw)
108 {
109         if (atomic_sub_and_test(RW_LOCK_BIAS, &rw->counter))
110                 return 1;
111         
112         atomic_add(RW_LOCK_BIAS, &rw->counter);
113
114         return 0;
115 }
116
117 #endif /* __ASM_SH_SPINLOCK_H */
118