diff options
Diffstat (limited to 'include/asm-arm/system.h')
-rw-r--r-- | include/asm-arm/system.h | 87 |
1 files changed, 58 insertions, 29 deletions
diff --git a/include/asm-arm/system.h b/include/asm-arm/system.h index 2f44b2044214..3f9c3626a73c 100644 --- a/include/asm-arm/system.h +++ b/include/asm-arm/system.h | |||
@@ -323,12 +323,8 @@ do { \ | |||
323 | * NOTE that this solution won't work on an SMP system, so explcitly | 323 | * NOTE that this solution won't work on an SMP system, so explcitly |
324 | * forbid it here. | 324 | * forbid it here. |
325 | */ | 325 | */ |
326 | #ifdef CONFIG_SMP | ||
327 | #error SMP is not supported on SA1100/SA110 | ||
328 | #else | ||
329 | #define swp_is_buggy | 326 | #define swp_is_buggy |
330 | #endif | 327 | #endif |
331 | #endif | ||
332 | 328 | ||
333 | static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size) | 329 | static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size) |
334 | { | 330 | { |
@@ -337,35 +333,68 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size | |||
337 | #ifdef swp_is_buggy | 333 | #ifdef swp_is_buggy |
338 | unsigned long flags; | 334 | unsigned long flags; |
339 | #endif | 335 | #endif |
336 | #if __LINUX_ARM_ARCH__ >= 6 | ||
337 | unsigned int tmp; | ||
338 | #endif | ||
340 | 339 | ||
341 | switch (size) { | 340 | switch (size) { |
342 | #ifdef swp_is_buggy | 341 | #if __LINUX_ARM_ARCH__ >= 6 |
343 | case 1: | 342 | case 1: |
344 | local_irq_save(flags); | 343 | asm volatile("@ __xchg1\n" |
345 | ret = *(volatile unsigned char *)ptr; | 344 | "1: ldrexb %0, [%3]\n" |
346 | *(volatile unsigned char *)ptr = x; | 345 | " strexb %1, %2, [%3]\n" |
347 | local_irq_restore(flags); | 346 | " teq %1, #0\n" |
348 | break; | 347 | " bne 1b" |
349 | 348 | : "=&r" (ret), "=&r" (tmp) | |
350 | case 4: | 349 | : "r" (x), "r" (ptr) |
351 | local_irq_save(flags); | 350 | : "memory", "cc"); |
352 | ret = *(volatile unsigned long *)ptr; | 351 | break; |
353 | *(volatile unsigned long *)ptr = x; | 352 | case 4: |
354 | local_irq_restore(flags); | 353 | asm volatile("@ __xchg4\n" |
355 | break; | 354 | "1: ldrex %0, [%3]\n" |
355 | " strex %1, %2, [%3]\n" | ||
356 | " teq %1, #0\n" | ||
357 | " bne 1b" | ||
358 | : "=&r" (ret), "=&r" (tmp) | ||
359 | : "r" (x), "r" (ptr) | ||
360 | : "memory", "cc"); | ||
361 | break; | ||
362 | #elif defined(swp_is_buggy) | ||
363 | #ifdef CONFIG_SMP | ||
364 | #error SMP is not supported on this platform | ||
365 | #endif | ||
366 | case 1: | ||
367 | local_irq_save(flags); | ||
368 | ret = *(volatile unsigned char *)ptr; | ||
369 | *(volatile unsigned char *)ptr = x; | ||
370 | local_irq_restore(flags); | ||
371 | break; | ||
372 | |||
373 | case 4: | ||
374 | local_irq_save(flags); | ||
375 | ret = *(volatile unsigned long *)ptr; | ||
376 | *(volatile unsigned long *)ptr = x; | ||
377 | local_irq_restore(flags); | ||
378 | break; | ||
356 | #else | 379 | #else |
357 | case 1: __asm__ __volatile__ ("swpb %0, %1, [%2]" | 380 | case 1: |
358 | : "=&r" (ret) | 381 | asm volatile("@ __xchg1\n" |
359 | : "r" (x), "r" (ptr) | 382 | " swpb %0, %1, [%2]" |
360 | : "memory", "cc"); | 383 | : "=&r" (ret) |
361 | break; | 384 | : "r" (x), "r" (ptr) |
362 | case 4: __asm__ __volatile__ ("swp %0, %1, [%2]" | 385 | : "memory", "cc"); |
363 | : "=&r" (ret) | 386 | break; |
364 | : "r" (x), "r" (ptr) | 387 | case 4: |
365 | : "memory", "cc"); | 388 | asm volatile("@ __xchg4\n" |
366 | break; | 389 | " swp %0, %1, [%2]" |
390 | : "=&r" (ret) | ||
391 | : "r" (x), "r" (ptr) | ||
392 | : "memory", "cc"); | ||
393 | break; | ||
367 | #endif | 394 | #endif |
368 | default: __bad_xchg(ptr, size), ret = 0; | 395 | default: |
396 | __bad_xchg(ptr, size), ret = 0; | ||
397 | break; | ||
369 | } | 398 | } |
370 | 399 | ||
371 | return ret; | 400 | return ret; |