diff options
Diffstat (limited to 'arch/mips/include/asm/cmpxchg.h')
-rw-r--r-- | arch/mips/include/asm/cmpxchg.h | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/arch/mips/include/asm/cmpxchg.h b/arch/mips/include/asm/cmpxchg.h index d8d1c2805ac7..285a41fa0b18 100644 --- a/arch/mips/include/asm/cmpxchg.h +++ b/arch/mips/include/asm/cmpxchg.h | |||
@@ -9,6 +9,130 @@ | |||
9 | #define __ASM_CMPXCHG_H | 9 | #define __ASM_CMPXCHG_H |
10 | 10 | ||
11 | #include <linux/irqflags.h> | 11 | #include <linux/irqflags.h> |
12 | #include <asm/war.h> | ||
13 | |||
14 | static inline unsigned long __xchg_u32(volatile int * m, unsigned int val) | ||
15 | { | ||
16 | __u32 retval; | ||
17 | |||
18 | smp_mb__before_llsc(); | ||
19 | |||
20 | if (kernel_uses_llsc && R10000_LLSC_WAR) { | ||
21 | unsigned long dummy; | ||
22 | |||
23 | __asm__ __volatile__( | ||
24 | " .set mips3 \n" | ||
25 | "1: ll %0, %3 # xchg_u32 \n" | ||
26 | " .set mips0 \n" | ||
27 | " move %2, %z4 \n" | ||
28 | " .set mips3 \n" | ||
29 | " sc %2, %1 \n" | ||
30 | " beqzl %2, 1b \n" | ||
31 | " .set mips0 \n" | ||
32 | : "=&r" (retval), "=m" (*m), "=&r" (dummy) | ||
33 | : "R" (*m), "Jr" (val) | ||
34 | : "memory"); | ||
35 | } else if (kernel_uses_llsc) { | ||
36 | unsigned long dummy; | ||
37 | |||
38 | do { | ||
39 | __asm__ __volatile__( | ||
40 | " .set mips3 \n" | ||
41 | " ll %0, %3 # xchg_u32 \n" | ||
42 | " .set mips0 \n" | ||
43 | " move %2, %z4 \n" | ||
44 | " .set mips3 \n" | ||
45 | " sc %2, %1 \n" | ||
46 | " .set mips0 \n" | ||
47 | : "=&r" (retval), "=m" (*m), "=&r" (dummy) | ||
48 | : "R" (*m), "Jr" (val) | ||
49 | : "memory"); | ||
50 | } while (unlikely(!dummy)); | ||
51 | } else { | ||
52 | unsigned long flags; | ||
53 | |||
54 | raw_local_irq_save(flags); | ||
55 | retval = *m; | ||
56 | *m = val; | ||
57 | raw_local_irq_restore(flags); /* implies memory barrier */ | ||
58 | } | ||
59 | |||
60 | smp_llsc_mb(); | ||
61 | |||
62 | return retval; | ||
63 | } | ||
64 | |||
65 | #ifdef CONFIG_64BIT | ||
66 | static inline __u64 __xchg_u64(volatile __u64 * m, __u64 val) | ||
67 | { | ||
68 | __u64 retval; | ||
69 | |||
70 | smp_mb__before_llsc(); | ||
71 | |||
72 | if (kernel_uses_llsc && R10000_LLSC_WAR) { | ||
73 | unsigned long dummy; | ||
74 | |||
75 | __asm__ __volatile__( | ||
76 | " .set mips3 \n" | ||
77 | "1: lld %0, %3 # xchg_u64 \n" | ||
78 | " move %2, %z4 \n" | ||
79 | " scd %2, %1 \n" | ||
80 | " beqzl %2, 1b \n" | ||
81 | " .set mips0 \n" | ||
82 | : "=&r" (retval), "=m" (*m), "=&r" (dummy) | ||
83 | : "R" (*m), "Jr" (val) | ||
84 | : "memory"); | ||
85 | } else if (kernel_uses_llsc) { | ||
86 | unsigned long dummy; | ||
87 | |||
88 | do { | ||
89 | __asm__ __volatile__( | ||
90 | " .set mips3 \n" | ||
91 | " lld %0, %3 # xchg_u64 \n" | ||
92 | " move %2, %z4 \n" | ||
93 | " scd %2, %1 \n" | ||
94 | " .set mips0 \n" | ||
95 | : "=&r" (retval), "=m" (*m), "=&r" (dummy) | ||
96 | : "R" (*m), "Jr" (val) | ||
97 | : "memory"); | ||
98 | } while (unlikely(!dummy)); | ||
99 | } else { | ||
100 | unsigned long flags; | ||
101 | |||
102 | raw_local_irq_save(flags); | ||
103 | retval = *m; | ||
104 | *m = val; | ||
105 | raw_local_irq_restore(flags); /* implies memory barrier */ | ||
106 | } | ||
107 | |||
108 | smp_llsc_mb(); | ||
109 | |||
110 | return retval; | ||
111 | } | ||
112 | #else | ||
113 | extern __u64 __xchg_u64_unsupported_on_32bit_kernels(volatile __u64 * m, __u64 val); | ||
114 | #define __xchg_u64 __xchg_u64_unsupported_on_32bit_kernels | ||
115 | #endif | ||
116 | |||
117 | static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size) | ||
118 | { | ||
119 | switch (size) { | ||
120 | case 4: | ||
121 | return __xchg_u32(ptr, x); | ||
122 | case 8: | ||
123 | return __xchg_u64(ptr, x); | ||
124 | } | ||
125 | |||
126 | return x; | ||
127 | } | ||
128 | |||
129 | #define xchg(ptr, x) \ | ||
130 | ({ \ | ||
131 | BUILD_BUG_ON(sizeof(*(ptr)) & ~0xc); \ | ||
132 | \ | ||
133 | ((__typeof__(*(ptr))) \ | ||
134 | __xchg((unsigned long)(x), (ptr), sizeof(*(ptr)))); \ | ||
135 | }) | ||
12 | 136 | ||
13 | #define __HAVE_ARCH_CMPXCHG 1 | 137 | #define __HAVE_ARCH_CMPXCHG 1 |
14 | 138 | ||