Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v4.3-rc4 309 lines 6.6 kB view raw
1#ifndef _ASM_POWERPC_CMPXCHG_H_ 2#define _ASM_POWERPC_CMPXCHG_H_ 3 4#ifdef __KERNEL__ 5#include <linux/compiler.h> 6#include <asm/synch.h> 7#include <asm/asm-compat.h> 8 9/* 10 * Atomic exchange 11 * 12 * Changes the memory location '*ptr' to be val and returns 13 * the previous value stored there. 14 */ 15static __always_inline unsigned long 16__xchg_u32(volatile void *p, unsigned long val) 17{ 18 unsigned long prev; 19 20 __asm__ __volatile__( 21 PPC_RELEASE_BARRIER 22"1: lwarx %0,0,%2 \n" 23 PPC405_ERR77(0,%2) 24" stwcx. %3,0,%2 \n\ 25 bne- 1b" 26 PPC_ACQUIRE_BARRIER 27 : "=&r" (prev), "+m" (*(volatile unsigned int *)p) 28 : "r" (p), "r" (val) 29 : "cc", "memory"); 30 31 return prev; 32} 33 34/* 35 * Atomic exchange 36 * 37 * Changes the memory location '*ptr' to be val and returns 38 * the previous value stored there. 39 */ 40static __always_inline unsigned long 41__xchg_u32_local(volatile void *p, unsigned long val) 42{ 43 unsigned long prev; 44 45 __asm__ __volatile__( 46"1: lwarx %0,0,%2 \n" 47 PPC405_ERR77(0,%2) 48" stwcx. %3,0,%2 \n\ 49 bne- 1b" 50 : "=&r" (prev), "+m" (*(volatile unsigned int *)p) 51 : "r" (p), "r" (val) 52 : "cc", "memory"); 53 54 return prev; 55} 56 57#ifdef CONFIG_PPC64 58static __always_inline unsigned long 59__xchg_u64(volatile void *p, unsigned long val) 60{ 61 unsigned long prev; 62 63 __asm__ __volatile__( 64 PPC_RELEASE_BARRIER 65"1: ldarx %0,0,%2 \n" 66 PPC405_ERR77(0,%2) 67" stdcx. %3,0,%2 \n\ 68 bne- 1b" 69 PPC_ACQUIRE_BARRIER 70 : "=&r" (prev), "+m" (*(volatile unsigned long *)p) 71 : "r" (p), "r" (val) 72 : "cc", "memory"); 73 74 return prev; 75} 76 77static __always_inline unsigned long 78__xchg_u64_local(volatile void *p, unsigned long val) 79{ 80 unsigned long prev; 81 82 __asm__ __volatile__( 83"1: ldarx %0,0,%2 \n" 84 PPC405_ERR77(0,%2) 85" stdcx. %3,0,%2 \n\ 86 bne- 1b" 87 : "=&r" (prev), "+m" (*(volatile unsigned long *)p) 88 : "r" (p), "r" (val) 89 : "cc", "memory"); 90 91 return prev; 92} 93#endif 94 95/* 96 * This function doesn't exist, so you'll get a linker error 97 * if something tries to do an invalid xchg(). 98 */ 99extern void __xchg_called_with_bad_pointer(void); 100 101static __always_inline unsigned long 102__xchg(volatile void *ptr, unsigned long x, unsigned int size) 103{ 104 switch (size) { 105 case 4: 106 return __xchg_u32(ptr, x); 107#ifdef CONFIG_PPC64 108 case 8: 109 return __xchg_u64(ptr, x); 110#endif 111 } 112 __xchg_called_with_bad_pointer(); 113 return x; 114} 115 116static __always_inline unsigned long 117__xchg_local(volatile void *ptr, unsigned long x, unsigned int size) 118{ 119 switch (size) { 120 case 4: 121 return __xchg_u32_local(ptr, x); 122#ifdef CONFIG_PPC64 123 case 8: 124 return __xchg_u64_local(ptr, x); 125#endif 126 } 127 __xchg_called_with_bad_pointer(); 128 return x; 129} 130#define xchg(ptr,x) \ 131 ({ \ 132 __typeof__(*(ptr)) _x_ = (x); \ 133 (__typeof__(*(ptr))) __xchg((ptr), (unsigned long)_x_, sizeof(*(ptr))); \ 134 }) 135 136#define xchg_local(ptr,x) \ 137 ({ \ 138 __typeof__(*(ptr)) _x_ = (x); \ 139 (__typeof__(*(ptr))) __xchg_local((ptr), \ 140 (unsigned long)_x_, sizeof(*(ptr))); \ 141 }) 142 143/* 144 * Compare and exchange - if *p == old, set it to new, 145 * and return the old value of *p. 146 */ 147 148static __always_inline unsigned long 149__cmpxchg_u32(volatile unsigned int *p, unsigned long old, unsigned long new) 150{ 151 unsigned int prev; 152 153 __asm__ __volatile__ ( 154 PPC_RELEASE_BARRIER 155"1: lwarx %0,0,%2 # __cmpxchg_u32\n\ 156 cmpw 0,%0,%3\n\ 157 bne- 2f\n" 158 PPC405_ERR77(0,%2) 159" stwcx. %4,0,%2\n\ 160 bne- 1b" 161 PPC_ACQUIRE_BARRIER 162 "\n\ 1632:" 164 : "=&r" (prev), "+m" (*p) 165 : "r" (p), "r" (old), "r" (new) 166 : "cc", "memory"); 167 168 return prev; 169} 170 171static __always_inline unsigned long 172__cmpxchg_u32_local(volatile unsigned int *p, unsigned long old, 173 unsigned long new) 174{ 175 unsigned int prev; 176 177 __asm__ __volatile__ ( 178"1: lwarx %0,0,%2 # __cmpxchg_u32\n\ 179 cmpw 0,%0,%3\n\ 180 bne- 2f\n" 181 PPC405_ERR77(0,%2) 182" stwcx. %4,0,%2\n\ 183 bne- 1b" 184 "\n\ 1852:" 186 : "=&r" (prev), "+m" (*p) 187 : "r" (p), "r" (old), "r" (new) 188 : "cc", "memory"); 189 190 return prev; 191} 192 193#ifdef CONFIG_PPC64 194static __always_inline unsigned long 195__cmpxchg_u64(volatile unsigned long *p, unsigned long old, unsigned long new) 196{ 197 unsigned long prev; 198 199 __asm__ __volatile__ ( 200 PPC_RELEASE_BARRIER 201"1: ldarx %0,0,%2 # __cmpxchg_u64\n\ 202 cmpd 0,%0,%3\n\ 203 bne- 2f\n\ 204 stdcx. %4,0,%2\n\ 205 bne- 1b" 206 PPC_ACQUIRE_BARRIER 207 "\n\ 2082:" 209 : "=&r" (prev), "+m" (*p) 210 : "r" (p), "r" (old), "r" (new) 211 : "cc", "memory"); 212 213 return prev; 214} 215 216static __always_inline unsigned long 217__cmpxchg_u64_local(volatile unsigned long *p, unsigned long old, 218 unsigned long new) 219{ 220 unsigned long prev; 221 222 __asm__ __volatile__ ( 223"1: ldarx %0,0,%2 # __cmpxchg_u64\n\ 224 cmpd 0,%0,%3\n\ 225 bne- 2f\n\ 226 stdcx. %4,0,%2\n\ 227 bne- 1b" 228 "\n\ 2292:" 230 : "=&r" (prev), "+m" (*p) 231 : "r" (p), "r" (old), "r" (new) 232 : "cc", "memory"); 233 234 return prev; 235} 236#endif 237 238/* This function doesn't exist, so you'll get a linker error 239 if something tries to do an invalid cmpxchg(). */ 240extern void __cmpxchg_called_with_bad_pointer(void); 241 242static __always_inline unsigned long 243__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, 244 unsigned int size) 245{ 246 switch (size) { 247 case 4: 248 return __cmpxchg_u32(ptr, old, new); 249#ifdef CONFIG_PPC64 250 case 8: 251 return __cmpxchg_u64(ptr, old, new); 252#endif 253 } 254 __cmpxchg_called_with_bad_pointer(); 255 return old; 256} 257 258static __always_inline unsigned long 259__cmpxchg_local(volatile void *ptr, unsigned long old, unsigned long new, 260 unsigned int size) 261{ 262 switch (size) { 263 case 4: 264 return __cmpxchg_u32_local(ptr, old, new); 265#ifdef CONFIG_PPC64 266 case 8: 267 return __cmpxchg_u64_local(ptr, old, new); 268#endif 269 } 270 __cmpxchg_called_with_bad_pointer(); 271 return old; 272} 273 274#define cmpxchg(ptr, o, n) \ 275 ({ \ 276 __typeof__(*(ptr)) _o_ = (o); \ 277 __typeof__(*(ptr)) _n_ = (n); \ 278 (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_, \ 279 (unsigned long)_n_, sizeof(*(ptr))); \ 280 }) 281 282 283#define cmpxchg_local(ptr, o, n) \ 284 ({ \ 285 __typeof__(*(ptr)) _o_ = (o); \ 286 __typeof__(*(ptr)) _n_ = (n); \ 287 (__typeof__(*(ptr))) __cmpxchg_local((ptr), (unsigned long)_o_, \ 288 (unsigned long)_n_, sizeof(*(ptr))); \ 289 }) 290 291#ifdef CONFIG_PPC64 292#define cmpxchg64(ptr, o, n) \ 293 ({ \ 294 BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ 295 cmpxchg((ptr), (o), (n)); \ 296 }) 297#define cmpxchg64_local(ptr, o, n) \ 298 ({ \ 299 BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ 300 cmpxchg_local((ptr), (o), (n)); \ 301 }) 302#define cmpxchg64_relaxed cmpxchg64_local 303#else 304#include <asm-generic/cmpxchg-local.h> 305#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n)) 306#endif 307 308#endif /* __KERNEL__ */ 309#endif /* _ASM_POWERPC_CMPXCHG_H_ */