Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | #ifndef __ASM_SPINLOCK_H |
2 | #define __ASM_SPINLOCK_H | |
3 | ||
4 | #if __LINUX_ARM_ARCH__ < 6 | |
5 | #error SMP not supported on pre-ARMv6 CPUs | |
6 | #endif | |
7 | ||
8 | /* | |
9 | * ARMv6 Spin-locking. | |
10 | * | |
6d9b37a3 RK |
11 | * We exclusively read the old value. If it is zero, we may have |
12 | * won the lock, so we try exclusively storing it. A memory barrier | |
13 | * is required after we get a lock, and before we release it, because | |
14 | * V6 CPUs are assumed to have weakly ordered memory. | |
1da177e4 LT |
15 | * |
16 | * Unlocked value: 0 | |
17 | * Locked value: 1 | |
18 | */ | |
1da177e4 | 19 | |
fb1c8f93 IM |
20 | #define __raw_spin_is_locked(x) ((x)->lock != 0) |
21 | #define __raw_spin_unlock_wait(lock) \ | |
22 | do { while (__raw_spin_is_locked(lock)) cpu_relax(); } while (0) | |
1da177e4 | 23 | |
fb1c8f93 | 24 | #define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock) |
1da177e4 | 25 | |
fb1c8f93 | 26 | static inline void __raw_spin_lock(raw_spinlock_t *lock) |
1da177e4 LT |
27 | { |
28 | unsigned long tmp; | |
29 | ||
30 | __asm__ __volatile__( | |
31 | "1: ldrex %0, [%1]\n" | |
32 | " teq %0, #0\n" | |
00b4c907 RK |
33 | #ifdef CONFIG_CPU_32v6K |
34 | " wfene\n" | |
35 | #endif | |
1da177e4 LT |
36 | " strexeq %0, %2, [%1]\n" |
37 | " teqeq %0, #0\n" | |
38 | " bne 1b" | |
39 | : "=&r" (tmp) | |
40 | : "r" (&lock->lock), "r" (1) | |
6d9b37a3 RK |
41 | : "cc"); |
42 | ||
43 | smp_mb(); | |
1da177e4 LT |
44 | } |
45 | ||
fb1c8f93 | 46 | static inline int __raw_spin_trylock(raw_spinlock_t *lock) |
1da177e4 LT |
47 | { |
48 | unsigned long tmp; | |
49 | ||
50 | __asm__ __volatile__( | |
51 | " ldrex %0, [%1]\n" | |
52 | " teq %0, #0\n" | |
53 | " strexeq %0, %2, [%1]" | |
54 | : "=&r" (tmp) | |
55 | : "r" (&lock->lock), "r" (1) | |
6d9b37a3 RK |
56 | : "cc"); |
57 | ||
58 | if (tmp == 0) { | |
59 | smp_mb(); | |
60 | return 1; | |
61 | } else { | |
62 | return 0; | |
63 | } | |
1da177e4 LT |
64 | } |
65 | ||
fb1c8f93 | 66 | static inline void __raw_spin_unlock(raw_spinlock_t *lock) |
1da177e4 | 67 | { |
6d9b37a3 RK |
68 | smp_mb(); |
69 | ||
1da177e4 | 70 | __asm__ __volatile__( |
00b4c907 RK |
71 | " str %1, [%0]\n" |
72 | #ifdef CONFIG_CPU_32v6K | |
73 | " mcr p15, 0, %1, c7, c10, 4\n" /* DSB */ | |
74 | " sev" | |
75 | #endif | |
1da177e4 LT |
76 | : |
77 | : "r" (&lock->lock), "r" (0) | |
6d9b37a3 | 78 | : "cc"); |
1da177e4 LT |
79 | } |
80 | ||
81 | /* | |
82 | * RWLOCKS | |
fb1c8f93 IM |
83 | * |
84 | * | |
1da177e4 LT |
85 | * Write locks are easy - we just set bit 31. When unlocking, we can |
86 | * just write zero since the lock is exclusively held. | |
87 | */ | |
fb1c8f93 | 88 | |
7e86df27 | 89 | static inline void __raw_write_lock(raw_rwlock_t *rw) |
1da177e4 LT |
90 | { |
91 | unsigned long tmp; | |
92 | ||
93 | __asm__ __volatile__( | |
94 | "1: ldrex %0, [%1]\n" | |
95 | " teq %0, #0\n" | |
00b4c907 RK |
96 | #ifdef CONFIG_CPU_32v6K |
97 | " wfene\n" | |
98 | #endif | |
1da177e4 LT |
99 | " strexeq %0, %2, [%1]\n" |
100 | " teq %0, #0\n" | |
101 | " bne 1b" | |
102 | : "=&r" (tmp) | |
103 | : "r" (&rw->lock), "r" (0x80000000) | |
6d9b37a3 RK |
104 | : "cc"); |
105 | ||
106 | smp_mb(); | |
1da177e4 LT |
107 | } |
108 | ||
7e86df27 | 109 | static inline int __raw_write_trylock(raw_rwlock_t *rw) |
4e8fd22b RK |
110 | { |
111 | unsigned long tmp; | |
112 | ||
113 | __asm__ __volatile__( | |
114 | "1: ldrex %0, [%1]\n" | |
115 | " teq %0, #0\n" | |
116 | " strexeq %0, %2, [%1]" | |
117 | : "=&r" (tmp) | |
118 | : "r" (&rw->lock), "r" (0x80000000) | |
6d9b37a3 RK |
119 | : "cc"); |
120 | ||
121 | if (tmp == 0) { | |
122 | smp_mb(); | |
123 | return 1; | |
124 | } else { | |
125 | return 0; | |
126 | } | |
4e8fd22b RK |
127 | } |
128 | ||
fb1c8f93 | 129 | static inline void __raw_write_unlock(raw_rwlock_t *rw) |
1da177e4 | 130 | { |
6d9b37a3 RK |
131 | smp_mb(); |
132 | ||
1da177e4 | 133 | __asm__ __volatile__( |
00b4c907 RK |
134 | "str %1, [%0]\n" |
135 | #ifdef CONFIG_CPU_32v6K | |
136 | " mcr p15, 0, %1, c7, c10, 4\n" /* DSB */ | |
137 | " sev\n" | |
138 | #endif | |
1da177e4 LT |
139 | : |
140 | : "r" (&rw->lock), "r" (0) | |
6d9b37a3 | 141 | : "cc"); |
1da177e4 LT |
142 | } |
143 | ||
c2a4c406 | 144 | /* write_can_lock - would write_trylock() succeed? */ |
1e5c5946 | 145 | #define __raw_write_can_lock(x) ((x)->lock == 0) |
c2a4c406 | 146 | |
1da177e4 LT |
147 | /* |
148 | * Read locks are a bit more hairy: | |
149 | * - Exclusively load the lock value. | |
150 | * - Increment it. | |
151 | * - Store new lock value if positive, and we still own this location. | |
152 | * If the value is negative, we've already failed. | |
153 | * - If we failed to store the value, we want a negative result. | |
154 | * - If we failed, try again. | |
155 | * Unlocking is similarly hairy. We may have multiple read locks | |
156 | * currently active. However, we know we won't have any write | |
157 | * locks. | |
158 | */ | |
fb1c8f93 | 159 | static inline void __raw_read_lock(raw_rwlock_t *rw) |
1da177e4 LT |
160 | { |
161 | unsigned long tmp, tmp2; | |
162 | ||
163 | __asm__ __volatile__( | |
164 | "1: ldrex %0, [%2]\n" | |
165 | " adds %0, %0, #1\n" | |
166 | " strexpl %1, %0, [%2]\n" | |
00b4c907 RK |
167 | #ifdef CONFIG_CPU_32v6K |
168 | " wfemi\n" | |
169 | #endif | |
1da177e4 LT |
170 | " rsbpls %0, %1, #0\n" |
171 | " bmi 1b" | |
172 | : "=&r" (tmp), "=&r" (tmp2) | |
173 | : "r" (&rw->lock) | |
6d9b37a3 RK |
174 | : "cc"); |
175 | ||
176 | smp_mb(); | |
1da177e4 LT |
177 | } |
178 | ||
7e86df27 | 179 | static inline void __raw_read_unlock(raw_rwlock_t *rw) |
1da177e4 | 180 | { |
4e8fd22b RK |
181 | unsigned long tmp, tmp2; |
182 | ||
6d9b37a3 RK |
183 | smp_mb(); |
184 | ||
1da177e4 LT |
185 | __asm__ __volatile__( |
186 | "1: ldrex %0, [%2]\n" | |
187 | " sub %0, %0, #1\n" | |
188 | " strex %1, %0, [%2]\n" | |
189 | " teq %1, #0\n" | |
190 | " bne 1b" | |
00b4c907 RK |
191 | #ifdef CONFIG_CPU_32v6K |
192 | "\n cmp %0, #0\n" | |
193 | " mcreq p15, 0, %0, c7, c10, 4\n" | |
194 | " seveq" | |
195 | #endif | |
1da177e4 LT |
196 | : "=&r" (tmp), "=&r" (tmp2) |
197 | : "r" (&rw->lock) | |
6d9b37a3 | 198 | : "cc"); |
1da177e4 LT |
199 | } |
200 | ||
8e34703b RK |
201 | static inline int __raw_read_trylock(raw_rwlock_t *rw) |
202 | { | |
e89bc811 | 203 | unsigned long tmp, tmp2 = 1; |
8e34703b RK |
204 | |
205 | __asm__ __volatile__( | |
206 | "1: ldrex %0, [%2]\n" | |
207 | " adds %0, %0, #1\n" | |
208 | " strexpl %1, %0, [%2]\n" | |
209 | : "=&r" (tmp), "+r" (tmp2) | |
210 | : "r" (&rw->lock) | |
211 | : "cc"); | |
212 | ||
213 | smp_mb(); | |
214 | return tmp2 == 0; | |
215 | } | |
1da177e4 | 216 | |
c2a4c406 CM |
217 | /* read_can_lock - would read_trylock() succeed? */ |
218 | #define __raw_read_can_lock(x) ((x)->lock < 0x80000000) | |
219 | ||
ef6edc97 MS |
220 | #define _raw_spin_relax(lock) cpu_relax() |
221 | #define _raw_read_relax(lock) cpu_relax() | |
222 | #define _raw_write_relax(lock) cpu_relax() | |
223 | ||
1da177e4 | 224 | #endif /* __ASM_SPINLOCK_H */ |