Import 2.3.18pre1
[davej-history.git] / arch / ppc / lib / locks.c
blobd6b56dc5f9dd4b2d941f0636221e741e2f6a20f8
1 /*
2 * $Id: locks.c,v 1.24 1999/08/03 19:16:47 cort Exp $
4 * Locks for smp ppc
5 *
6 * Written by Cort Dougan (cort@cs.nmt.edu)
7 */
10 #include <linux/kernel.h>
11 #include <linux/sched.h>
12 #include <linux/delay.h>
13 #include <linux/spinlock.h>
14 #include <asm/processor.h>
15 #include <asm/system.h>
16 #include <asm/io.h>
18 #define DEBUG_LOCKS 1
20 #undef INIT_STUCK
21 #define INIT_STUCK 200000000 /*0xffffffff*/
23 void _spin_lock(spinlock_t *lock)
25 int cpu = smp_processor_id();
26 #ifdef DEBUG_LOCKS
27 unsigned int stuck = INIT_STUCK;
28 #endif /* DEBUG_LOCKS */
29 while (__spin_trylock(&lock->lock)) {
30 #ifdef DEBUG_LOCKS
31 if(!--stuck) {
32 printk("_spin_lock(%p) CPU#%d NIP %p"
33 " holder: cpu %ld pc %08lX\n",
34 lock, cpu, __builtin_return_address(0),
35 lock->owner_cpu,lock->owner_pc);
36 stuck = INIT_STUCK;
37 /* steal the lock */
38 /*xchg_u32((void *)&lock->lock,0);*/
40 #endif /* DEBUG_LOCKS */
42 lock->owner_pc = (unsigned long)__builtin_return_address(0);
43 lock->owner_cpu = cpu;
46 int spin_trylock(spinlock_t *lock)
48 if (__spin_trylock(&lock->lock))
49 return 0;
50 lock->owner_cpu = smp_processor_id();
51 lock->owner_pc = (unsigned long)__builtin_return_address(0);
52 return 1;
57 void _spin_unlock(spinlock_t *lp)
59 #ifdef DEBUG_LOCKS
60 if ( !lp->lock )
61 printk("_spin_unlock(%p): no lock cpu %d %s/%d\n", lp,
62 smp_processor_id(),current->comm,current->pid);
63 if ( lp->owner_cpu != smp_processor_id() )
64 printk("_spin_unlock(%p): cpu %d trying clear of cpu %d pc %lx val %lx\n",
65 lp, smp_processor_id(), (int)lp->owner_cpu,
66 lp->owner_pc,lp->lock);
67 #endif /* DEBUG_LOCKS */
68 lp->owner_pc = lp->owner_cpu = 0;
69 wmb();
70 lp->lock = 0;
71 wmb();
75 * Just like x86, implement read-write locks as a 32-bit counter
76 * with the high bit (sign) being the "write" bit.
77 * -- Cort
79 void _read_lock(rwlock_t *rw)
81 #ifdef DEBUG_LOCKS
82 unsigned long stuck = INIT_STUCK;
83 int cpu = smp_processor_id();
84 #endif /* DEBUG_LOCKS */
86 again:
87 /* get our read lock in there */
88 wmb();
89 atomic_inc((atomic_t *) &(rw)->lock);
90 if ( (signed long)((rw)->lock) < 0) /* someone has a write lock */
92 /* turn off our read lock */
93 atomic_dec((atomic_t *) &(rw)->lock);
94 /* wait for the write lock to go away */
95 while ((signed long)((rw)->lock) < 0)
97 #ifdef DEBUG_LOCKS
98 if(!--stuck)
100 printk("_read_lock(%p) CPU#%d\n", rw, cpu);
101 stuck = INIT_STUCK;
103 #endif /* DEBUG_LOCKS */
105 /* try to get the read lock again */
106 goto again;
108 wmb();
111 void _read_unlock(rwlock_t *rw)
113 #ifdef DEBUG_LOCKS
114 if ( rw->lock == 0 )
115 printk("_read_unlock(): %s/%d (nip %08lX) lock %lx\n",
116 current->comm,current->pid,current->thread.regs->nip,
117 rw->lock);
118 #endif /* DEBUG_LOCKS */
119 wmb();
120 atomic_dec((atomic_t *) &(rw)->lock);
121 wmb();
124 void _write_lock(rwlock_t *rw)
126 #ifdef DEBUG_LOCKS
127 unsigned long stuck = INIT_STUCK;
128 int cpu = smp_processor_id();
129 #endif /* DEBUG_LOCKS */
131 again:
132 wmb();
133 if ( test_and_set_bit(31,&(rw)->lock) ) /* someone has a write lock */
135 while ( (rw)->lock & (1<<31) ) /* wait for write lock */
137 #ifdef DEBUG_LOCKS
138 if(!--stuck)
140 printk("write_lock(%p) CPU#%d lock %lx)\n",
141 rw, cpu,rw->lock);
142 stuck = INIT_STUCK;
144 #endif /* DEBUG_LOCKS */
145 barrier();
147 goto again;
150 if ( (rw)->lock & ~(1<<31)) /* someone has a read lock */
152 /* clear our write lock and wait for reads to go away */
153 clear_bit(31,&(rw)->lock);
154 while ( (rw)->lock & ~(1<<31) )
156 #ifdef DEBUG_LOCKS
157 if(!--stuck)
159 printk("write_lock(%p) 2 CPU#%d lock %lx)\n",
160 rw, cpu,rw->lock);
161 stuck = INIT_STUCK;
163 #endif /* DEBUG_LOCKS */
164 barrier();
166 goto again;
168 wmb();
171 void _write_unlock(rwlock_t *rw)
173 #ifdef DEBUG_LOCKS
174 if ( !(rw->lock & (1<<31)) )
175 printk("_write_lock(): %s/%d (nip %08lX) lock %lx\n",
176 current->comm,current->pid,current->thread.regs->nip,
177 rw->lock);
178 #endif /* DEBUG_LOCKS */
179 wmb();
180 clear_bit(31,&(rw)->lock);
181 wmb();
184 void __lock_kernel(struct task_struct *task)
186 #ifdef DEBUG_LOCKS
187 unsigned long stuck = INIT_STUCK;
189 if ( (signed long)(task->lock_depth) < 0 )
191 printk("__lock_kernel(): %s/%d (nip %08lX) lock depth %x\n",
192 task->comm,task->pid,task->thread.regs->nip,
193 task->lock_depth);
195 #endif /* DEBUG_LOCKS */
197 if (atomic_inc_return((atomic_t *) &task->lock_depth) != 1)
198 return;
199 /* mine! */
200 while (__spin_trylock(&klock_info.kernel_flag)) {
201 #ifdef DEBUG_LOCKS
202 if(!--stuck) {
203 printk("_lock_kernel() CPU#%d NIP %p\n",
204 smp_processor_id(),
205 __builtin_return_address(0));
206 stuck = INIT_STUCK;
208 #endif /* DEBUG_LOCKS */
211 klock_info.akp = smp_processor_id();
212 /* my kernel mode! mine!!! */
215 void __unlock_kernel(struct task_struct *task)
217 #ifdef DEBUG_LOCKS
218 if ((task->lock_depth == 0) || (klock_info.kernel_flag != KLOCK_HELD))
220 printk("__unlock_kernel(): %s/%d (nip %08lX) "
221 "lock depth %x flags %lx\n",
222 task->comm,task->pid,task->thread.regs->nip,
223 task->lock_depth, klock_info.kernel_flag);
224 klock_info.akp = NO_PROC_ID;
225 klock_info.kernel_flag = 0;
226 return;
228 #endif /* DEBUG_LOCKS */
229 if (atomic_dec_and_test((atomic_t *) &task->lock_depth))
231 wmb();
232 klock_info.akp = NO_PROC_ID;
233 wmb();
234 klock_info.kernel_flag = KLOCK_CLEAR;
235 wmb();
239 void reacquire_kernel_lock(struct task_struct *task, int cpu,int depth)
241 if (depth)
243 __cli();
244 __lock_kernel(task);
245 task->lock_depth = depth;
246 __sti();