blob: ef4c897772d1459f589ac2a1967a742e822cad2a [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Russell King4baa9922008-08-02 10:55:55 +01002 * arch/arm/include/asm/locks.h
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
4 * Copyright (C) 2000 Russell King
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * Interrupt safe locking assembler.
11 */
12#ifndef __ASM_PROC_LOCKS_H
13#define __ASM_PROC_LOCKS_H
14
15#if __LINUX_ARM_ARCH__ >= 6
16
17#define __down_op(ptr,fail) \
18 ({ \
19 __asm__ __volatile__( \
20 "@ down_op\n" \
21"1: ldrex lr, [%0]\n" \
22" sub lr, lr, %1\n" \
23" strex ip, lr, [%0]\n" \
24" teq ip, #0\n" \
25" bne 1b\n" \
26" teq lr, #0\n" \
27" movmi ip, %0\n" \
28" blmi " #fail \
29 : \
30 : "r" (ptr), "I" (1) \
Russell King6d9b37a2005-07-26 19:44:26 +010031 : "ip", "lr", "cc"); \
32 smp_mb(); \
Linus Torvalds1da177e2005-04-16 15:20:36 -070033 })
34
35#define __down_op_ret(ptr,fail) \
36 ({ \
37 unsigned int ret; \
38 __asm__ __volatile__( \
39 "@ down_op_ret\n" \
40"1: ldrex lr, [%1]\n" \
41" sub lr, lr, %2\n" \
42" strex ip, lr, [%1]\n" \
43" teq ip, #0\n" \
44" bne 1b\n" \
45" teq lr, #0\n" \
46" movmi ip, %1\n" \
47" movpl ip, #0\n" \
48" blmi " #fail "\n" \
49" mov %0, ip" \
50 : "=&r" (ret) \
51 : "r" (ptr), "I" (1) \
Russell King6d9b37a2005-07-26 19:44:26 +010052 : "ip", "lr", "cc"); \
53 smp_mb(); \
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 ret; \
55 })
56
57#define __up_op(ptr,wake) \
58 ({ \
Russell King6d9b37a2005-07-26 19:44:26 +010059 smp_mb(); \
Linus Torvalds1da177e2005-04-16 15:20:36 -070060 __asm__ __volatile__( \
61 "@ up_op\n" \
62"1: ldrex lr, [%0]\n" \
63" add lr, lr, %1\n" \
64" strex ip, lr, [%0]\n" \
65" teq ip, #0\n" \
66" bne 1b\n" \
Russell King4e8fd222005-07-24 12:13:40 +010067" cmp lr, #0\n" \
Linus Torvalds1da177e2005-04-16 15:20:36 -070068" movle ip, %0\n" \
69" blle " #wake \
70 : \
71 : "r" (ptr), "I" (1) \
Russell King6d9b37a2005-07-26 19:44:26 +010072 : "ip", "lr", "cc"); \
Linus Torvalds1da177e2005-04-16 15:20:36 -070073 })
74
75/*
76 * The value 0x01000000 supports up to 128 processors and
77 * lots of processes. BIAS must be chosen such that sub'ing
78 * BIAS once per CPU will result in the long remaining
79 * negative.
80 */
81#define RW_LOCK_BIAS 0x01000000
82#define RW_LOCK_BIAS_STR "0x01000000"
83
84#define __down_op_write(ptr,fail) \
85 ({ \
86 __asm__ __volatile__( \
87 "@ down_op_write\n" \
88"1: ldrex lr, [%0]\n" \
89" sub lr, lr, %1\n" \
90" strex ip, lr, [%0]\n" \
91" teq ip, #0\n" \
92" bne 1b\n" \
93" teq lr, #0\n" \
94" movne ip, %0\n" \
95" blne " #fail \
96 : \
97 : "r" (ptr), "I" (RW_LOCK_BIAS) \
Russell King6d9b37a2005-07-26 19:44:26 +010098 : "ip", "lr", "cc"); \
99 smp_mb(); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 })
101
102#define __up_op_write(ptr,wake) \
103 ({ \
Russell King6d9b37a2005-07-26 19:44:26 +0100104 smp_mb(); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 __asm__ __volatile__( \
Nicolas Pitre9b15c6c2005-10-18 07:51:34 +0100106 "@ up_op_write\n" \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107"1: ldrex lr, [%0]\n" \
Russell King4e8fd222005-07-24 12:13:40 +0100108" adds lr, lr, %1\n" \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109" strex ip, lr, [%0]\n" \
110" teq ip, #0\n" \
111" bne 1b\n" \
112" movcs ip, %0\n" \
113" blcs " #wake \
114 : \
115 : "r" (ptr), "I" (RW_LOCK_BIAS) \
Russell King6d9b37a2005-07-26 19:44:26 +0100116 : "ip", "lr", "cc"); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 })
118
119#define __down_op_read(ptr,fail) \
120 __down_op(ptr, fail)
121
122#define __up_op_read(ptr,wake) \
123 ({ \
Russell King6d9b37a2005-07-26 19:44:26 +0100124 smp_mb(); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 __asm__ __volatile__( \
126 "@ up_op_read\n" \
127"1: ldrex lr, [%0]\n" \
128" add lr, lr, %1\n" \
129" strex ip, lr, [%0]\n" \
130" teq ip, #0\n" \
131" bne 1b\n" \
132" teq lr, #0\n" \
133" moveq ip, %0\n" \
134" bleq " #wake \
135 : \
136 : "r" (ptr), "I" (1) \
Russell King6d9b37a2005-07-26 19:44:26 +0100137 : "ip", "lr", "cc"); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 })
139
140#else
141
142#define __down_op(ptr,fail) \
143 ({ \
144 __asm__ __volatile__( \
145 "@ down_op\n" \
146" mrs ip, cpsr\n" \
147" orr lr, ip, #128\n" \
148" msr cpsr_c, lr\n" \
149" ldr lr, [%0]\n" \
150" subs lr, lr, %1\n" \
151" str lr, [%0]\n" \
152" msr cpsr_c, ip\n" \
153" movmi ip, %0\n" \
154" blmi " #fail \
155 : \
156 : "r" (ptr), "I" (1) \
Russell King6d9b37a2005-07-26 19:44:26 +0100157 : "ip", "lr", "cc"); \
158 smp_mb(); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 })
160
161#define __down_op_ret(ptr,fail) \
162 ({ \
163 unsigned int ret; \
164 __asm__ __volatile__( \
165 "@ down_op_ret\n" \
166" mrs ip, cpsr\n" \
167" orr lr, ip, #128\n" \
168" msr cpsr_c, lr\n" \
169" ldr lr, [%1]\n" \
170" subs lr, lr, %2\n" \
171" str lr, [%1]\n" \
172" msr cpsr_c, ip\n" \
173" movmi ip, %1\n" \
174" movpl ip, #0\n" \
175" blmi " #fail "\n" \
176" mov %0, ip" \
177 : "=&r" (ret) \
178 : "r" (ptr), "I" (1) \
Russell King6d9b37a2005-07-26 19:44:26 +0100179 : "ip", "lr", "cc"); \
180 smp_mb(); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 ret; \
182 })
183
184#define __up_op(ptr,wake) \
185 ({ \
Russell King6d9b37a2005-07-26 19:44:26 +0100186 smp_mb(); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 __asm__ __volatile__( \
188 "@ up_op\n" \
189" mrs ip, cpsr\n" \
190" orr lr, ip, #128\n" \
191" msr cpsr_c, lr\n" \
192" ldr lr, [%0]\n" \
193" adds lr, lr, %1\n" \
194" str lr, [%0]\n" \
195" msr cpsr_c, ip\n" \
196" movle ip, %0\n" \
197" blle " #wake \
198 : \
199 : "r" (ptr), "I" (1) \
Russell King6d9b37a2005-07-26 19:44:26 +0100200 : "ip", "lr", "cc"); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 })
202
203/*
204 * The value 0x01000000 supports up to 128 processors and
205 * lots of processes. BIAS must be chosen such that sub'ing
206 * BIAS once per CPU will result in the long remaining
207 * negative.
208 */
209#define RW_LOCK_BIAS 0x01000000
210#define RW_LOCK_BIAS_STR "0x01000000"
211
212#define __down_op_write(ptr,fail) \
213 ({ \
214 __asm__ __volatile__( \
215 "@ down_op_write\n" \
216" mrs ip, cpsr\n" \
217" orr lr, ip, #128\n" \
218" msr cpsr_c, lr\n" \
219" ldr lr, [%0]\n" \
220" subs lr, lr, %1\n" \
221" str lr, [%0]\n" \
222" msr cpsr_c, ip\n" \
223" movne ip, %0\n" \
224" blne " #fail \
225 : \
226 : "r" (ptr), "I" (RW_LOCK_BIAS) \
Russell King6d9b37a2005-07-26 19:44:26 +0100227 : "ip", "lr", "cc"); \
228 smp_mb(); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 })
230
231#define __up_op_write(ptr,wake) \
232 ({ \
233 __asm__ __volatile__( \
Nicolas Pitre9b15c6c2005-10-18 07:51:34 +0100234 "@ up_op_write\n" \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235" mrs ip, cpsr\n" \
236" orr lr, ip, #128\n" \
237" msr cpsr_c, lr\n" \
238" ldr lr, [%0]\n" \
239" adds lr, lr, %1\n" \
240" str lr, [%0]\n" \
241" msr cpsr_c, ip\n" \
242" movcs ip, %0\n" \
243" blcs " #wake \
244 : \
245 : "r" (ptr), "I" (RW_LOCK_BIAS) \
Russell King6d9b37a2005-07-26 19:44:26 +0100246 : "ip", "lr", "cc"); \
247 smp_mb(); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 })
249
250#define __down_op_read(ptr,fail) \
251 __down_op(ptr, fail)
252
253#define __up_op_read(ptr,wake) \
254 ({ \
Russell King6d9b37a2005-07-26 19:44:26 +0100255 smp_mb(); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256 __asm__ __volatile__( \
257 "@ up_op_read\n" \
258" mrs ip, cpsr\n" \
259" orr lr, ip, #128\n" \
260" msr cpsr_c, lr\n" \
261" ldr lr, [%0]\n" \
262" adds lr, lr, %1\n" \
263" str lr, [%0]\n" \
264" msr cpsr_c, ip\n" \
265" moveq ip, %0\n" \
266" bleq " #wake \
267 : \
268 : "r" (ptr), "I" (1) \
Russell King6d9b37a2005-07-26 19:44:26 +0100269 : "ip", "lr", "cc"); \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 })
271
272#endif
273
274#endif