diff options
Diffstat (limited to 'include/asm-m32r/system.h')
-rw-r--r-- | include/asm-m32r/system.h | 111 |
1 files changed, 101 insertions, 10 deletions
diff --git a/include/asm-m32r/system.h b/include/asm-m32r/system.h index 2365de5c2955..7e7eb3703d85 100644 --- a/include/asm-m32r/system.h +++ b/include/asm-m32r/system.h | |||
@@ -121,8 +121,11 @@ static inline void local_irq_disable(void) | |||
121 | 121 | ||
122 | #define nop() __asm__ __volatile__ ("nop" : : ) | 122 | #define nop() __asm__ __volatile__ ("nop" : : ) |
123 | 123 | ||
124 | #define xchg(ptr,x) \ | 124 | #define xchg(ptr, x) \ |
125 | ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) | 125 | ((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), sizeof(*(ptr)))) |
126 | #define xchg_local(ptr, x) \ | ||
127 | ((__typeof__(*(ptr)))__xchg_local((unsigned long)(x), (ptr), \ | ||
128 | sizeof(*(ptr)))) | ||
126 | 129 | ||
127 | #ifdef CONFIG_SMP | 130 | #ifdef CONFIG_SMP |
128 | extern void __xchg_called_with_bad_pointer(void); | 131 | extern void __xchg_called_with_bad_pointer(void); |
@@ -146,7 +149,7 @@ extern void __xchg_called_with_bad_pointer(void); | |||
146 | #endif /* CONFIG_CHIP_M32700_TS1 */ | 149 | #endif /* CONFIG_CHIP_M32700_TS1 */ |
147 | 150 | ||
148 | static __always_inline unsigned long | 151 | static __always_inline unsigned long |
149 | __xchg(unsigned long x, volatile void * ptr, int size) | 152 | __xchg(unsigned long x, volatile void *ptr, int size) |
150 | { | 153 | { |
151 | unsigned long flags; | 154 | unsigned long flags; |
152 | unsigned long tmp = 0; | 155 | unsigned long tmp = 0; |
@@ -196,6 +199,42 @@ __xchg(unsigned long x, volatile void * ptr, int size) | |||
196 | return (tmp); | 199 | return (tmp); |
197 | } | 200 | } |
198 | 201 | ||
202 | static __always_inline unsigned long | ||
203 | __xchg_local(unsigned long x, volatile void *ptr, int size) | ||
204 | { | ||
205 | unsigned long flags; | ||
206 | unsigned long tmp = 0; | ||
207 | |||
208 | local_irq_save(flags); | ||
209 | |||
210 | switch (size) { | ||
211 | case 1: | ||
212 | __asm__ __volatile__ ( | ||
213 | "ldb %0, @%2 \n\t" | ||
214 | "stb %1, @%2 \n\t" | ||
215 | : "=&r" (tmp) : "r" (x), "r" (ptr) : "memory"); | ||
216 | break; | ||
217 | case 2: | ||
218 | __asm__ __volatile__ ( | ||
219 | "ldh %0, @%2 \n\t" | ||
220 | "sth %1, @%2 \n\t" | ||
221 | : "=&r" (tmp) : "r" (x), "r" (ptr) : "memory"); | ||
222 | break; | ||
223 | case 4: | ||
224 | __asm__ __volatile__ ( | ||
225 | "ld %0, @%2 \n\t" | ||
226 | "st %1, @%2 \n\t" | ||
227 | : "=&r" (tmp) : "r" (x), "r" (ptr) : "memory"); | ||
228 | break; | ||
229 | default: | ||
230 | __xchg_called_with_bad_pointer(); | ||
231 | } | ||
232 | |||
233 | local_irq_restore(flags); | ||
234 | |||
235 | return (tmp); | ||
236 | } | ||
237 | |||
199 | #define __HAVE_ARCH_CMPXCHG 1 | 238 | #define __HAVE_ARCH_CMPXCHG 1 |
200 | 239 | ||
201 | static inline unsigned long | 240 | static inline unsigned long |
@@ -228,6 +267,37 @@ __cmpxchg_u32(volatile unsigned int *p, unsigned int old, unsigned int new) | |||
228 | return retval; | 267 | return retval; |
229 | } | 268 | } |
230 | 269 | ||
270 | static inline unsigned long | ||
271 | __cmpxchg_local_u32(volatile unsigned int *p, unsigned int old, | ||
272 | unsigned int new) | ||
273 | { | ||
274 | unsigned long flags; | ||
275 | unsigned int retval; | ||
276 | |||
277 | local_irq_save(flags); | ||
278 | __asm__ __volatile__ ( | ||
279 | DCACHE_CLEAR("%0", "r4", "%1") | ||
280 | "ld %0, @%1; \n" | ||
281 | " bne %0, %2, 1f; \n" | ||
282 | "st %3, @%1; \n" | ||
283 | " bra 2f; \n" | ||
284 | " .fillinsn \n" | ||
285 | "1:" | ||
286 | "st %0, @%1; \n" | ||
287 | " .fillinsn \n" | ||
288 | "2:" | ||
289 | : "=&r" (retval) | ||
290 | : "r" (p), "r" (old), "r" (new) | ||
291 | : "cbit", "memory" | ||
292 | #ifdef CONFIG_CHIP_M32700_TS1 | ||
293 | , "r4" | ||
294 | #endif /* CONFIG_CHIP_M32700_TS1 */ | ||
295 | ); | ||
296 | local_irq_restore(flags); | ||
297 | |||
298 | return retval; | ||
299 | } | ||
300 | |||
231 | /* This function doesn't exist, so you'll get a linker error | 301 | /* This function doesn't exist, so you'll get a linker error |
232 | if something tries to do an invalid cmpxchg(). */ | 302 | if something tries to do an invalid cmpxchg(). */ |
233 | extern void __cmpxchg_called_with_bad_pointer(void); | 303 | extern void __cmpxchg_called_with_bad_pointer(void); |
@@ -247,13 +317,34 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) | |||
247 | return old; | 317 | return old; |
248 | } | 318 | } |
249 | 319 | ||
250 | #define cmpxchg(ptr,o,n) \ | 320 | #define cmpxchg(ptr, o, n) \ |
251 | ({ \ | 321 | ((__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)(o), \ |
252 | __typeof__(*(ptr)) _o_ = (o); \ | 322 | (unsigned long)(n), sizeof(*(ptr)))) |
253 | __typeof__(*(ptr)) _n_ = (n); \ | 323 | |
254 | (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_, \ | 324 | #include <asm-generic/cmpxchg-local.h> |
255 | (unsigned long)_n_, sizeof(*(ptr))); \ | 325 | |
256 | }) | 326 | static inline unsigned long __cmpxchg_local(volatile void *ptr, |
327 | unsigned long old, | ||
328 | unsigned long new, int size) | ||
329 | { | ||
330 | switch (size) { | ||
331 | case 4: | ||
332 | return __cmpxchg_local_u32(ptr, old, new); | ||
333 | default: | ||
334 | return __cmpxchg_local_generic(ptr, old, new, size); | ||
335 | } | ||
336 | |||
337 | return old; | ||
338 | } | ||
339 | |||
340 | /* | ||
341 | * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make | ||
342 | * them available. | ||
343 | */ | ||
344 | #define cmpxchg_local(ptr, o, n) \ | ||
345 | ((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o), \ | ||
346 | (unsigned long)(n), sizeof(*(ptr)))) | ||
347 | #define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n)) | ||
257 | 348 | ||
258 | #endif /* __KERNEL__ */ | 349 | #endif /* __KERNEL__ */ |
259 | 350 | ||