cmpxchg.h 7.2 KB

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