diff options
Diffstat (limited to 'include/asm-generic')
-rw-r--r-- | include/asm-generic/cmpxchg-local.h | 65 | ||||
-rw-r--r-- | include/asm-generic/cmpxchg.h | 22 |
2 files changed, 87 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 | ||
diff --git a/include/asm-generic/cmpxchg.h b/include/asm-generic/cmpxchg.h new file mode 100644 index 000000000000..213ac6e8fe39 --- /dev/null +++ b/include/asm-generic/cmpxchg.h | |||
@@ -0,0 +1,22 @@ | |||
1 | #ifndef __ASM_GENERIC_CMPXCHG_H | ||
2 | #define __ASM_GENERIC_CMPXCHG_H | ||
3 | |||
4 | /* | ||
5 | * Generic cmpxchg | ||
6 | * | ||
7 | * Uses the local cmpxchg. Does not support SMP. | ||
8 | */ | ||
9 | #ifdef CONFIG_SMP | ||
10 | #error "Cannot use generic cmpxchg on SMP" | ||
11 | #endif | ||
12 | |||
13 | /* | ||
14 | * Atomic compare and exchange. | ||
15 | * | ||
16 | * Do not define __HAVE_ARCH_CMPXCHG because we want to use it to check whether | ||
17 | * a cmpxchg primitive faster than repeated local irq save/restore exists. | ||
18 | */ | ||
19 | #define cmpxchg(ptr, o, n) cmpxchg_local((ptr), (o), (n)) | ||
20 | #define cmpxchg64(ptr, o, n) cmpxchg64_local((ptr), (o), (n)) | ||
21 | |||
22 | #endif | ||