spinlock.h 8.0 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
/* spinlock.h: 64-bit Sparc spinlock support.
 *
 * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
 */

#ifndef __SPARC64_SPINLOCK_H
#define __SPARC64_SPINLOCK_H

#include <linux/config.h>
#include <linux/threads.h>	/* For NR_CPUS */

#ifndef __ASSEMBLY__

/* To get debugging spinlocks which detect and catch
 * deadlock situations, set CONFIG_DEBUG_SPINLOCK
 * and rebuild your kernel.
 */

/* All of these locking primitives are expected to work properly
 * even in an RMO memory model, which currently is what the kernel
 * runs in.
 *
 * There is another issue.  Because we play games to save cycles
 * in the non-contention case, we need to be extra careful about
 * branch targets into the "spinning" code.  They live in their
 * own section, but the newer V9 branches have a shorter range
 * than the traditional 32-bit sparc branch variants.  The rule
 * is that the branches that go into and out of the spinner sections
 * must be pre-V9 branches.
 */

#ifndef CONFIG_DEBUG_SPINLOCK

A
Al Viro 已提交
34 35 36 37 38 39 40
typedef struct {
	volatile unsigned char lock;
#ifdef CONFIG_PREEMPT
	unsigned int break_lock;
#endif
} spinlock_t;
#define SPIN_LOCK_UNLOCKED	(spinlock_t) {0,}
L
Linus Torvalds 已提交
41

A
Al Viro 已提交
42 43
#define spin_lock_init(lp)	do { *(lp)= SPIN_LOCK_UNLOCKED; } while(0)
#define spin_is_locked(lp)  ((lp)->lock != 0)
L
Linus Torvalds 已提交
44

A
Al Viro 已提交
45
#define spin_unlock_wait(lp)	\
46
do {	rmb();			\
D
David S. Miller 已提交
47
} while((lp)->lock)
L
Linus Torvalds 已提交
48 49 50 51 52 53 54

static inline void _raw_spin_lock(spinlock_t *lock)
{
	unsigned long tmp;

	__asm__ __volatile__(
"1:	ldstub		[%1], %0\n"
55
"	membar		#StoreLoad | #StoreStore\n"
L
Linus Torvalds 已提交
56
"	brnz,pn		%0, 2f\n"
57
"	 nop\n"
L
Linus Torvalds 已提交
58 59
"	.subsection	2\n"
"2:	ldub		[%1], %0\n"
60
"	membar		#LoadLoad\n"
L
Linus Torvalds 已提交
61
"	brnz,pt		%0, 2b\n"
62
"	 nop\n"
L
Linus Torvalds 已提交
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
"	ba,a,pt		%%xcc, 1b\n"
"	.previous"
	: "=&r" (tmp)
	: "r" (lock)
	: "memory");
}

static inline int _raw_spin_trylock(spinlock_t *lock)
{
	unsigned long result;

	__asm__ __volatile__(
"	ldstub		[%1], %0\n"
"	membar		#StoreLoad | #StoreStore"
	: "=r" (result)
	: "r" (lock)
	: "memory");

	return (result == 0UL);
}

static inline void _raw_spin_unlock(spinlock_t *lock)
{
	__asm__ __volatile__(
"	membar		#StoreStore | #LoadStore\n"
"	stb		%%g0, [%0]"
	: /* No outputs */
	: "r" (lock)
	: "memory");
}

static inline void _raw_spin_lock_flags(spinlock_t *lock, unsigned long flags)
{
	unsigned long tmp1, tmp2;

	__asm__ __volatile__(
"1:	ldstub		[%2], %0\n"
"	membar		#StoreLoad | #StoreStore\n"
101 102
"	brnz,pn		%0, 2f\n"
"	 nop\n"
L
Linus Torvalds 已提交
103 104 105 106 107
"	.subsection	2\n"
"2:	rdpr		%%pil, %1\n"
"	wrpr		%3, %%pil\n"
"3:	ldub		[%2], %0\n"
"	membar		#LoadLoad\n"
108 109
"	brnz,pt		%0, 3b\n"
"	 nop\n"
L
Linus Torvalds 已提交
110
"	ba,pt		%%xcc, 1b\n"
111
"	 wrpr		%1, %%pil\n"
L
Linus Torvalds 已提交
112 113 114 115 116 117 118 119 120
"	.previous"
	: "=&r" (tmp1), "=&r" (tmp2)
	: "r"(lock), "r"(flags)
	: "memory");
}

#else /* !(CONFIG_DEBUG_SPINLOCK) */

