diff options
Diffstat (limited to 'include/asm-generic/cmpxchg-local.h')
-rw-r--r-- | include/asm-generic/cmpxchg-local.h | 65 |
1 files changed, 65 insertions, 0 deletions
diff --git a/include/asm-generic/cmpxchg-local.h b/include/asm-generic/cmpxchg-local.h new file mode 100644 index 000000000000..b2ba2fc8829a --- /dev/null +++ b/include/asm-generic/cmpxchg-local.h | |||
@@ -0,0 +1,65 @@ | |||
1 | #ifndef __ASM_GENERIC_CMPXCHG_LOCAL_H | ||
2 | #define __ASM_GENERIC_CMPXCHG_LOCAL_H | ||
3 | |||
4 | #include <linux/types.h> | ||
5 | |||
6 | extern unsigned long wrong_size_cmpxchg(volatile void *ptr); | ||
7 | |||
8 | /* | ||
9 | * Generic version of __cmpxchg_local (disables interrupts). Takes an unsigned | ||
10 | * long parameter, supporting various types of architectures. | ||
11 | */ | ||
12 | static inline unsigned long __cmpxchg_local_generic(volatile void *ptr, | ||
13 | unsigned long old, unsigned long new, int size) | ||
14 | { | ||
15 | unsigned long flags, prev; | ||
16 | |||
17 | /* | ||
18 | * Sanity checking, compile-time. | ||
19 | */ | ||
20 | if (size == 8 && sizeof(unsigned long) != 8) | ||
21 | wrong_size_cmpxchg(ptr); | ||
22 | |||
23 | local_irq_save(flags); | ||
24 | switch (size) { | ||
25 | case 1: prev = *(u8 *)ptr; | ||
26 | if (prev == old) | ||
27 | *(u8 *)ptr = (u8)new; | ||
28 | break; | ||
29 | case 2: prev = *(u16 *)ptr; | ||
30 | if (prev == old) | ||
31 | *(u16 *)ptr = (u16)new; | ||
32 | break; | ||
33 | case 4: prev = *(u32 *)ptr; | ||
34 | if (prev == old) | ||
35 | *(u32 *)ptr = (u32)new; | ||
36 | break; | ||
37 | case 8: prev = *(u64 *)ptr; | ||
38 | if (prev == old) | ||
39 | *(u64 *)ptr = (u64)new; | ||
40 | break; | ||
41 | default: | ||
42 | wrong_size_cmpxchg(ptr); | ||
43 | } | ||
44 | local_irq_restore(flags); | ||
45 | return prev; | ||
46 | } | ||
47 | |||
48 | /* | ||
49 | * Generic version of __cmpxchg64_local. Takes an u64 parameter. | ||
50 | */ | ||
51 | static inline u64 __cmpxchg64_local_generic(volatile void *ptr, | ||
52 | u64 old, u64 new) | ||
53 | { | ||
54 | u64 prev; | ||
55 | unsigned long flags; | ||
56 | |||
57 | local_irq_save(flags); | ||
58 | prev = *(u64 *)ptr; | ||
59 | if (prev == old) | ||
60 | *(u64 *)ptr = new; | ||
61 | local_irq_restore(flags); | ||
62 | return prev; | ||
63 | } | ||
64 | |||
65 | #endif | ||