From 9560782f9a68a5de3e72bc3ba71317f373844549 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 26 Jul 2005 19:39:31 +0100 Subject: [PATCH] ARM SMP: Use exclusive load/store for __xchg Signed-off-by: Russell King --- include/asm-arm/system.h | 87 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 58 insertions(+), 29 deletions(-) (limited to 'include') diff --git a/include/asm-arm/system.h b/include/asm-arm/system.h index 2f44b204421..3f9c3626a73 100644 --- a/include/asm-arm/system.h +++ b/include/asm-arm/system.h @@ -323,12 +323,8 @@ do { \ * NOTE that this solution won't work on an SMP system, so explcitly * forbid it here. */ -#ifdef CONFIG_SMP -#error SMP is not supported on SA1100/SA110 -#else #define swp_is_buggy #endif -#endif static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size) { @@ -337,35 +333,68 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size #ifdef swp_is_buggy unsigned long flags; #endif +#if __LINUX_ARM_ARCH__ >= 6 + unsigned int tmp; +#endif switch (size) { -#ifdef swp_is_buggy - case 1: - local_irq_save(flags); - ret = *(volatile unsigned char *)ptr; - *(volatile unsigned char *)ptr = x; - local_irq_restore(flags); - break; - - case 4: - local_irq_save(flags); - ret = *(volatile unsigned long *)ptr; - *(volatile unsigned long *)ptr = x; - local_irq_restore(flags); - break; +#if __LINUX_ARM_ARCH__ >= 6 + case 1: + asm volatile("@ __xchg1\n" + "1: ldrexb %0, [%3]\n" + " strexb %1, %2, [%3]\n" + " teq %1, #0\n" + " bne 1b" + : "=&r" (ret), "=&r" (tmp) + : "r" (x), "r" (ptr) + : "memory", "cc"); + break; + case 4: + asm volatile("@ __xchg4\n" + "1: ldrex %0, [%3]\n" + " strex %1, %2, [%3]\n" + " teq %1, #0\n" + " bne 1b" + : "=&r" (ret), "=&r" (tmp) + : "r" (x), "r" (ptr) + : "memory", "cc"); + break; +#elif defined(swp_is_buggy) +#ifdef CONFIG_SMP +#error SMP is not supported on this platform +#endif + case 1: + local_irq_save(flags); + ret = *(volatile unsigned char *)ptr; + *(volatile unsigned char *)ptr = x; + local_irq_restore(flags); + break; + + case 4: + local_irq_save(flags); + ret = *(volatile unsigned long *)ptr; + *(volatile unsigned long *)ptr = x; + local_irq_restore(flags); + break; #else - case 1: __asm__ __volatile__ ("swpb %0, %1, [%2]" - : "=&r" (ret) - : "r" (x), "r" (ptr) - : "memory", "cc"); - break; - case 4: __asm__ __volatile__ ("swp %0, %1, [%2]" - : "=&r" (ret) - : "r" (x), "r" (ptr) - : "memory", "cc"); - break; + case 1: + asm volatile("@ __xchg1\n" + " swpb %0, %1, [%2]" + : "=&r" (ret) + : "r" (x), "r" (ptr) + : "memory", "cc"); + break; + case 4: + asm volatile("@ __xchg4\n" + " swp %0, %1, [%2]" + : "=&r" (ret) + : "r" (x), "r" (ptr) + : "memory", "cc"); + break; #endif - default: __bad_xchg(ptr, size), ret = 0; + default: + __bad_xchg(ptr, size), ret = 0; + break; } return ret; -- cgit v1.2.3