File: /usr/src/linux/include/asm-sparc64/spinlock.h

1     /* spinlock.h: 64-bit Sparc spinlock support.
2      *
3      * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
4      */
5     
6     #ifndef __SPARC64_SPINLOCK_H
7     #define __SPARC64_SPINLOCK_H
8     
9     #ifndef __ASSEMBLY__
10     
11     /* To get debugging spinlocks which detect and catch
12      * deadlock situations, set DEBUG_SPINLOCKS in the sparc64
13      * specific makefile and rebuild your kernel.
14      */
15     
16     /* All of these locking primitives are expected to work properly
17      * even in an RMO memory model, which currently is what the kernel
18      * runs in.
19      *
20      * There is another issue.  Because we play games to save cycles
21      * in the non-contention case, we need to be extra careful about
22      * branch targets into the "spinning" code.  They live in their
23      * own section, but the newer V9 branches have a shorter range
24      * than the traditional 32-bit sparc branch variants.  The rule
25      * is that the branches that go into and out of the spinner sections
26      * must be pre-V9 branches.
27      */
28     
29     #ifndef SPIN_LOCK_DEBUG
30     
31     typedef unsigned char spinlock_t;
32     #define SPIN_LOCK_UNLOCKED	0
33     
34     #define spin_lock_init(lock)	(*((unsigned char *)(lock)) = 0)
35     #define spin_is_locked(lock)	(*((volatile unsigned char *)(lock)) != 0)
36     
37     #define spin_unlock_wait(lock)	\
38     do {	membar("#LoadLoad");	\
39     } while(*((volatile unsigned char *)lock))
40     
41     extern __inline__ void spin_lock(spinlock_t *lock)
42     {
43     	__asm__ __volatile__(
44     "1:	ldstub		[%0], %%g7\n"
45     "	brnz,pn		%%g7, 2f\n"
46     "	 membar		#StoreLoad | #StoreStore\n"
47     "	.subsection	2\n"
48     "2:	ldub		[%0], %%g7\n"
49     "	brnz,pt		%%g7, 2b\n"
50     "	 membar		#LoadLoad\n"
51     "	b,a,pt		%%xcc, 1b\n"
52     "	.previous\n"
53     	: /* no outputs */
54     	: "r" (lock)
55     	: "g7", "memory");
56     }
57     
58     extern __inline__ int spin_trylock(spinlock_t *lock)
59     {
60     	unsigned int result;
61     	__asm__ __volatile__("ldstub [%1], %0\n\t"
62     			     "membar #StoreLoad | #StoreStore"
63     			     : "=r" (result)
64     			     : "r" (lock)
65     			     : "memory");
66     	return (result == 0);
67     }
68     
69     extern __inline__ void spin_unlock(spinlock_t *lock)
70     {
71     	__asm__ __volatile__("membar	#StoreStore | #LoadStore\n\t"
72     			     "stb	%%g0, [%0]"
73     			     : /* No outputs */
74     			     : "r" (lock)
75     			     : "memory");
76     }
77     
78     #else /* !(SPIN_LOCK_DEBUG) */
79     
80     typedef struct {
81     	unsigned char lock;
82     	unsigned int owner_pc, owner_cpu;
83     } spinlock_t;
84     #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0, 0, 0xff }
85     #define spin_lock_init(__lock)	\
86     do {	(__lock)->lock = 0; \
87     	(__lock)->owner_pc = 0; \
88     	(__lock)->owner_cpu = 0xff; \
89     } while(0)
90     #define spin_is_locked(__lock)	(*((volatile unsigned char *)(&((__lock)->lock))) != 0)
91     #define spin_unlock_wait(__lock)	\
92     do { \
93     	membar("#LoadLoad"); \
94     } while(*((volatile unsigned char *)(&((__lock)->lock))))
95     
96     extern void _do_spin_lock (spinlock_t *lock, char *str);
97     extern void _do_spin_unlock (spinlock_t *lock);
98     extern int _spin_trylock (spinlock_t *lock);
99     
100     #define spin_trylock(lp)	_spin_trylock(lp)
101     #define spin_lock(lock)		_do_spin_lock(lock, "spin_lock")
102     #define spin_unlock(lock)	_do_spin_unlock(lock)
103     
104     #endif /* SPIN_LOCK_DEBUG */
105     
106     /* Multi-reader locks, these are much saner than the 32-bit Sparc ones... */
107     
108     #ifndef SPIN_LOCK_DEBUG
109     
110     typedef unsigned int rwlock_t;
111     #define RW_LOCK_UNLOCKED	0
112     #define rwlock_init(lp) do { *(lp) = RW_LOCK_UNLOCKED; } while(0)
113     
114     extern void __read_lock(rwlock_t *);
115     extern void __read_unlock(rwlock_t *);
116     extern void __write_lock(rwlock_t *);
117     extern void __write_unlock(rwlock_t *);
118     
119     #define read_lock(p)	__read_lock(p)
120     #define read_unlock(p)	__read_unlock(p)
121     #define write_lock(p)	__write_lock(p)
122     #define write_unlock(p)	__write_unlock(p)
123     
124     #else /* !(SPIN_LOCK_DEBUG) */
125     
126     typedef struct {
127     	unsigned long lock;
128     	unsigned int writer_pc, writer_cpu;
129     	unsigned int reader_pc[4];
130     } rwlock_t;
131     #define RW_LOCK_UNLOCKED	(rwlock_t) { 0, 0, 0xff, { 0, 0, 0, 0 } }
132     #define rwlock_init(lp) do { *(lp) = RW_LOCK_UNLOCKED; } while(0)
133     
134     extern void _do_read_lock(rwlock_t *rw, char *str);
135     extern void _do_read_unlock(rwlock_t *rw, char *str);
136     extern void _do_write_lock(rwlock_t *rw, char *str);
137     extern void _do_write_unlock(rwlock_t *rw);
138     
139     #define read_lock(lock)	\
140     do {	unsigned long flags; \
141     	__save_and_cli(flags); \
142     	_do_read_lock(lock, "read_lock"); \
143     	__restore_flags(flags); \
144     } while(0)
145     
146     #define read_unlock(lock) \
147     do {	unsigned long flags; \
148     	__save_and_cli(flags); \
149     	_do_read_unlock(lock, "read_unlock"); \
150     	__restore_flags(flags); \
151     } while(0)
152     
153     #define write_lock(lock) \
154     do {	unsigned long flags; \
155     	__save_and_cli(flags); \
156     	_do_write_lock(lock, "write_lock"); \
157     	__restore_flags(flags); \
158     } while(0)
159     
160     #define write_unlock(lock) \
161     do {	unsigned long flags; \
162     	__save_and_cli(flags); \
163     	_do_write_unlock(lock); \
164     	__restore_flags(flags); \
165     } while(0)
166     
167     #endif /* SPIN_LOCK_DEBUG */
168     
169     #endif /* !(__ASSEMBLY__) */
170     
171     #endif /* !(__SPARC64_SPINLOCK_H) */
172