diff options
author | Nicolas Pitre <nicolas.pitre@linaro.org> | 2011-06-19 23:36:03 -0400 |
---|---|---|
committer | Nicolas Pitre <nico@fluxnic.net> | 2011-06-28 15:47:47 -0400 |
commit | 40fb79c8a88625504857d44de1bc89dc0341e618 (patch) | |
tree | 1f0e417a1f1c80fcaa79729f1a4b29e96f01fed2 /Documentation/arm | |
parent | 37b8304642c7f91df54888955c373ae89b577fcc (diff) |
ARM: add a kuser_cmpxchg64 user space helper
Some user space applications are designed around the ability to perform
atomic operations on 64 bit values. Since this is natively possible
only with ARMv6k and above, let's provide a new kuser helper to perform
the operation with kernel supervision on pre ARMv6k hardware.
Signed-off-by: Nicolas Pitre <nicolas.pitre@linaro.org>
Tested-by: Dave Martin <dave.martin@linaro.org>
Diffstat (limited to 'Documentation/arm')
-rw-r--r-- | Documentation/arm/kernel_user_helpers.txt | 64 |
1 files changed, 64 insertions, 0 deletions
diff --git a/Documentation/arm/kernel_user_helpers.txt b/Documentation/arm/kernel_user_helpers.txt index 0c33f72d1873..a17df9f91d16 100644 --- a/Documentation/arm/kernel_user_helpers.txt +++ b/Documentation/arm/kernel_user_helpers.txt | |||
@@ -201,3 +201,67 @@ typedef void (__kuser_dmb_t)(void); | |||
201 | Notes: | 201 | Notes: |
202 | 202 | ||
203 | - Valid only if __kuser_helper_version >= 3 (from kernel version 2.6.15). | 203 | - Valid only if __kuser_helper_version >= 3 (from kernel version 2.6.15). |
204 | |||
205 | kuser_cmpxchg64 | ||
206 | --------------- | ||
207 | |||
208 | Location: 0xffff0f60 | ||
209 | |||
210 | Reference prototype: | ||
211 | |||
212 | int __kuser_cmpxchg64(const int64_t *oldval, | ||
213 | const int64_t *newval, | ||
214 | volatile int64_t *ptr); | ||
215 | |||
216 | Input: | ||
217 | |||
218 | r0 = pointer to oldval | ||
219 | r1 = pointer to newval | ||
220 | r2 = pointer to target value | ||
221 | lr = return address | ||
222 | |||
223 | Output: | ||
224 | |||
225 | r0 = success code (zero or non-zero) | ||
226 | C flag = set if r0 == 0, clear if r0 != 0 | ||
227 | |||
228 | Clobbered registers: | ||
229 | |||
230 | r3, lr, flags | ||
231 | |||
232 | Definition: | ||
233 | |||
234 | Atomically store the 64-bit value pointed by *newval in *ptr only if *ptr | ||
235 | is equal to the 64-bit value pointed by *oldval. Return zero if *ptr was | ||
236 | changed or non-zero if no exchange happened. | ||
237 | |||
238 | The C flag is also set if *ptr was changed to allow for assembly | ||
239 | optimization in the calling code. | ||
240 | |||
241 | Usage example: | ||
242 | |||
243 | typedef int (__kuser_cmpxchg64_t)(const int64_t *oldval, | ||
244 | const int64_t *newval, | ||
245 | volatile int64_t *ptr); | ||
246 | #define __kuser_cmpxchg64 (*(__kuser_cmpxchg64_t *)0xffff0f60) | ||
247 | |||
248 | int64_t atomic_add64(volatile int64_t *ptr, int64_t val) | ||
249 | { | ||
250 | int64_t old, new; | ||
251 | |||
252 | do { | ||
253 | old = *ptr; | ||
254 | new = old + val; | ||
255 | } while(__kuser_cmpxchg64(&old, &new, ptr)); | ||
256 | |||
257 | return new; | ||
258 | } | ||
259 | |||
260 | Notes: | ||
261 | |||
262 | - This routine already includes memory barriers as needed. | ||
263 | |||
264 | - Due to the length of this sequence, this spans 2 conventional kuser | ||
265 | "slots", therefore 0xffff0f80 is not used as a valid entry point. | ||
266 | |||
267 | - Valid only if __kuser_helper_version >= 5 (from kernel version 3.1). | ||