blob: 669b8e349ff29544fce6a35c91307950ba660f4a [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * This file is subject to the terms and conditions of the GNU General Public
3 * License. See the file "COPYING" in the main directory of this archive
4 * for more details.
5 *
6 * Copyright (C) 1999, 2000 by Ralf Baechle
7 * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
8 */
9#ifndef _ASM_SPINLOCK_H
10#define _ASM_SPINLOCK_H
11
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <asm/war.h>
13
14/*
15 * Your basic SMP spinlocks, allowing only a single CPU anywhere
16 */
17
Ralf Baechlebeb3ca82005-10-29 19:32:40 +010018#define __raw_spin_is_locked(x) ((x)->lock != 0)
Ingo Molnarfb1c8f92005-09-10 00:25:56 -070019#define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock)
20#define __raw_spin_unlock_wait(x) \
Ralf Baechlebeb3ca82005-10-29 19:32:40 +010021 do { cpu_relax(); } while ((x)->lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -070022
23/*
24 * Simple spin lock operations. There are two variants, one clears IRQ's
25 * on the local processor, one does not.
26 *
27 * We make no fairness assumptions. They have a cost.
28 */
29
Ingo Molnarfb1c8f92005-09-10 00:25:56 -070030static inline void __raw_spin_lock(raw_spinlock_t *lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -070031{
32 unsigned int tmp;
33
34 if (R10000_LLSC_WAR) {
35 __asm__ __volatile__(
Ingo Molnarfb1c8f92005-09-10 00:25:56 -070036 " .set noreorder # __raw_spin_lock \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -070037 "1: ll %1, %2 \n"
38 " bnez %1, 1b \n"
39 " li %1, 1 \n"
40 " sc %1, %0 \n"
41 " beqzl %1, 1b \n"
42 " nop \n"
43 " sync \n"
44 " .set reorder \n"
45 : "=m" (lock->lock), "=&r" (tmp)
46 : "m" (lock->lock)
47 : "memory");
48 } else {
49 __asm__ __volatile__(
Ingo Molnarfb1c8f92005-09-10 00:25:56 -070050 " .set noreorder # __raw_spin_lock \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -070051 "1: ll %1, %2 \n"
52 " bnez %1, 1b \n"
53 " li %1, 1 \n"
54 " sc %1, %0 \n"
55 " beqz %1, 1b \n"
56 " sync \n"
57 " .set reorder \n"
58 : "=m" (lock->lock), "=&r" (tmp)
59 : "m" (lock->lock)
60 : "memory");
61 }
62}
63
Ingo Molnarfb1c8f92005-09-10 00:25:56 -070064static inline void __raw_spin_unlock(raw_spinlock_t *lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -070065{
66 __asm__ __volatile__(
Ingo Molnarfb1c8f92005-09-10 00:25:56 -070067 " .set noreorder # __raw_spin_unlock \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -070068 " sync \n"
69 " sw $0, %0 \n"
70 " .set\treorder \n"
71 : "=m" (lock->lock)
72 : "m" (lock->lock)
73 : "memory");
74}
75
Ingo Molnarfb1c8f92005-09-10 00:25:56 -070076static inline unsigned int __raw_spin_trylock(raw_spinlock_t *lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -070077{
78 unsigned int temp, res;
79
80 if (R10000_LLSC_WAR) {
81 __asm__ __volatile__(
Ingo Molnarfb1c8f92005-09-10 00:25:56 -070082 " .set noreorder # __raw_spin_trylock \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -070083 "1: ll %0, %3 \n"
84 " ori %2, %0, 1 \n"
85 " sc %2, %1 \n"
86 " beqzl %2, 1b \n"
87 " nop \n"
88 " andi %2, %0, 1 \n"
89 " sync \n"
90 " .set reorder"
91 : "=&r" (temp), "=m" (lock->lock), "=&r" (res)
92 : "m" (lock->lock)
93 : "memory");
94 } else {
95 __asm__ __volatile__(
Ingo Molnarfb1c8f92005-09-10 00:25:56 -070096 " .set noreorder # __raw_spin_trylock \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 "1: ll %0, %3 \n"
98 " ori %2, %0, 1 \n"
99 " sc %2, %1 \n"
100 " beqz %2, 1b \n"
101 " andi %2, %0, 1 \n"
102 " sync \n"
103 " .set reorder"
104 : "=&r" (temp), "=m" (lock->lock), "=&r" (res)
105 : "m" (lock->lock)
106 : "memory");
107 }
108
109 return res == 0;
110}
111
112/*
113 * Read-write spinlocks, allowing multiple readers but only one writer.
114 *
115 * NOTE! it is quite common to have readers in interrupts but no interrupt
116 * writers. For those circumstances we can "mix" irq-safe locks - any writer
117 * needs to get a irq-safe write-lock, but readers can get non-irqsafe
118 * read-locks.
119 */
120
Ralf Baechlee3c48072005-02-03 13:34:45 +0000121/*
122 * read_can_lock - would read_trylock() succeed?
123 * @lock: the rwlock in question.
124 */
125#define __raw_read_can_lock(rw) ((rw)->lock >= 0)
126
127/*
128 * write_can_lock - would write_trylock() succeed?
129 * @lock: the rwlock in question.
130 */
131#define __raw_write_can_lock(rw) (!(rw)->lock)
132
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700133static inline void __raw_read_lock(raw_rwlock_t *rw)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134{
135 unsigned int tmp;
136
137 if (R10000_LLSC_WAR) {
138 __asm__ __volatile__(
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700139 " .set noreorder # __raw_read_lock \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 "1: ll %1, %2 \n"
141 " bltz %1, 1b \n"
142 " addu %1, 1 \n"
143 " sc %1, %0 \n"
144 " beqzl %1, 1b \n"
145 " nop \n"
146 " sync \n"
147 " .set reorder \n"
148 : "=m" (rw->lock), "=&r" (tmp)
149 : "m" (rw->lock)
150 : "memory");
151 } else {
152 __asm__ __volatile__(
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700153 " .set noreorder # __raw_read_lock \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 "1: ll %1, %2 \n"
155 " bltz %1, 1b \n"
156 " addu %1, 1 \n"
157 " sc %1, %0 \n"
158 " beqz %1, 1b \n"
159 " sync \n"
160 " .set reorder \n"
161 : "=m" (rw->lock), "=&r" (tmp)
162 : "m" (rw->lock)
163 : "memory");
164 }
165}
166
167/* Note the use of sub, not subu which will make the kernel die with an
168 overflow exception if we ever try to unlock an rwlock that is already
169 unlocked or is being held by a writer. */
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700170static inline void __raw_read_unlock(raw_rwlock_t *rw)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171{
172 unsigned int tmp;
173
174 if (R10000_LLSC_WAR) {
175 __asm__ __volatile__(
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700176 "1: ll %1, %2 # __raw_read_unlock \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 " sub %1, 1 \n"
178 " sc %1, %0 \n"
179 " beqzl %1, 1b \n"
180 " sync \n"
181 : "=m" (rw->lock), "=&r" (tmp)
182 : "m" (rw->lock)
183 : "memory");
184 } else {
185 __asm__ __volatile__(
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700186 " .set noreorder # __raw_read_unlock \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 "1: ll %1, %2 \n"
188 " sub %1, 1 \n"
189 " sc %1, %0 \n"
190 " beqz %1, 1b \n"
191 " sync \n"
192 " .set reorder \n"
193 : "=m" (rw->lock), "=&r" (tmp)
194 : "m" (rw->lock)
195 : "memory");
196 }
197}
198
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700199static inline void __raw_write_lock(raw_rwlock_t *rw)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200{
201 unsigned int tmp;
202
203 if (R10000_LLSC_WAR) {
204 __asm__ __volatile__(
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700205 " .set noreorder # __raw_write_lock \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 "1: ll %1, %2 \n"
207 " bnez %1, 1b \n"
208 " lui %1, 0x8000 \n"
209 " sc %1, %0 \n"
210 " beqzl %1, 1b \n"
Ralf Baechleb63014a2005-04-14 15:28:28 +0000211 " sync \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 " .set reorder \n"
213 : "=m" (rw->lock), "=&r" (tmp)
214 : "m" (rw->lock)
215 : "memory");
216 } else {
217 __asm__ __volatile__(
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700218 " .set noreorder # __raw_write_lock \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 "1: ll %1, %2 \n"
220 " bnez %1, 1b \n"
221 " lui %1, 0x8000 \n"
222 " sc %1, %0 \n"
223 " beqz %1, 1b \n"
Ralf Baechleb63014a2005-04-14 15:28:28 +0000224 " sync \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 " .set reorder \n"
226 : "=m" (rw->lock), "=&r" (tmp)
227 : "m" (rw->lock)
228 : "memory");
229 }
230}
231
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700232static inline void __raw_write_unlock(raw_rwlock_t *rw)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233{
234 __asm__ __volatile__(
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700235 " sync # __raw_write_unlock \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 " sw $0, %0 \n"
237 : "=m" (rw->lock)
238 : "m" (rw->lock)
239 : "memory");
240}
241
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700242#define __raw_read_trylock(lock) generic__raw_read_trylock(lock)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700244static inline int __raw_write_trylock(raw_rwlock_t *rw)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245{
246 unsigned int tmp;
247 int ret;
248
249 if (R10000_LLSC_WAR) {
250 __asm__ __volatile__(
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700251 " .set noreorder # __raw_write_trylock \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252 " li %2, 0 \n"
253 "1: ll %1, %3 \n"
254 " bnez %1, 2f \n"
255 " lui %1, 0x8000 \n"
256 " sc %1, %0 \n"
257 " beqzl %1, 1b \n"
Ralf Baechleb63014a2005-04-14 15:28:28 +0000258 " sync \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700259 " li %2, 1 \n"
260 " .set reorder \n"
261 "2: \n"
262 : "=m" (rw->lock), "=&r" (tmp), "=&r" (ret)
263 : "m" (rw->lock)
264 : "memory");
265 } else {
266 __asm__ __volatile__(
Ingo Molnarfb1c8f92005-09-10 00:25:56 -0700267 " .set noreorder # __raw_write_trylock \n"
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 " li %2, 0 \n"
269 "1: ll %1, %3 \n"
270 " bnez %1, 2f \n"
271 " lui %1, 0x8000 \n"
272 " sc %1, %0 \n"
273 " beqz %1, 1b \n"
274 " sync \n"
275 " li %2, 1 \n"
276 " .set reorder \n"
277 "2: \n"
278 : "=m" (rw->lock), "=&r" (tmp), "=&r" (ret)
279 : "m" (rw->lock)
280 : "memory");
281 }
282
283 return ret;
284}
285
286#endif /* _ASM_SPINLOCK_H */