1 /*
2 * Locks for smp ppc
3 *
4 * Written by Cort Dougan (cort@cs.nmt.edu)
5 */
6
7
8 #include <linux/kernel.h>
9 #include <linux/sched.h>
10 #include <linux/delay.h>
11 #include <linux/spinlock.h>
12 #include <asm/processor.h>
13 #include <asm/system.h>
14 #include <asm/io.h>
15
16 #if SPINLOCK_DEBUG
17
18 #undef INIT_STUCK
19 #define INIT_STUCK 200000000 /*0xffffffff*/
20
21 /*
22 * Try to acquire a spinlock.
23 * Only does the stwcx. if the load returned 0 - the Programming
24 * Environments Manual suggests not doing unnecessary stcwx.'s
25 * since they may inhibit forward progress by other CPUs in getting
26 * a lock.
27 */
__spin_trylock(volatile unsigned long * lock)28 static unsigned long __spin_trylock(volatile unsigned long *lock)
29 {
30 unsigned long ret;
31
32 __asm__ __volatile__ ("\n\
33 1: lwarx %0,0,%1\n\
34 cmpwi 0,%0,0\n\
35 bne 2f\n"
36 PPC405_ERR77(0,%1)
37 " stwcx. %2,0,%1\n\
38 bne- 1b\n\
39 isync\n\
40 2:"
41 : "=&r"(ret)
42 : "r"(lock), "r"(1)
43 : "cr0", "memory");
44
45 return ret;
46 }
47
_spin_lock(spinlock_t * lock)48 void _spin_lock(spinlock_t *lock)
49 {
50 int cpu = smp_processor_id();
51 unsigned int stuck = INIT_STUCK;
52 while (__spin_trylock(&lock->lock)) {
53 while ((unsigned volatile long)lock->lock != 0) {
54 if (!--stuck) {
55 printk("_spin_lock(%p) CPU#%d NIP %p"
56 " holder: cpu %ld pc %08lX\n",
57 lock, cpu, __builtin_return_address(0),
58 lock->owner_cpu,lock->owner_pc);
59 stuck = INIT_STUCK;
60 /* steal the lock */
61 /*xchg_u32((void *)&lock->lock,0);*/
62 }
63 }
64 }
65 lock->owner_pc = (unsigned long)__builtin_return_address(0);
66 lock->owner_cpu = cpu;
67 }
68
spin_trylock(spinlock_t * lock)69 int spin_trylock(spinlock_t *lock)
70 {
71 if (__spin_trylock(&lock->lock))
72 return 0;
73 lock->owner_cpu = smp_processor_id();
74 lock->owner_pc = (unsigned long)__builtin_return_address(0);
75 return 1;
76 }
77
_spin_unlock(spinlock_t * lp)78 void _spin_unlock(spinlock_t *lp)
79 {
80 if ( !lp->lock )
81 printk("_spin_unlock(%p): no lock cpu %d curr PC %p %s/%d\n",
82 lp, smp_processor_id(), __builtin_return_address(0),
83 current->comm, current->pid);
84 if ( lp->owner_cpu != smp_processor_id() )
85 printk("_spin_unlock(%p): cpu %d trying clear of cpu %d pc %lx val %lx\n",
86 lp, smp_processor_id(), (int)lp->owner_cpu,
87 lp->owner_pc,lp->lock);
88 lp->owner_pc = lp->owner_cpu = 0;
89 wmb();
90 lp->lock = 0;
91 }
92
93
94 /*
95 * Just like x86, implement read-write locks as a 32-bit counter
96 * with the high bit (sign) being the "write" bit.
97 * -- Cort
98 */
_read_lock(rwlock_t * rw)99 void _read_lock(rwlock_t *rw)
100 {
101 unsigned long stuck = INIT_STUCK;
102 int cpu = smp_processor_id();
103
104 again:
105 /* get our read lock in there */
106 atomic_inc((atomic_t *) &(rw)->lock);
107 if ( (signed long)((rw)->lock) < 0) /* someone has a write lock */
108 {
109 /* turn off our read lock */
110 atomic_dec((atomic_t *) &(rw)->lock);
111 /* wait for the write lock to go away */
112 while ((signed long)((rw)->lock) < 0)
113 {
114 if(!--stuck)
115 {
116 printk("_read_lock(%p) CPU#%d\n", rw, cpu);
117 stuck = INIT_STUCK;
118 }
119 }
120 /* try to get the read lock again */
121 goto again;
122 }
123 wmb();
124 }
125
_read_unlock(rwlock_t * rw)126 void _read_unlock(rwlock_t *rw)
127 {
128 if ( rw->lock == 0 )
129 printk("_read_unlock(): %s/%d (nip %08lX) lock %lx\n",
130 current->comm,current->pid,current->thread.regs->nip,
131 rw->lock);
132 wmb();
133 atomic_dec((atomic_t *) &(rw)->lock);
134 }
135
_write_lock(rwlock_t * rw)136 void _write_lock(rwlock_t *rw)
137 {
138 unsigned long stuck = INIT_STUCK;
139 int cpu = smp_processor_id();
140
141 again:
142 if ( test_and_set_bit(31,&(rw)->lock) ) /* someone has a write lock */
143 {
144 while ( (rw)->lock & (1<<31) ) /* wait for write lock */
145 {
146 if(!--stuck)
147 {
148 printk("write_lock(%p) CPU#%d lock %lx)\n",
149 rw, cpu,rw->lock);
150 stuck = INIT_STUCK;
151 }
152 barrier();
153 }
154 goto again;
155 }
156
157 if ( (rw)->lock & ~(1<<31)) /* someone has a read lock */
158 {
159 /* clear our write lock and wait for reads to go away */
160 clear_bit(31,&(rw)->lock);
161 while ( (rw)->lock & ~(1<<31) )
162 {
163 if(!--stuck)
164 {
165 printk("write_lock(%p) 2 CPU#%d lock %lx)\n",
166 rw, cpu,rw->lock);
167 stuck = INIT_STUCK;
168 }
169 barrier();
170 }
171 goto again;
172 }
173 wmb();
174 }
175
_write_unlock(rwlock_t * rw)176 void _write_unlock(rwlock_t *rw)
177 {
178 if ( !(rw->lock & (1<<31)) )
179 printk("_write_lock(): %s/%d (nip %08lX) lock %lx\n",
180 current->comm,current->pid,current->thread.regs->nip,
181 rw->lock);
182 wmb();
183 clear_bit(31,&(rw)->lock);
184 }
185
186 #endif
187