typedef struct {
A
Al Viro 已提交
121
	volatile unsigned char lock;
L
Linus Torvalds 已提交
122
	unsigned int owner_pc, owner_cpu;
A
Al Viro 已提交
123 124 125
#ifdef CONFIG_PREEMPT
	unsigned int break_lock;
#endif
L
Linus Torvalds 已提交
126 127
} spinlock_t;
#define SPIN_LOCK_UNLOCKED (spinlock_t) { 0, 0, 0xff }
A
Al Viro 已提交
128 129
#define spin_lock_init(lp)	do { *(lp)= SPIN_LOCK_UNLOCKED; } while(0)
#define spin_is_locked(__lock)	((__lock)->lock != 0)
L
Linus Torvalds 已提交
130 131
#define spin_unlock_wait(__lock)	\
do { \
132
	rmb(); \
A
Al Viro 已提交
133
} while((__lock)->lock)
L
Linus Torvalds 已提交
134

135 136 137 138 139 140 141 142 143
extern void _do_spin_lock(spinlock_t *lock, char *str, unsigned long caller);
extern void _do_spin_unlock(spinlock_t *lock);
extern int _do_spin_trylock(spinlock_t *lock, unsigned long caller);

#define _raw_spin_trylock(lp)	\
	_do_spin_trylock(lp, (unsigned long) __builtin_return_address(0))
#define _raw_spin_lock(lock)	\
	_do_spin_lock(lock, "spin_lock", \
		      (unsigned long) __builtin_return_address(0))
L
Linus Torvalds 已提交
144 145 146 147 148 149 150 151 152
#define _raw_spin_unlock(lock)	_do_spin_unlock(lock)
#define _raw_spin_lock_flags(lock, flags) _raw_spin_lock(lock)

#endif /* CONFIG_DEBUG_SPINLOCK */

/* Multi-reader locks, these are much saner than the 32-bit Sparc ones... */

#ifndef CONFIG_DEBUG_SPINLOCK

A
Al Viro 已提交
153 154 155 156 157 158
typedef struct {
	volatile unsigned int lock;
#ifdef CONFIG_PREEMPT
	unsigned int break_lock;
#endif
} rwlock_t;
D
David S. Miller 已提交
159
#define RW_LOCK_UNLOCKED	(rwlock_t) {0,}
L
Linus Torvalds 已提交
160 161 162 163 164 165 166 167 168 169 170 171
#define rwlock_init(lp) do { *(lp) = RW_LOCK_UNLOCKED; } while(0)

static void inline __read_lock(rwlock_t *lock)
{
	unsigned long tmp1, tmp2;

	__asm__ __volatile__ (
"1:	ldsw		[%2], %0\n"
"	brlz,pn		%0, 2f\n"
"4:	 add		%0, 1, %1\n"
"	cas		[%2], %0, %1\n"
"	cmp		%0, %1\n"
172
"	membar		#StoreLoad | #StoreStore\n"
L
Linus Torvalds 已提交
173
"	bne,pn		%%icc, 1b\n"
174
"	 nop\n"
L
Linus Torvalds 已提交
175 176
"	.subsection	2\n"
"2:	ldsw		[%2], %0\n"
177
"	membar		#LoadLoad\n"
L
Linus Torvalds 已提交
178
"	brlz,pt		%0, 2b\n"
179
"	 nop\n"
L
Linus Torvalds 已提交
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
"	ba,a,pt		%%xcc, 4b\n"
"	.previous"
	: "=&r" (tmp1), "=&r" (tmp2)
	: "r" (lock)
	: "memory");
}

static void inline __read_unlock(rwlock_t *lock)
{
	unsigned long tmp1, tmp2;

	__asm__ __volatile__(
"	membar	#StoreLoad | #LoadLoad\n"
"1:	lduw	[%2], %0\n"
"	sub	%0, 1, %1\n"
"	cas	[%2], %0, %1\n"
"	cmp	%0, %1\n"
"	bne,pn	%%xcc, 1b\n"
"	 nop"
	: "=&r" (tmp1), "=&r" (tmp2)
	: "r" (lock)
	: "memory");
}

static void inline __write_lock(rwlock_t *lock)
{
	unsigned long mask, tmp1, tmp2;

	mask = 0x80000000UL;

	__asm__ __volatile__(
"1:	lduw		[%2], %0\n"
"	brnz,pn		%0, 2f\n"
"4:	 or		%0, %3, %1\n"
"	cas		[%2], %0, %1\n"
"	cmp		%0, %1\n"
216
"	membar		#StoreLoad | #StoreStore\n"
L
Linus Torvalds 已提交
217
"	bne,pn		%%icc, 1b\n"
218
"	 nop\n"
L
Linus Torvalds 已提交
219 220
"	.subsection	2\n"
"2:	lduw		[%2], %0\n"
221
"	membar		#LoadLoad\n"
L
Linus Torvalds 已提交
222
"	brnz,pt		%0, 2b\n"
223
"	 nop\n"
L
Linus Torvalds 已提交
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
"	ba,a,pt		%%xcc, 4b\n"
"	.previous"
	: "=&r" (tmp1), "=&r" (tmp2)
	: "r" (lock), "r" (mask)
	: "memory");
}

