1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
| #define arch_xchg_relaxed(ptr, x) ({ \ (__typeof__(*(ptr)))__arch_xchg((unsigned long)(x), (ptr), \ sizeof(*(ptr))); \ })
static inline unsigned long __arch_xchg(unsigned long x, volatile void *ptr, int size) { extern void __bad_xchg(volatile void *, int); unsigned long ret; #ifdef swp_is_buggy unsigned long flags; #endif #if __LINUX_ARM_ARCH__ >= 6 unsigned int tmp; #endif
prefetchw((const void *)ptr); switch (size) { #if __LINUX_ARM_ARCH__ >= 6 #ifndef CONFIG_CPU_V6 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 2: asm volatile("@ __xchg2\n" "1: ldrexh %0, [%3]\n" " strexh %1, %2, [%3]\n" " teq %1, #0\n" " bne 1b" : "=&r" (ret), "=&r" (tmp) : "r" (x), "r" (ptr) : "memory", "cc"); break; #endif 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: raw_local_irq_save(flags); ret = *(volatile unsigned char *)ptr; *(volatile unsigned char *)ptr = x; raw_local_irq_restore(flags); break;
case 4: raw_local_irq_save(flags); ret = *(volatile unsigned long *)ptr; *(volatile unsigned long *)ptr = x; raw_local_irq_restore(flags); break; #else 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; break; }
return ret; }
|