diff options
| author | Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca> | 2008-02-07 03:16:17 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-07 11:42:32 -0500 |
| commit | 7b631c2de63b4475351258197409983c8189ed04 (patch) | |
| tree | 915d5b3d1b7ba8f47e0f5abfba70aec94c106d9e /include/asm-m32r | |
| parent | 4b78fff6e736cae55dc3fb5570c7ef4037eca9b7 (diff) | |
New cmpxchg_local (optimized for UP case) for m32r
Add __xchg_local, xchg_local (define), __cmpxchg_local_u32, __cmpxchg_local,
cmpxchg_local(macro).
cmpxchg_local and cmpxchg64_local will use the architecture specific
__cmpxchg_local_u32 for 32 bits arguments, and use the generic
__cmpxchg_local_generic for 8, 16 and 64 bits arguments.
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca>
Acked-by: Hirokazu Takata <takata@linux-m32r.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'include/asm-m32r')
| -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 | ||