static void inline __write_unlock(rwlock_t *lock)
{
	__asm__ __volatile__(
"	membar		#LoadStore | #StoreStore\n"
"	stw		%%g0, [%0]"
	: /* no outputs */
	: "r" (lock)
	: "memory");
}

static int inline __write_trylock(rwlock_t *lock)
{
	unsigned long mask, tmp1, tmp2, result;

	mask = 0x80000000UL;

	__asm__ __volatile__(
"	mov		0, %2\n"
"1:	lduw		[%3], %0\n"
"	brnz,pn		%0, 2f\n"
"	 or		%0, %4, %1\n"
"	cas		[%3], %0, %1\n"
"	cmp		%0, %1\n"
254
"	membar		#StoreLoad | #StoreStore\n"
L
Linus Torvalds 已提交
255
"	bne,pn		%%icc, 1b\n"
256
"	 nop\n"
L
Linus Torvalds 已提交
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
"	mov		1, %2\n"
"2:"
	: "=&r" (tmp1), "=&r" (tmp2), "=&r" (result)
	: "r" (lock), "r" (mask)
	: "memory");

	return result;
}

#define _raw_read_lock(p)	__read_lock(p)
#define _raw_read_unlock(p)	__read_unlock(p)
#define _raw_write_lock(p)	__write_lock(p)
#define _raw_write_unlock(p)	__write_unlock(p)
#define _raw_write_trylock(p)	__write_trylock(p)

#else /* !(CONFIG_DEBUG_SPINLOCK) */

typedef struct {
A
Al Viro 已提交
275
	volatile unsigned long lock;
L
Linus Torvalds 已提交
276 277
	unsigned int writer_pc, writer_cpu;
	unsigned int reader_pc[NR_CPUS];
A
Al Viro 已提交
278 279 280
#ifdef CONFIG_PREEMPT
	unsigned int break_lock;
#endif
L
Linus Torvalds 已提交
281 282 283 284
} rwlock_t;
#define RW_LOCK_UNLOCKED	(rwlock_t) { 0, 0, 0xff, { } }
#define rwlock_init(lp) do { *(lp) = RW_LOCK_UNLOCKED; } while(0)

285 286 287 288 289
extern void _do_read_lock(rwlock_t *rw, char *str, unsigned long caller);
extern void _do_read_unlock(rwlock_t *rw, char *str, unsigned long caller);
extern void _do_write_lock(rwlock_t *rw, char *str, unsigned long caller);
extern void _do_write_unlock(rwlock_t *rw, unsigned long caller);
extern int _do_write_trylock(rwlock_t *rw, char *str, unsigned long caller);
L
Linus Torvalds 已提交
290 291 292 293

#define _raw_read_lock(lock) \
do {	unsigned long flags; \
	local_irq_save(flags); \
294 295
	_do_read_lock(lock, "read_lock", \
		      (unsigned long) __builtin_return_address(0)); \
L
Linus Torvalds 已提交
296 297 298 299 300 301
	local_irq_restore(flags); \
} while(0)

#define _raw_read_unlock(lock) \
do {	unsigned long flags; \
	local_irq_save(flags); \
302 303
	_do_read_unlock(lock, "read_unlock", \
		      (unsigned long) __builtin_return_address(0)); \
L
Linus Torvalds 已提交
304 305 306 307 308 309
	local_irq_restore(flags); \
} while(0)

#define _raw_write_lock(lock) \
do {	unsigned long flags; \
	local_irq_save(flags); \
310 311
	_do_write_lock(lock, "write_lock", \
		      (unsigned long) __builtin_return_address(0)); \
L
Linus Torvalds 已提交
312 313 314 315 316 317
	local_irq_restore(flags); \
} while(0)

#define _raw_write_unlock(lock) \
do {	unsigned long flags; \
	local_irq_save(flags); \
318 319
	_do_write_unlock(lock, \
		      (unsigned long) __builtin_return_address(0)); \
L
Linus Torvalds 已提交
320 321 322 323 324 325 326
	local_irq_restore(flags); \
} while(0)

#define _raw_write_trylock(lock) \
({	unsigned long flags; \
	int val; \
	local_irq_save(flags); \
327 328
	val = _do_write_trylock(lock, "write_trylock", \
				(unsigned long) __builtin_return_address(0)); \
L
Linus Torvalds 已提交
329 330 331 332 333 334 335
	local_irq_restore(flags); \
	val; \
})

#endif /* CONFIG_DEBUG_SPINLOCK */

#define _raw_read_trylock(lock) generic_raw_read_trylock(lock)
A
Al Viro 已提交
336 337
#define read_can_lock(rw)	(!((rw)->lock & 0x80000000UL))
#define write_can_lock(rw)	(!(rw)->lock)
L
Linus Torvalds 已提交
338 339 340 341

#endif /* !(__ASSEMBLY__) */

#endif /* !(__SPARC64_SPINLOCK_H) */