1 /* 64-bit atomic xchg() and cmpxchg() definitions. 2 * 3 * Copyright (C) 1996, 1997, 2000 David S. Miller (davem@redhat.com) 4 */ 5 6 #ifndef __ARCH_SPARC64_CMPXCHG__ 7 #define __ARCH_SPARC64_CMPXCHG__ 8 9 static inline unsigned long xchg32(__volatile__ unsigned int *m, unsigned int val) 10 { 11 unsigned long tmp1, tmp2; 12 13 __asm__ __volatile__( 14 " mov %0, %1\n" 15 "1: lduw [%4], %2\n" 16 " cas [%4], %2, %0\n" 17 " cmp %2, %0\n" 18 " bne,a,pn %%icc, 1b\n" 19 " mov %1, %0\n" 20 : "=&r" (val), "=&r" (tmp1), "=&r" (tmp2) 21 : "0" (val), "r" (m) 22 : "cc", "memory"); 23 return val; 24 } 25 26 static inline unsigned long xchg64(__volatile__ unsigned long *m, unsigned long val) 27 { 28 unsigned long tmp1, tmp2; 29 30 __asm__ __volatile__( 31 " mov %0, %1\n" 32 "1: ldx [%4], %2\n" 33 " casx [%4], %2, %0\n" 34 " cmp %2, %0\n" 35 " bne,a,pn %%xcc, 1b\n" 36 " mov %1, %0\n" 37 : "=&r" (val), "=&r" (tmp1), "=&r" (tmp2) 38 : "0" (val), "r" (m) 39 : "cc", "memory"); 40 return val; 41 } 42 43 #define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) 44 45 extern void __xchg_called_with_bad_pointer(void); 46 47 static inline unsigned long __xchg(unsigned long x, __volatile__ void * ptr, 48 int size) 49 { 50 switch (size) { 51 case 4: 52 return xchg32(ptr, x); 53 case 8: 54 return xchg64(ptr, x); 55 } 56 __xchg_called_with_bad_pointer(); 57 return x; 58 } 59 60 /* 61 * Atomic compare and exchange. Compare OLD with MEM, if identical, 62 * store NEW in MEM. Return the initial value in MEM. Success is 63 * indicated by comparing RETURN with OLD. 64 */ 65 66 #include <asm-generic/cmpxchg-local.h> 67 68 #define __HAVE_ARCH_CMPXCHG 1 69 70 static inline unsigned long 71 __cmpxchg_u32(volatile int *m, int old, int new) 72 { 73 __asm__ __volatile__("cas [%2], %3, %0" 74 : "=&r" (new) 75 : "0" (new), "r" (m), "r" (old) 76 : "memory"); 77 78 return new; 79 } 80 81 static inline unsigned long 82 __cmpxchg_u64(volatile long *m, unsigned long old, unsigned long new) 83 { 84 __asm__ __volatile__("casx [%2], %3, %0" 85 : "=&r" (new) 86 : "0" (new), "r" (m), "r" (old) 87 : "memory"); 88 89 return new; 90 } 91 92 /* This function doesn't exist, so you'll get a linker error 93 if something tries to do an invalid cmpxchg(). */ 94 extern void __cmpxchg_called_with_bad_pointer(void); 95 96 static inline unsigned long 97 __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) 98 { 99 switch (size) { 100 case 4: 101 return __cmpxchg_u32(ptr, old, new); 102 case 8: 103 return __cmpxchg_u64(ptr, old, new); 104 } 105 __cmpxchg_called_with_bad_pointer(); 106 return old; 107 } 108 109 #define cmpxchg(ptr,o,n) \ 110 ({ \ 111 __typeof__(*(ptr)) _o_ = (o); \ 112 __typeof__(*(ptr)) _n_ = (n); \ 113 (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_, \ 114 (unsigned long)_n_, sizeof(*(ptr))); \ 115 }) 116 117 /* 118 * cmpxchg_local and cmpxchg64_local are atomic wrt current CPU. Always make 119 * them available. 120 */ 121 122 static inline unsigned long __cmpxchg_local(volatile void *ptr, 123 unsigned long old, 124 unsigned long new, int size) 125 { 126 switch (size) { 127 case 4: 128 case 8: return __cmpxchg(ptr, old, new, size); 129 default: 130 return __cmpxchg_local_generic(ptr, old, new, size); 131 } 132 133 return old; 134 } 135 136 #define cmpxchg_local(ptr, o, n) \ 137 ((__typeof__(*(ptr)))__cmpxchg_local((ptr), (unsigned long)(o), \ 138 (unsigned long)(n), sizeof(*(ptr)))) 139 #define cmpxchg64_local(ptr, o, n) \ 140 ({ \ 141 BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ 142 cmpxchg_local((ptr), (o), (n)); \ 143 }) 144 145 #endif /* __ARCH_SPARC64_CMPXCHG__ */ 146