1*4882a593Smuzhiyun /* SPDX-License-Identifier: GPL-2.0-only */ 2*4882a593Smuzhiyun /* 3*4882a593Smuzhiyun * Based on arch/arm/include/asm/cmpxchg.h 4*4882a593Smuzhiyun * 5*4882a593Smuzhiyun * Copyright (C) 2012 ARM Ltd. 6*4882a593Smuzhiyun */ 7*4882a593Smuzhiyun #ifndef __ASM_CMPXCHG_H 8*4882a593Smuzhiyun #define __ASM_CMPXCHG_H 9*4882a593Smuzhiyun 10*4882a593Smuzhiyun #include <linux/build_bug.h> 11*4882a593Smuzhiyun #include <linux/compiler.h> 12*4882a593Smuzhiyun 13*4882a593Smuzhiyun #include <asm/barrier.h> 14*4882a593Smuzhiyun #include <asm/lse.h> 15*4882a593Smuzhiyun 16*4882a593Smuzhiyun /* 17*4882a593Smuzhiyun * We need separate acquire parameters for ll/sc and lse, since the full 18*4882a593Smuzhiyun * barrier case is generated as release+dmb for the former and 19*4882a593Smuzhiyun * acquire+release for the latter. 20*4882a593Smuzhiyun */ 21*4882a593Smuzhiyun #define __XCHG_CASE(w, sfx, name, sz, mb, nop_lse, acq, acq_lse, rel, cl) \ 22*4882a593Smuzhiyun static inline u##sz __xchg_case_##name##sz(u##sz x, volatile void *ptr) \ 23*4882a593Smuzhiyun { \ 24*4882a593Smuzhiyun u##sz ret; \ 25*4882a593Smuzhiyun unsigned long tmp; \ 26*4882a593Smuzhiyun \ 27*4882a593Smuzhiyun asm volatile(ARM64_LSE_ATOMIC_INSN( \ 28*4882a593Smuzhiyun /* LL/SC */ \ 29*4882a593Smuzhiyun " prfm pstl1strm, %2\n" \ 30*4882a593Smuzhiyun "1: ld" #acq "xr" #sfx "\t%" #w "0, %2\n" \ 31*4882a593Smuzhiyun " st" #rel "xr" #sfx "\t%w1, %" #w "3, %2\n" \ 32*4882a593Smuzhiyun " cbnz %w1, 1b\n" \ 33*4882a593Smuzhiyun " " #mb, \ 34*4882a593Smuzhiyun /* LSE atomics */ \ 35*4882a593Smuzhiyun " swp" #acq_lse #rel #sfx "\t%" #w "3, %" #w "0, %2\n" \ 36*4882a593Smuzhiyun __nops(3) \ 37*4882a593Smuzhiyun " " #nop_lse) \ 38*4882a593Smuzhiyun : "=&r" (ret), "=&r" (tmp), "+Q" (*(u##sz *)ptr) \ 39*4882a593Smuzhiyun : "r" (x) \ 40*4882a593Smuzhiyun : cl); \ 41*4882a593Smuzhiyun \ 42*4882a593Smuzhiyun return ret; \ 43*4882a593Smuzhiyun } 44*4882a593Smuzhiyun 45*4882a593Smuzhiyun __XCHG_CASE(w, b, , 8, , , , , , ) 46*4882a593Smuzhiyun __XCHG_CASE(w, h, , 16, , , , , , ) 47*4882a593Smuzhiyun __XCHG_CASE(w, , , 32, , , , , , ) 48*4882a593Smuzhiyun __XCHG_CASE( , , , 64, , , , , , ) 49*4882a593Smuzhiyun __XCHG_CASE(w, b, acq_, 8, , , a, a, , "memory") 50*4882a593Smuzhiyun __XCHG_CASE(w, h, acq_, 16, , , a, a, , "memory") 51*4882a593Smuzhiyun __XCHG_CASE(w, , acq_, 32, , , a, a, , "memory") 52*4882a593Smuzhiyun __XCHG_CASE( , , acq_, 64, , , a, a, , "memory") 53*4882a593Smuzhiyun __XCHG_CASE(w, b, rel_, 8, , , , , l, "memory") 54*4882a593Smuzhiyun __XCHG_CASE(w, h, rel_, 16, , , , , l, "memory") 55*4882a593Smuzhiyun __XCHG_CASE(w, , rel_, 32, , , , , l, "memory") 56*4882a593Smuzhiyun __XCHG_CASE( , , rel_, 64, , , , , l, "memory") 57*4882a593Smuzhiyun __XCHG_CASE(w, b, mb_, 8, dmb ish, nop, , a, l, "memory") 58*4882a593Smuzhiyun __XCHG_CASE(w, h, mb_, 16, dmb ish, nop, , a, l, "memory") 59*4882a593Smuzhiyun __XCHG_CASE(w, , mb_, 32, dmb ish, nop, , a, l, "memory") 60*4882a593Smuzhiyun __XCHG_CASE( , , mb_, 64, dmb ish, nop, , a, l, "memory") 61*4882a593Smuzhiyun 62*4882a593Smuzhiyun #undef __XCHG_CASE 63*4882a593Smuzhiyun 64*4882a593Smuzhiyun #define __XCHG_GEN(sfx) \ 65*4882a593Smuzhiyun static __always_inline unsigned long __xchg##sfx(unsigned long x, \ 66*4882a593Smuzhiyun volatile void *ptr, \ 67*4882a593Smuzhiyun int size) \ 68*4882a593Smuzhiyun { \ 69*4882a593Smuzhiyun switch (size) { \ 70*4882a593Smuzhiyun case 1: \ 71*4882a593Smuzhiyun return __xchg_case##sfx##_8(x, ptr); \ 72*4882a593Smuzhiyun case 2: \ 73*4882a593Smuzhiyun return __xchg_case##sfx##_16(x, ptr); \ 74*4882a593Smuzhiyun case 4: \ 75*4882a593Smuzhiyun return __xchg_case##sfx##_32(x, ptr); \ 76*4882a593Smuzhiyun case 8: \ 77*4882a593Smuzhiyun return __xchg_case##sfx##_64(x, ptr); \ 78*4882a593Smuzhiyun default: \ 79*4882a593Smuzhiyun BUILD_BUG(); \ 80*4882a593Smuzhiyun } \ 81*4882a593Smuzhiyun \ 82*4882a593Smuzhiyun unreachable(); \ 83*4882a593Smuzhiyun } 84*4882a593Smuzhiyun 85*4882a593Smuzhiyun __XCHG_GEN() 86*4882a593Smuzhiyun __XCHG_GEN(_acq) 87*4882a593Smuzhiyun __XCHG_GEN(_rel) 88*4882a593Smuzhiyun __XCHG_GEN(_mb) 89*4882a593Smuzhiyun 90*4882a593Smuzhiyun #undef __XCHG_GEN 91*4882a593Smuzhiyun 92*4882a593Smuzhiyun #define __xchg_wrapper(sfx, ptr, x) \ 93*4882a593Smuzhiyun ({ \ 94*4882a593Smuzhiyun __typeof__(*(ptr)) __ret; \ 95*4882a593Smuzhiyun __ret = (__typeof__(*(ptr))) \ 96*4882a593Smuzhiyun __xchg##sfx((unsigned long)(x), (ptr), sizeof(*(ptr))); \ 97*4882a593Smuzhiyun __ret; \ 98*4882a593Smuzhiyun }) 99*4882a593Smuzhiyun 100*4882a593Smuzhiyun /* xchg */ 101*4882a593Smuzhiyun #define arch_xchg_relaxed(...) __xchg_wrapper( , __VA_ARGS__) 102*4882a593Smuzhiyun #define arch_xchg_acquire(...) __xchg_wrapper(_acq, __VA_ARGS__) 103*4882a593Smuzhiyun #define arch_xchg_release(...) __xchg_wrapper(_rel, __VA_ARGS__) 104*4882a593Smuzhiyun #define arch_xchg(...) __xchg_wrapper( _mb, __VA_ARGS__) 105*4882a593Smuzhiyun 106*4882a593Smuzhiyun #define __CMPXCHG_CASE(name, sz) \ 107*4882a593Smuzhiyun static inline u##sz __cmpxchg_case_##name##sz(volatile void *ptr, \ 108*4882a593Smuzhiyun u##sz old, \ 109*4882a593Smuzhiyun u##sz new) \ 110*4882a593Smuzhiyun { \ 111*4882a593Smuzhiyun return __lse_ll_sc_body(_cmpxchg_case_##name##sz, \ 112*4882a593Smuzhiyun ptr, old, new); \ 113*4882a593Smuzhiyun } 114*4882a593Smuzhiyun 115*4882a593Smuzhiyun __CMPXCHG_CASE( , 8) 116*4882a593Smuzhiyun __CMPXCHG_CASE( , 16) 117*4882a593Smuzhiyun __CMPXCHG_CASE( , 32) 118*4882a593Smuzhiyun __CMPXCHG_CASE( , 64) 119*4882a593Smuzhiyun __CMPXCHG_CASE(acq_, 8) 120*4882a593Smuzhiyun __CMPXCHG_CASE(acq_, 16) 121*4882a593Smuzhiyun __CMPXCHG_CASE(acq_, 32) 122*4882a593Smuzhiyun __CMPXCHG_CASE(acq_, 64) 123*4882a593Smuzhiyun __CMPXCHG_CASE(rel_, 8) 124*4882a593Smuzhiyun __CMPXCHG_CASE(rel_, 16) 125*4882a593Smuzhiyun __CMPXCHG_CASE(rel_, 32) 126*4882a593Smuzhiyun __CMPXCHG_CASE(rel_, 64) 127*4882a593Smuzhiyun __CMPXCHG_CASE(mb_, 8) 128*4882a593Smuzhiyun __CMPXCHG_CASE(mb_, 16) 129*4882a593Smuzhiyun __CMPXCHG_CASE(mb_, 32) 130*4882a593Smuzhiyun __CMPXCHG_CASE(mb_, 64) 131*4882a593Smuzhiyun 132*4882a593Smuzhiyun #undef __CMPXCHG_CASE 133*4882a593Smuzhiyun 134*4882a593Smuzhiyun #define __CMPXCHG_DBL(name) \ 135*4882a593Smuzhiyun static inline long __cmpxchg_double##name(unsigned long old1, \ 136*4882a593Smuzhiyun unsigned long old2, \ 137*4882a593Smuzhiyun unsigned long new1, \ 138*4882a593Smuzhiyun unsigned long new2, \ 139*4882a593Smuzhiyun volatile void *ptr) \ 140*4882a593Smuzhiyun { \ 141*4882a593Smuzhiyun return __lse_ll_sc_body(_cmpxchg_double##name, \ 142*4882a593Smuzhiyun old1, old2, new1, new2, ptr); \ 143*4882a593Smuzhiyun } 144*4882a593Smuzhiyun 145*4882a593Smuzhiyun __CMPXCHG_DBL( ) 146*4882a593Smuzhiyun __CMPXCHG_DBL(_mb) 147*4882a593Smuzhiyun 148*4882a593Smuzhiyun #undef __CMPXCHG_DBL 149*4882a593Smuzhiyun 150*4882a593Smuzhiyun #define __CMPXCHG_GEN(sfx) \ 151*4882a593Smuzhiyun static __always_inline unsigned long __cmpxchg##sfx(volatile void *ptr, \ 152*4882a593Smuzhiyun unsigned long old, \ 153*4882a593Smuzhiyun unsigned long new, \ 154*4882a593Smuzhiyun int size) \ 155*4882a593Smuzhiyun { \ 156*4882a593Smuzhiyun switch (size) { \ 157*4882a593Smuzhiyun case 1: \ 158*4882a593Smuzhiyun return __cmpxchg_case##sfx##_8(ptr, old, new); \ 159*4882a593Smuzhiyun case 2: \ 160*4882a593Smuzhiyun return __cmpxchg_case##sfx##_16(ptr, old, new); \ 161*4882a593Smuzhiyun case 4: \ 162*4882a593Smuzhiyun return __cmpxchg_case##sfx##_32(ptr, old, new); \ 163*4882a593Smuzhiyun case 8: \ 164*4882a593Smuzhiyun return __cmpxchg_case##sfx##_64(ptr, old, new); \ 165*4882a593Smuzhiyun default: \ 166*4882a593Smuzhiyun BUILD_BUG(); \ 167*4882a593Smuzhiyun } \ 168*4882a593Smuzhiyun \ 169*4882a593Smuzhiyun unreachable(); \ 170*4882a593Smuzhiyun } 171*4882a593Smuzhiyun 172*4882a593Smuzhiyun __CMPXCHG_GEN() 173*4882a593Smuzhiyun __CMPXCHG_GEN(_acq) 174*4882a593Smuzhiyun __CMPXCHG_GEN(_rel) 175*4882a593Smuzhiyun __CMPXCHG_GEN(_mb) 176*4882a593Smuzhiyun 177*4882a593Smuzhiyun #undef __CMPXCHG_GEN 178*4882a593Smuzhiyun 179*4882a593Smuzhiyun #define __cmpxchg_wrapper(sfx, ptr, o, n) \ 180*4882a593Smuzhiyun ({ \ 181*4882a593Smuzhiyun __typeof__(*(ptr)) __ret; \ 182*4882a593Smuzhiyun __ret = (__typeof__(*(ptr))) \ 183*4882a593Smuzhiyun __cmpxchg##sfx((ptr), (unsigned long)(o), \ 184*4882a593Smuzhiyun (unsigned long)(n), sizeof(*(ptr))); \ 185*4882a593Smuzhiyun __ret; \ 186*4882a593Smuzhiyun }) 187*4882a593Smuzhiyun 188*4882a593Smuzhiyun /* cmpxchg */ 189*4882a593Smuzhiyun #define arch_cmpxchg_relaxed(...) __cmpxchg_wrapper( , __VA_ARGS__) 190*4882a593Smuzhiyun #define arch_cmpxchg_acquire(...) __cmpxchg_wrapper(_acq, __VA_ARGS__) 191*4882a593Smuzhiyun #define arch_cmpxchg_release(...) __cmpxchg_wrapper(_rel, __VA_ARGS__) 192*4882a593Smuzhiyun #define arch_cmpxchg(...) __cmpxchg_wrapper( _mb, __VA_ARGS__) 193*4882a593Smuzhiyun #define arch_cmpxchg_local arch_cmpxchg_relaxed 194*4882a593Smuzhiyun 195*4882a593Smuzhiyun /* cmpxchg64 */ 196*4882a593Smuzhiyun #define arch_cmpxchg64_relaxed arch_cmpxchg_relaxed 197*4882a593Smuzhiyun #define arch_cmpxchg64_acquire arch_cmpxchg_acquire 198*4882a593Smuzhiyun #define arch_cmpxchg64_release arch_cmpxchg_release 199*4882a593Smuzhiyun #define arch_cmpxchg64 arch_cmpxchg 200*4882a593Smuzhiyun #define arch_cmpxchg64_local arch_cmpxchg_local 201*4882a593Smuzhiyun 202*4882a593Smuzhiyun /* cmpxchg_double */ 203*4882a593Smuzhiyun #define system_has_cmpxchg_double() 1 204*4882a593Smuzhiyun 205*4882a593Smuzhiyun #define __cmpxchg_double_check(ptr1, ptr2) \ 206*4882a593Smuzhiyun ({ \ 207*4882a593Smuzhiyun if (sizeof(*(ptr1)) != 8) \ 208*4882a593Smuzhiyun BUILD_BUG(); \ 209*4882a593Smuzhiyun VM_BUG_ON((unsigned long *)(ptr2) - (unsigned long *)(ptr1) != 1); \ 210*4882a593Smuzhiyun }) 211*4882a593Smuzhiyun 212*4882a593Smuzhiyun #define arch_cmpxchg_double(ptr1, ptr2, o1, o2, n1, n2) \ 213*4882a593Smuzhiyun ({ \ 214*4882a593Smuzhiyun int __ret; \ 215*4882a593Smuzhiyun __cmpxchg_double_check(ptr1, ptr2); \ 216*4882a593Smuzhiyun __ret = !__cmpxchg_double_mb((unsigned long)(o1), (unsigned long)(o2), \ 217*4882a593Smuzhiyun (unsigned long)(n1), (unsigned long)(n2), \ 218*4882a593Smuzhiyun ptr1); \ 219*4882a593Smuzhiyun __ret; \ 220*4882a593Smuzhiyun }) 221*4882a593Smuzhiyun 222*4882a593Smuzhiyun #define arch_cmpxchg_double_local(ptr1, ptr2, o1, o2, n1, n2) \ 223*4882a593Smuzhiyun ({ \ 224*4882a593Smuzhiyun int __ret; \ 225*4882a593Smuzhiyun __cmpxchg_double_check(ptr1, ptr2); \ 226*4882a593Smuzhiyun __ret = !__cmpxchg_double((unsigned long)(o1), (unsigned long)(o2), \ 227*4882a593Smuzhiyun (unsigned long)(n1), (unsigned long)(n2), \ 228*4882a593Smuzhiyun ptr1); \ 229*4882a593Smuzhiyun __ret; \ 230*4882a593Smuzhiyun }) 231*4882a593Smuzhiyun 232*4882a593Smuzhiyun #define __CMPWAIT_CASE(w, sfx, sz) \ 233*4882a593Smuzhiyun static inline void __cmpwait_case_##sz(volatile void *ptr, \ 234*4882a593Smuzhiyun unsigned long val) \ 235*4882a593Smuzhiyun { \ 236*4882a593Smuzhiyun unsigned long tmp; \ 237*4882a593Smuzhiyun \ 238*4882a593Smuzhiyun asm volatile( \ 239*4882a593Smuzhiyun " sevl\n" \ 240*4882a593Smuzhiyun " wfe\n" \ 241*4882a593Smuzhiyun " ldxr" #sfx "\t%" #w "[tmp], %[v]\n" \ 242*4882a593Smuzhiyun " eor %" #w "[tmp], %" #w "[tmp], %" #w "[val]\n" \ 243*4882a593Smuzhiyun " cbnz %" #w "[tmp], 1f\n" \ 244*4882a593Smuzhiyun " wfe\n" \ 245*4882a593Smuzhiyun "1:" \ 246*4882a593Smuzhiyun : [tmp] "=&r" (tmp), [v] "+Q" (*(unsigned long *)ptr) \ 247*4882a593Smuzhiyun : [val] "r" (val)); \ 248*4882a593Smuzhiyun } 249*4882a593Smuzhiyun 250*4882a593Smuzhiyun __CMPWAIT_CASE(w, b, 8); 251*4882a593Smuzhiyun __CMPWAIT_CASE(w, h, 16); 252*4882a593Smuzhiyun __CMPWAIT_CASE(w, , 32); 253*4882a593Smuzhiyun __CMPWAIT_CASE( , , 64); 254*4882a593Smuzhiyun 255*4882a593Smuzhiyun #undef __CMPWAIT_CASE 256*4882a593Smuzhiyun 257*4882a593Smuzhiyun #define __CMPWAIT_GEN(sfx) \ 258*4882a593Smuzhiyun static __always_inline void __cmpwait##sfx(volatile void *ptr, \ 259*4882a593Smuzhiyun unsigned long val, \ 260*4882a593Smuzhiyun int size) \ 261*4882a593Smuzhiyun { \ 262*4882a593Smuzhiyun switch (size) { \ 263*4882a593Smuzhiyun case 1: \ 264*4882a593Smuzhiyun return __cmpwait_case##sfx##_8(ptr, (u8)val); \ 265*4882a593Smuzhiyun case 2: \ 266*4882a593Smuzhiyun return __cmpwait_case##sfx##_16(ptr, (u16)val); \ 267*4882a593Smuzhiyun case 4: \ 268*4882a593Smuzhiyun return __cmpwait_case##sfx##_32(ptr, val); \ 269*4882a593Smuzhiyun case 8: \ 270*4882a593Smuzhiyun return __cmpwait_case##sfx##_64(ptr, val); \ 271*4882a593Smuzhiyun default: \ 272*4882a593Smuzhiyun BUILD_BUG(); \ 273*4882a593Smuzhiyun } \ 274*4882a593Smuzhiyun \ 275*4882a593Smuzhiyun unreachable(); \ 276*4882a593Smuzhiyun } 277*4882a593Smuzhiyun 278*4882a593Smuzhiyun __CMPWAIT_GEN() 279*4882a593Smuzhiyun 280*4882a593Smuzhiyun #undef __CMPWAIT_GEN 281*4882a593Smuzhiyun 282*4882a593Smuzhiyun #define __cmpwait_relaxed(ptr, val) \ 283*4882a593Smuzhiyun __cmpwait((ptr), (unsigned long)(val), sizeof(*(ptr))) 284*4882a593Smuzhiyun 285*4882a593Smuzhiyun #endif /* __ASM_CMPXCHG_H */ 286