1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0 */ 2*4882a593Smuzhiyun #ifndef ASM_X86_CMPXCHG_H 3*4882a593Smuzhiyun #define ASM_X86_CMPXCHG_H 4*4882a593Smuzhiyun 5*4882a593Smuzhiyun #include <linux/compiler.h> 6*4882a593Smuzhiyun #include <asm/cpufeatures.h> 7*4882a593Smuzhiyun #include <asm/alternative.h> /* Provides LOCK_PREFIX */ 8*4882a593Smuzhiyun 9*4882a593Smuzhiyun /* 10*4882a593Smuzhiyun * Non-existent functions to indicate usage errors at link time 11*4882a593Smuzhiyun * (or compile-time if the compiler implements __compiletime_error(). 12*4882a593Smuzhiyun */ 13*4882a593Smuzhiyun extern void __xchg_wrong_size(void) 14*4882a593Smuzhiyun __compiletime_error("Bad argument size for xchg"); 15*4882a593Smuzhiyun extern void __cmpxchg_wrong_size(void) 16*4882a593Smuzhiyun __compiletime_error("Bad argument size for cmpxchg"); 17*4882a593Smuzhiyun extern void __xadd_wrong_size(void) 18*4882a593Smuzhiyun __compiletime_error("Bad argument size for xadd"); 19*4882a593Smuzhiyun extern void __add_wrong_size(void) 20*4882a593Smuzhiyun __compiletime_error("Bad argument size for add"); 21*4882a593Smuzhiyun 22*4882a593Smuzhiyun /* 23*4882a593Smuzhiyun * Constants for operation sizes. On 32-bit, the 64-bit size it set to 24*4882a593Smuzhiyun * -1 because sizeof will never return -1, thereby making those switch 25*4882a593Smuzhiyun * case statements guaranteeed dead code which the compiler will 26*4882a593Smuzhiyun * eliminate, and allowing the "missing symbol in the default case" to 27*4882a593Smuzhiyun * indicate a usage error. 28*4882a593Smuzhiyun */ 29*4882a593Smuzhiyun #define __X86_CASE_B 1 30*4882a593Smuzhiyun #define __X86_CASE_W 2 31*4882a593Smuzhiyun #define __X86_CASE_L 4 32*4882a593Smuzhiyun #ifdef CONFIG_64BIT 33*4882a593Smuzhiyun #define __X86_CASE_Q 8 34*4882a593Smuzhiyun #else 35*4882a593Smuzhiyun #define __X86_CASE_Q -1 /* sizeof will never return -1 */ 36*4882a593Smuzhiyun #endif 37*4882a593Smuzhiyun 38*4882a593Smuzhiyun /* 39*4882a593Smuzhiyun * An exchange-type operation, which takes a value and a pointer, and 40*4882a593Smuzhiyun * returns the old value. 41*4882a593Smuzhiyun */ 42*4882a593Smuzhiyun #define __xchg_op(ptr, arg, op, lock) \ 43*4882a593Smuzhiyun ({ \ 44*4882a593Smuzhiyun __typeof__ (*(ptr)) __ret = (arg); \ 45*4882a593Smuzhiyun switch (sizeof(*(ptr))) { \ 46*4882a593Smuzhiyun case __X86_CASE_B: \ 47*4882a593Smuzhiyun asm volatile (lock #op "b %b0, %1\n" \ 48*4882a593Smuzhiyun : "+q" (__ret), "+m" (*(ptr)) \ 49*4882a593Smuzhiyun : : "memory", "cc"); \ 50*4882a593Smuzhiyun break; \ 51*4882a593Smuzhiyun case __X86_CASE_W: \ 52*4882a593Smuzhiyun asm volatile (lock #op "w %w0, %1\n" \ 53*4882a593Smuzhiyun : "+r" (__ret), "+m" (*(ptr)) \ 54*4882a593Smuzhiyun : : "memory", "cc"); \ 55*4882a593Smuzhiyun break; \ 56*4882a593Smuzhiyun case __X86_CASE_L: \ 57*4882a593Smuzhiyun asm volatile (lock #op "l %0, %1\n" \ 58*4882a593Smuzhiyun : "+r" (__ret), "+m" (*(ptr)) \ 59*4882a593Smuzhiyun : : "memory", "cc"); \ 60*4882a593Smuzhiyun break; \ 61*4882a593Smuzhiyun case __X86_CASE_Q: \ 62*4882a593Smuzhiyun asm volatile (lock #op "q %q0, %1\n" \ 63*4882a593Smuzhiyun : "+r" (__ret), "+m" (*(ptr)) \ 64*4882a593Smuzhiyun : : "memory", "cc"); \ 65*4882a593Smuzhiyun break; \ 66*4882a593Smuzhiyun default: \ 67*4882a593Smuzhiyun __ ## op ## _wrong_size(); \ 68*4882a593Smuzhiyun } \ 69*4882a593Smuzhiyun __ret; \ 70*4882a593Smuzhiyun }) 71*4882a593Smuzhiyun 72*4882a593Smuzhiyun /* 73*4882a593Smuzhiyun * Note: no "lock" prefix even on SMP: xchg always implies lock anyway. 74*4882a593Smuzhiyun * Since this is generally used to protect other memory information, we 75*4882a593Smuzhiyun * use "asm volatile" and "memory" clobbers to prevent gcc from moving 76*4882a593Smuzhiyun * information around. 77*4882a593Smuzhiyun */ 78*4882a593Smuzhiyun #define arch_xchg(ptr, v) __xchg_op((ptr), (v), xchg, "") 79*4882a593Smuzhiyun 80*4882a593Smuzhiyun /* 81*4882a593Smuzhiyun * Atomic compare and exchange. Compare OLD with MEM, if identical, 82*4882a593Smuzhiyun * store NEW in MEM. Return the initial value in MEM. Success is 83*4882a593Smuzhiyun * indicated by comparing RETURN with OLD. 84*4882a593Smuzhiyun */ 85*4882a593Smuzhiyun #define __raw_cmpxchg(ptr, old, new, size, lock) \ 86*4882a593Smuzhiyun ({ \ 87*4882a593Smuzhiyun __typeof__(*(ptr)) __ret; \ 88*4882a593Smuzhiyun __typeof__(*(ptr)) __old = (old); \ 89*4882a593Smuzhiyun __typeof__(*(ptr)) __new = (new); \ 90*4882a593Smuzhiyun switch (size) { \ 91*4882a593Smuzhiyun case __X86_CASE_B: \ 92*4882a593Smuzhiyun { \ 93*4882a593Smuzhiyun volatile u8 *__ptr = (volatile u8 *)(ptr); \ 94*4882a593Smuzhiyun asm volatile(lock "cmpxchgb %2,%1" \ 95*4882a593Smuzhiyun : "=a" (__ret), "+m" (*__ptr) \ 96*4882a593Smuzhiyun : "q" (__new), "0" (__old) \ 97*4882a593Smuzhiyun : "memory"); \ 98*4882a593Smuzhiyun break; \ 99*4882a593Smuzhiyun } \ 100*4882a593Smuzhiyun case __X86_CASE_W: \ 101*4882a593Smuzhiyun { \ 102*4882a593Smuzhiyun volatile u16 *__ptr = (volatile u16 *)(ptr); \ 103*4882a593Smuzhiyun asm volatile(lock "cmpxchgw %2,%1" \ 104*4882a593Smuzhiyun : "=a" (__ret), "+m" (*__ptr) \ 105*4882a593Smuzhiyun : "r" (__new), "0" (__old) \ 106*4882a593Smuzhiyun : "memory"); \ 107*4882a593Smuzhiyun break; \ 108*4882a593Smuzhiyun } \ 109*4882a593Smuzhiyun case __X86_CASE_L: \ 110*4882a593Smuzhiyun { \ 111*4882a593Smuzhiyun volatile u32 *__ptr = (volatile u32 *)(ptr); \ 112*4882a593Smuzhiyun asm volatile(lock "cmpxchgl %2,%1" \ 113*4882a593Smuzhiyun : "=a" (__ret), "+m" (*__ptr) \ 114*4882a593Smuzhiyun : "r" (__new), "0" (__old) \ 115*4882a593Smuzhiyun : "memory"); \ 116*4882a593Smuzhiyun break; \ 117*4882a593Smuzhiyun } \ 118*4882a593Smuzhiyun case __X86_CASE_Q: \ 119*4882a593Smuzhiyun { \ 120*4882a593Smuzhiyun volatile u64 *__ptr = (volatile u64 *)(ptr); \ 121*4882a593Smuzhiyun asm volatile(lock "cmpxchgq %2,%1" \ 122*4882a593Smuzhiyun : "=a" (__ret), "+m" (*__ptr) \ 123*4882a593Smuzhiyun : "r" (__new), "0" (__old) \ 124*4882a593Smuzhiyun : "memory"); \ 125*4882a593Smuzhiyun break; \ 126*4882a593Smuzhiyun } \ 127*4882a593Smuzhiyun default: \ 128*4882a593Smuzhiyun __cmpxchg_wrong_size(); \ 129*4882a593Smuzhiyun } \ 130*4882a593Smuzhiyun __ret; \ 131*4882a593Smuzhiyun }) 132*4882a593Smuzhiyun 133*4882a593Smuzhiyun #define __cmpxchg(ptr, old, new, size) \ 134*4882a593Smuzhiyun __raw_cmpxchg((ptr), (old), (new), (size), LOCK_PREFIX) 135*4882a593Smuzhiyun 136*4882a593Smuzhiyun #define __sync_cmpxchg(ptr, old, new, size) \ 137*4882a593Smuzhiyun __raw_cmpxchg((ptr), (old), (new), (size), "lock; ") 138*4882a593Smuzhiyun 139*4882a593Smuzhiyun #define __cmpxchg_local(ptr, old, new, size) \ 140*4882a593Smuzhiyun __raw_cmpxchg((ptr), (old), (new), (size), "") 141*4882a593Smuzhiyun 142*4882a593Smuzhiyun #ifdef CONFIG_X86_32 143*4882a593Smuzhiyun # include <asm/cmpxchg_32.h> 144*4882a593Smuzhiyun #else 145*4882a593Smuzhiyun # include <asm/cmpxchg_64.h> 146*4882a593Smuzhiyun #endif 147*4882a593Smuzhiyun 148*4882a593Smuzhiyun #define arch_cmpxchg(ptr, old, new) \ 149*4882a593Smuzhiyun __cmpxchg(ptr, old, new, sizeof(*(ptr))) 150*4882a593Smuzhiyun 151*4882a593Smuzhiyun #define arch_sync_cmpxchg(ptr, old, new) \ 152*4882a593Smuzhiyun __sync_cmpxchg(ptr, old, new, sizeof(*(ptr))) 153*4882a593Smuzhiyun 154*4882a593Smuzhiyun #define arch_cmpxchg_local(ptr, old, new) \ 155*4882a593Smuzhiyun __cmpxchg_local(ptr, old, new, sizeof(*(ptr))) 156*4882a593Smuzhiyun 157*4882a593Smuzhiyun 158*4882a593Smuzhiyun #define __raw_try_cmpxchg(_ptr, _pold, _new, size, lock) \ 159*4882a593Smuzhiyun ({ \ 160*4882a593Smuzhiyun bool success; \ 161*4882a593Smuzhiyun __typeof__(_ptr) _old = (__typeof__(_ptr))(_pold); \ 162*4882a593Smuzhiyun __typeof__(*(_ptr)) __old = *_old; \ 163*4882a593Smuzhiyun __typeof__(*(_ptr)) __new = (_new); \ 164*4882a593Smuzhiyun switch (size) { \ 165*4882a593Smuzhiyun case __X86_CASE_B: \ 166*4882a593Smuzhiyun { \ 167*4882a593Smuzhiyun volatile u8 *__ptr = (volatile u8 *)(_ptr); \ 168*4882a593Smuzhiyun asm volatile(lock "cmpxchgb %[new], %[ptr]" \ 169*4882a593Smuzhiyun CC_SET(z) \ 170*4882a593Smuzhiyun : CC_OUT(z) (success), \ 171*4882a593Smuzhiyun [ptr] "+m" (*__ptr), \ 172*4882a593Smuzhiyun [old] "+a" (__old) \ 173*4882a593Smuzhiyun : [new] "q" (__new) \ 174*4882a593Smuzhiyun : "memory"); \ 175*4882a593Smuzhiyun break; \ 176*4882a593Smuzhiyun } \ 177*4882a593Smuzhiyun case __X86_CASE_W: \ 178*4882a593Smuzhiyun { \ 179*4882a593Smuzhiyun volatile u16 *__ptr = (volatile u16 *)(_ptr); \ 180*4882a593Smuzhiyun asm volatile(lock "cmpxchgw %[new], %[ptr]" \ 181*4882a593Smuzhiyun CC_SET(z) \ 182*4882a593Smuzhiyun : CC_OUT(z) (success), \ 183*4882a593Smuzhiyun [ptr] "+m" (*__ptr), \ 184*4882a593Smuzhiyun [old] "+a" (__old) \ 185*4882a593Smuzhiyun : [new] "r" (__new) \ 186*4882a593Smuzhiyun : "memory"); \ 187*4882a593Smuzhiyun break; \ 188*4882a593Smuzhiyun } \ 189*4882a593Smuzhiyun case __X86_CASE_L: \ 190*4882a593Smuzhiyun { \ 191*4882a593Smuzhiyun volatile u32 *__ptr = (volatile u32 *)(_ptr); \ 192*4882a593Smuzhiyun asm volatile(lock "cmpxchgl %[new], %[ptr]" \ 193*4882a593Smuzhiyun CC_SET(z) \ 194*4882a593Smuzhiyun : CC_OUT(z) (success), \ 195*4882a593Smuzhiyun [ptr] "+m" (*__ptr), \ 196*4882a593Smuzhiyun [old] "+a" (__old) \ 197*4882a593Smuzhiyun : [new] "r" (__new) \ 198*4882a593Smuzhiyun : "memory"); \ 199*4882a593Smuzhiyun break; \ 200*4882a593Smuzhiyun } \ 201*4882a593Smuzhiyun case __X86_CASE_Q: \ 202*4882a593Smuzhiyun { \ 203*4882a593Smuzhiyun volatile u64 *__ptr = (volatile u64 *)(_ptr); \ 204*4882a593Smuzhiyun asm volatile(lock "cmpxchgq %[new], %[ptr]" \ 205*4882a593Smuzhiyun CC_SET(z) \ 206*4882a593Smuzhiyun : CC_OUT(z) (success), \ 207*4882a593Smuzhiyun [ptr] "+m" (*__ptr), \ 208*4882a593Smuzhiyun [old] "+a" (__old) \ 209*4882a593Smuzhiyun : [new] "r" (__new) \ 210*4882a593Smuzhiyun : "memory"); \ 211*4882a593Smuzhiyun break; \ 212*4882a593Smuzhiyun } \ 213*4882a593Smuzhiyun default: \ 214*4882a593Smuzhiyun __cmpxchg_wrong_size(); \ 215*4882a593Smuzhiyun } \ 216*4882a593Smuzhiyun if (unlikely(!success)) \ 217*4882a593Smuzhiyun *_old = __old; \ 218*4882a593Smuzhiyun likely(success); \ 219*4882a593Smuzhiyun }) 220*4882a593Smuzhiyun 221*4882a593Smuzhiyun #define __try_cmpxchg(ptr, pold, new, size) \ 222*4882a593Smuzhiyun __raw_try_cmpxchg((ptr), (pold), (new), (size), LOCK_PREFIX) 223*4882a593Smuzhiyun 224*4882a593Smuzhiyun #define try_cmpxchg(ptr, pold, new) \ 225*4882a593Smuzhiyun __try_cmpxchg((ptr), (pold), (new), sizeof(*(ptr))) 226*4882a593Smuzhiyun 227*4882a593Smuzhiyun /* 228*4882a593Smuzhiyun * xadd() adds "inc" to "*ptr" and atomically returns the previous 229*4882a593Smuzhiyun * value of "*ptr". 230*4882a593Smuzhiyun * 231*4882a593Smuzhiyun * xadd() is locked when multiple CPUs are online 232*4882a593Smuzhiyun */ 233*4882a593Smuzhiyun #define __xadd(ptr, inc, lock) __xchg_op((ptr), (inc), xadd, lock) 234*4882a593Smuzhiyun #define xadd(ptr, inc) __xadd((ptr), (inc), LOCK_PREFIX) 235*4882a593Smuzhiyun 236*4882a593Smuzhiyun #define __cmpxchg_double(pfx, p1, p2, o1, o2, n1, n2) \ 237*4882a593Smuzhiyun ({ \ 238*4882a593Smuzhiyun bool __ret; \ 239*4882a593Smuzhiyun __typeof__(*(p1)) __old1 = (o1), __new1 = (n1); \ 240*4882a593Smuzhiyun __typeof__(*(p2)) __old2 = (o2), __new2 = (n2); \ 241*4882a593Smuzhiyun BUILD_BUG_ON(sizeof(*(p1)) != sizeof(long)); \ 242*4882a593Smuzhiyun BUILD_BUG_ON(sizeof(*(p2)) != sizeof(long)); \ 243*4882a593Smuzhiyun VM_BUG_ON((unsigned long)(p1) % (2 * sizeof(long))); \ 244*4882a593Smuzhiyun VM_BUG_ON((unsigned long)((p1) + 1) != (unsigned long)(p2)); \ 245*4882a593Smuzhiyun asm volatile(pfx "cmpxchg%c5b %1" \ 246*4882a593Smuzhiyun CC_SET(e) \ 247*4882a593Smuzhiyun : CC_OUT(e) (__ret), \ 248*4882a593Smuzhiyun "+m" (*(p1)), "+m" (*(p2)), \ 249*4882a593Smuzhiyun "+a" (__old1), "+d" (__old2) \ 250*4882a593Smuzhiyun : "i" (2 * sizeof(long)), \ 251*4882a593Smuzhiyun "b" (__new1), "c" (__new2)); \ 252*4882a593Smuzhiyun __ret; \ 253*4882a593Smuzhiyun }) 254*4882a593Smuzhiyun 255*4882a593Smuzhiyun #define arch_cmpxchg_double(p1, p2, o1, o2, n1, n2) \ 256*4882a593Smuzhiyun __cmpxchg_double(LOCK_PREFIX, p1, p2, o1, o2, n1, n2) 257*4882a593Smuzhiyun 258*4882a593Smuzhiyun #define arch_cmpxchg_double_local(p1, p2, o1, o2, n1, n2) \ 259*4882a593Smuzhiyun __cmpxchg_double(, p1, p2, o1, o2, n1, n2) 260*4882a593Smuzhiyun 261*4882a593Smuzhiyun #endif /* ASM_X86_CMPXCHG_H */ 262