[PATCH] spinlock consolidation
[linux-2.6.git] / 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 #include <linux/config.h>
10 #include <linux/threads.h>      /* For NR_CPUS */
11
12 #ifndef __ASSEMBLY__
13
14 /* To get debugging spinlocks which detect and catch
15  * deadlock situations, set CONFIG_DEBUG_SPINLOCK
16  * and rebuild your kernel.
17  */
18
19 /* All of these locking primitives are expected to work properly
20  * even in an RMO memory model, which currently is what the kernel
21  * runs in.
22  *
23  * There is another issue.  Because we play games to save cycles
24  * in the non-contention case, we need to be extra careful about
25  * branch targets into the "spinning" code.  They live in their
26  * own section, but the newer V9 branches have a shorter range
27  * than the traditional 32-bit sparc branch variants.  The rule
28  * is that the branches that go into and out of the spinner sections
29  * must be pre-V9 branches.
30  */
31
32 #define __raw_spin_is_locked(lp)        ((lp)->lock != 0)
33
34 #define __raw_spin_unlock_wait(lp)      \
35         do {    rmb();                  \
36         } while((lp)->lock)
37
38 static inline void __raw_spin_lock(raw_spinlock_t *lock)
39 {
40         unsigned long tmp;
41
42         __asm__ __volatile__(
43 "1:     ldstub          [%1], %0\n"
44 "       membar          #StoreLoad | #StoreStore\n"
45 "       brnz,pn         %0, 2f\n"
46 "        nop\n"
47 "       .subsection     2\n"
48 "2:     ldub            [%1], %0\n"
49 "       membar          #LoadLoad\n"
50 "       brnz,pt         %0, 2b\n"
51 "        nop\n"
52 "       ba,a,pt         %%xcc, 1b\n"
53 "       .previous"
54         : "=&r" (tmp)
55         : "r" (lock)
56         : "memory");
57 }
58
59 static inline int __raw_spin_trylock(raw_spinlock_t *lock)
60 {
61         unsigned long result;
62
63         __asm__ __volatile__(
64 "       ldstub          [%1], %0\n"
65 "       membar          #StoreLoad | #StoreStore"
66         : "=r" (result)
67         : "r" (lock)
68         : "memory");
69
70         return (result == 0UL);
71 }
72
73 static inline void __raw_spin_unlock(raw_spinlock_t *lock)
74 {
75         __asm__ __volatile__(
76 "       membar          #StoreStore | #LoadStore\n"
77 "       stb             %%g0, [%0]"
78         : /* No outputs */
79         : "r" (lock)
80         : "memory");
81 }
82
83 static inline void __raw_spin_lock_flags(raw_spinlock_t *lock, unsigned long flags)
84 {
85         unsigned long tmp1, tmp2;
86
87         __asm__ __volatile__(
88 "1:     ldstub          [%2], %0\n"
89 "       membar          #StoreLoad | #StoreStore\n"
90 "       brnz,pn         %0, 2f\n"
91 "        nop\n"
92 "       .subsection     2\n"
93 "2:     rdpr            %%pil, %1\n"
94 "       wrpr            %3, %%pil\n"
95 "3:     ldub            [%2], %0\n"
96 "       membar          #LoadLoad\n"
97 "       brnz,pt         %0, 3b\n"
98 "        nop\n"
99 "       ba,pt           %%xcc, 1b\n"
100 "        wrpr           %1, %%pil\n"
101 "       .previous"
102         : "=&r" (tmp1), "=&r" (tmp2)
103         : "r"(lock), "r"(flags)
104         : "memory");
105 }
106
107 /* Multi-reader locks, these are much saner than the 32-bit Sparc ones... */
108
109 static void inline __read_lock(raw_rwlock_t *lock)
110 {
111         unsigned long tmp1, tmp2;
112
113         __asm__ __volatile__ (
114 "1:     ldsw            [%2], %0\n"
115 "       brlz,pn         %0, 2f\n"
116 "4:      add            %0, 1, %1\n"
117 "       cas             [%2], %0, %1\n"
118 "       cmp             %0, %1\n"
119 "       membar          #StoreLoad | #StoreStore\n"
120 "       bne,pn          %%icc, 1b\n"
121 "        nop\n"
122 "       .subsection     2\n"
123 "2:     ldsw            [%2], %0\n"
124 "       membar          #LoadLoad\n"
125 "       brlz,pt         %0, 2b\n"
126 "        nop\n"
127 "       ba,a,pt         %%xcc, 4b\n"
128 "       .previous"
129         : "=&r" (tmp1), "=&r" (tmp2)
130         : "r" (lock)
131         : "memory");
132 }
133
134 static void inline __read_unlock(raw_rwlock_t *lock)
135 {
136         unsigned long tmp1, tmp2;
137
138         __asm__ __volatile__(
139 "       membar  #StoreLoad | #LoadLoad\n"
140 "1:     lduw    [%2], %0\n"
141 "       sub     %0, 1, %1\n"
142 "       cas     [%2], %0, %1\n"
143 "       cmp     %0, %1\n"
144 "       bne,pn  %%xcc, 1b\n"
145 "        nop"
146         : "=&r" (tmp1), "=&r" (tmp2)
147         : "r" (lock)
148         : "memory");
149 }
150
151 static void inline __write_lock(raw_rwlock_t *lock)
152 {
153         unsigned long mask, tmp1, tmp2;
154
155         mask = 0x80000000UL;
156
157         __asm__ __volatile__(
158 "1:     lduw            [%2], %0\n"
159 "       brnz,pn         %0, 2f\n"
160 "4:      or             %0, %3, %1\n"
161 "       cas             [%2], %0, %1\n"
162 "       cmp             %0, %1\n"
163 "       membar          #StoreLoad | #StoreStore\n"
164 "       bne,pn          %%icc, 1b\n"
165 "        nop\n"
166 "       .subsection     2\n"
167 "2:     lduw            [%2], %0\n"
168 "       membar          #LoadLoad\n"
169 "       brnz,pt         %0, 2b\n"
170 "        nop\n"
171 "       ba,a,pt         %%xcc, 4b\n"
172 "       .previous"
173         : "=&r" (tmp1), "=&r" (tmp2)
174         : "r" (lock), "r" (mask)
175         : "memory");
176 }
177
178 static void inline __write_unlock(raw_rwlock_t *lock)
179 {
180         __asm__ __volatile__(
181 "       membar          #LoadStore | #StoreStore\n"
182 "       stw             %%g0, [%0]"
183         : /* no outputs */
184         : "r" (lock)
185         : "memory");
186 }
187
188 static int inline __write_trylock(raw_rwlock_t *lock)
189 {
190         unsigned long mask, tmp1, tmp2, result;
191
192         mask = 0x80000000UL;
193
194         __asm__ __volatile__(
195 "       mov             0, %2\n"
196 "1:     lduw            [%3], %0\n"
197 "       brnz,pn         %0, 2f\n"
198 "        or             %0, %4, %1\n"
199 "       cas             [%3], %0, %1\n"
200 "       cmp             %0, %1\n"
201 "       membar          #StoreLoad | #StoreStore\n"
202 "       bne,pn          %%icc, 1b\n"
203 "        nop\n"
204 "       mov             1, %2\n"
205 "2:"
206         : "=&r" (tmp1), "=&r" (tmp2), "=&r" (result)
207         : "r" (lock), "r" (mask)
208         : "memory");
209
210         return result;
211 }
212
213 #define __raw_read_lock(p)      __read_lock(p)
214 #define __raw_read_unlock(p)    __read_unlock(p)
215 #define __raw_write_lock(p)     __write_lock(p)
216 #define __raw_write_unlock(p)   __write_unlock(p)
217 #define __raw_write_trylock(p)  __write_trylock(p)
218
219 #define __raw_read_trylock(lock)        generic__raw_read_trylock(lock)
220 #define __raw_read_can_lock(rw)         (!((rw)->lock & 0x80000000UL))
221 #define __raw_write_can_lock(rw)        (!(rw)->lock)
222
223 #endif /* !(__ASSEMBLY__) */
224
225 #endif /* !(__SPARC64_SPINLOCK_H) */