patch-2_6_7-vs1_9_1_12
[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 #define _raw_spin_lock_flags(lock, flags) _raw_spin_lock(lock)
29
30 /*
31  * Simple spin lock operations.  There are two variants, one clears IRQ's
32  * on the local processor, one does not.
33  *
34  * We make no fairness assumptions.  They have a cost.
35  */
36 static inline void _raw_spin_lock(spinlock_t *lock)
37 {
38         __asm__ __volatile__ (
39                 "1:\n\t"
40                 "tas.b @%0\n\t"
41                 "bf/s 1b\n\t"
42                 "nop\n\t"
43                 : "=r" (lock->lock)
44                 : "r" (&lock->lock)
45                 : "t", "memory"
46         );
47 }
48
49 static inline void _raw_spin_unlock(spinlock_t *lock)
50 {
51 #ifdef CONFIG_DEBUG_SPINLOCK
52         BUG_ON(!spin_is_locked(lock));
53 #endif
54
55         lock->lock = 0;
56 }
57
58 #define _raw_spin_trylock(x) (!test_and_set_bit(0, &(x)->lock))
59
60 /*
61  * Read-write spinlocks, allowing multiple readers but only one writer.
62  *
63  * NOTE! it is quite common to have readers in interrupts but no interrupt
64  * writers. For those circumstances we can "mix" irq-safe locks - any writer
65  * needs to get a irq-safe write-lock, but readers can get non-irqsafe
66  * read-locks.
67  */
68 typedef struct {
69         spinlock_t lock;
70         atomic_t counter;
71 } rwlock_t;
72
73 #define RW_LOCK_BIAS            0x01000000
74 #define RW_LOCK_UNLOCKED        (rwlock_t) { { 0 }, { RW_LOCK_BIAS } }
75 #define rwlock_init(x)          do { *(x) = RW_LOCK_UNLOCKED; } while (0)
76 #define rwlock_is_locked(x)     (atomic_read(&(x)->counter) != RW_LOCK_BIAS)
77
78 static inline void _raw_read_lock(rwlock_t *rw)
79 {
80         _raw_spin_lock(&rw->lock);
81
82         atomic_inc(&rw->counter);
83
84         _raw_spin_unlock(&rw->lock);
85 }
86
87 static inline void _raw_read_unlock(rwlock_t *rw)
88 {
89         _raw_spin_lock(&rw->lock);
90
91         atomic_dec(&rw->counter);
92
93         _raw_spin_unlock(&rw->lock);
94 }
95
96 static inline void _raw_write_lock(rwlock_t *rw)
97 {
98         _raw_spin_lock(&rw->lock);
99         atomic_set(&rw->counter, -1);
100 }
101
102 static inline void _raw_write_unlock(rwlock_t *rw)
103 {
104         atomic_set(&rw->counter, 0);
105         _raw_spin_unlock(&rw->lock);
106 }
107
108 static inline int _raw_write_trylock(rwlock_t *rw)
109 {
110         if (atomic_sub_and_test(RW_LOCK_BIAS, &rw->counter))
111                 return 1;
112         
113         atomic_add(RW_LOCK_BIAS, &rw->counter);
114
115         return 0;
116 }
117
118 #endif /* __ASM_SH_SPINLOCK_H */
119