patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / include / asm-parisc / spinlock.h
1 #ifndef __ASM_SPINLOCK_H
2 #define __ASM_SPINLOCK_H
3
4 #include <asm/system.h>
5
6 /* Note that PA-RISC has to use `1' to mean unlocked and `0' to mean locked
7  * since it only has load-and-zero. Moreover, at least on some PA processors,
8  * the semaphore address has to be 16-byte aligned.
9  */
10
11 #undef SPIN_LOCK_UNLOCKED
12 #define SPIN_LOCK_UNLOCKED (spinlock_t) { { 1, 1, 1, 1 } }
13
14 #define spin_lock_init(x)       do { *(x) = SPIN_LOCK_UNLOCKED; } while(0)
15
16 static inline int spin_is_locked(spinlock_t *x)
17 {
18         volatile unsigned int *a = __ldcw_align(x);
19         return *a == 0;
20 }
21
22 #define spin_unlock_wait(x)     do { barrier(); } while(spin_is_locked(x))
23 #define _raw_spin_lock_flags(lock, flags) _raw_spin_lock(lock)
24
25 static inline void _raw_spin_lock(spinlock_t *x)
26 {
27         volatile unsigned int *a = __ldcw_align(x);
28         while (__ldcw(a) == 0)
29                 while (*a == 0);
30 }
31
32 static inline void _raw_spin_unlock(spinlock_t *x)
33 {
34         volatile unsigned int *a = __ldcw_align(x);
35         *a = 1;
36 }
37
38 static inline int _raw_spin_trylock(spinlock_t *x)
39 {
40         volatile unsigned int *a = __ldcw_align(x);
41         return __ldcw(a) != 0;
42 }
43         
44 /*
45  * Read-write spinlocks, allowing multiple readers
46  * but only one writer.
47  */
48 typedef struct {
49         spinlock_t lock;
50         volatile int counter;
51 } rwlock_t;
52
53 #define RW_LOCK_UNLOCKED (rwlock_t) { { { 1, 1, 1, 1 } }, 0 }
54
55 #define rwlock_init(lp) do { *(lp) = RW_LOCK_UNLOCKED; } while (0)
56
57 #define rwlock_is_locked(lp) ((lp)->counter != 0)
58
59 /* read_lock, read_unlock are pretty straightforward.  Of course it somehow
60  * sucks we end up saving/restoring flags twice for read_lock_irqsave aso. */
61
62 static  __inline__ void _raw_read_lock(rwlock_t *rw)
63 {
64         unsigned long flags;
65         local_irq_save(flags);
66         _raw_spin_lock(&rw->lock); 
67
68         rw->counter++;
69
70         _raw_spin_unlock(&rw->lock);
71         local_irq_restore(flags);
72 }
73
74 static  __inline__ void _raw_read_unlock(rwlock_t *rw)
75 {
76         unsigned long flags;
77         local_irq_save(flags);
78         _raw_spin_lock(&rw->lock); 
79
80         rw->counter--;
81
82         _raw_spin_unlock(&rw->lock);
83         local_irq_restore(flags);
84 }
85
86 /* write_lock is less trivial.  We optimistically grab the lock and check
87  * if we surprised any readers.  If so we release the lock and wait till
88  * they're all gone before trying again
89  *
90  * Also note that we don't use the _irqsave / _irqrestore suffixes here.
91  * If we're called with interrupts enabled and we've got readers (or other
92  * writers) in interrupt handlers someone fucked up and we'd dead-lock
93  * sooner or later anyway.   prumpf */
94
95 static  __inline__ void _raw_write_lock(rwlock_t *rw)
96 {
97 retry:
98         _raw_spin_lock(&rw->lock);
99
100         if(rw->counter != 0) {
101                 /* this basically never happens */
102                 _raw_spin_unlock(&rw->lock);
103
104                 while(rw->counter != 0);
105
106                 goto retry;
107         }
108
109         /* got it.  now leave without unlocking */
110         rw->counter = -1; /* remember we are locked */
111 }
112
113 /* write_unlock is absolutely trivial - we don't have to wait for anything */
114
115 static  __inline__ void _raw_write_unlock(rwlock_t *rw)
116 {
117         rw->counter = 0;
118         _raw_spin_unlock(&rw->lock);
119 }
120
121 static __inline__ int is_read_locked(rwlock_t *rw)
122 {
123         return rw->counter > 0;
124 }
125
126 static __inline__ int is_write_locked(rwlock_t *rw)
127 {
128         return rw->counter < 0;
129 }
130
131 #endif /* __ASM_SPINLOCK_H */