cmpxchg.h 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. /* SPDX-License-Identifier: GPL-2.0-only */
  2. /*
  3. * Copyright (C) 2014 Regents of the University of California
  4. */
  5. #ifndef _ASM_RISCV_CMPXCHG_H
  6. #define _ASM_RISCV_CMPXCHG_H
  7. #include <linux/bug.h>
  8. #include <asm/alternative-macros.h>
  9. #include <asm/fence.h>
  10. #include <asm/hwcap.h>
  11. #include <asm/insn-def.h>
  12. #define __arch_xchg_masked(sc_sfx, prepend, append, r, p, n) \
  13. ({ \
  14. u32 *__ptr32b = (u32 *)((ulong)(p) & ~0x3); \
  15. ulong __s = ((ulong)(p) & (0x4 - sizeof(*p))) * BITS_PER_BYTE; \
  16. ulong __mask = GENMASK(((sizeof(*p)) * BITS_PER_BYTE) - 1, 0) \
  17. << __s; \
  18. ulong __newx = (ulong)(n) << __s; \
  19. ulong __retx; \
  20. ulong __rc; \
  21. \
  22. __asm__ __volatile__ ( \
  23. prepend \
  24. "0: lr.w %0, %2\n" \
  25. " and %1, %0, %z4\n" \
  26. " or %1, %1, %z3\n" \
  27. " sc.w" sc_sfx " %1, %1, %2\n" \
  28. " bnez %1, 0b\n" \
  29. append \
  30. : "=&r" (__retx), "=&r" (__rc), "+A" (*(__ptr32b)) \
  31. : "rJ" (__newx), "rJ" (~__mask) \
  32. : "memory"); \
  33. \
  34. r = (__typeof__(*(p)))((__retx & __mask) >> __s); \
  35. })
  36. #define __arch_xchg(sfx, prepend, append, r, p, n) \
  37. ({ \
  38. __asm__ __volatile__ ( \
  39. prepend \
  40. " amoswap" sfx " %0, %2, %1\n" \
  41. append \
  42. : "=r" (r), "+A" (*(p)) \
  43. : "r" (n) \
  44. : "memory"); \
  45. })
  46. #define _arch_xchg(ptr, new, sc_sfx, swap_sfx, prepend, \
  47. sc_append, swap_append) \
  48. ({ \
  49. __typeof__(ptr) __ptr = (ptr); \
  50. __typeof__(*(__ptr)) __new = (new); \
  51. __typeof__(*(__ptr)) __ret; \
  52. \
  53. switch (sizeof(*__ptr)) { \
  54. case 1: \
  55. case 2: \
  56. __arch_xchg_masked(sc_sfx, prepend, sc_append, \
  57. __ret, __ptr, __new); \
  58. break; \
  59. case 4: \
  60. __arch_xchg(".w" swap_sfx, prepend, swap_append, \
  61. __ret, __ptr, __new); \
  62. break; \
  63. case 8: \
  64. __arch_xchg(".d" swap_sfx, prepend, swap_append, \
  65. __ret, __ptr, __new); \
  66. break; \
  67. default: \
  68. BUILD_BUG(); \
  69. } \
  70. (__typeof__(*(__ptr)))__ret; \
  71. })
  72. #define arch_xchg_relaxed(ptr, x) \
  73. _arch_xchg(ptr, x, "", "", "", "", "")
  74. #define arch_xchg_acquire(ptr, x) \
  75. _arch_xchg(ptr, x, "", "", "", \
  76. RISCV_ACQUIRE_BARRIER, RISCV_ACQUIRE_BARRIER)
  77. #define arch_xchg_release(ptr, x) \
  78. _arch_xchg(ptr, x, "", "", RISCV_RELEASE_BARRIER, "", "")
  79. #define arch_xchg(ptr, x) \
  80. _arch_xchg(ptr, x, ".rl", ".aqrl", "", RISCV_FULL_BARRIER, "")
  81. #define xchg32(ptr, x) \
  82. ({ \
  83. BUILD_BUG_ON(sizeof(*(ptr)) != 4); \
  84. arch_xchg((ptr), (x)); \
  85. })
  86. #define xchg64(ptr, x) \
  87. ({ \
  88. BUILD_BUG_ON(sizeof(*(ptr)) != 8); \
  89. arch_xchg((ptr), (x)); \
  90. })
  91. /*
  92. * Atomic compare and exchange. Compare OLD with MEM, if identical,
  93. * store NEW in MEM. Return the initial value in MEM. Success is
  94. * indicated by comparing RETURN with OLD.
  95. */
  96. #define __arch_cmpxchg_masked(sc_sfx, prepend, append, r, p, o, n) \
  97. ({ \
  98. u32 *__ptr32b = (u32 *)((ulong)(p) & ~0x3); \
  99. ulong __s = ((ulong)(p) & (0x4 - sizeof(*p))) * BITS_PER_BYTE; \
  100. ulong __mask = GENMASK(((sizeof(*p)) * BITS_PER_BYTE) - 1, 0) \
  101. << __s; \
  102. ulong __newx = (ulong)(n) << __s; \
  103. ulong __oldx = (ulong)(o) << __s; \
  104. ulong __retx; \
  105. ulong __rc; \
  106. \
  107. __asm__ __volatile__ ( \
  108. prepend \
  109. "0: lr.w %0, %2\n" \
  110. " and %1, %0, %z5\n" \
  111. " bne %1, %z3, 1f\n" \
  112. " and %1, %0, %z6\n" \
  113. " or %1, %1, %z4\n" \
  114. " sc.w" sc_sfx " %1, %1, %2\n" \
  115. " bnez %1, 0b\n" \
  116. append \
  117. "1:\n" \
  118. : "=&r" (__retx), "=&r" (__rc), "+A" (*(__ptr32b)) \
  119. : "rJ" ((long)__oldx), "rJ" (__newx), \
  120. "rJ" (__mask), "rJ" (~__mask) \
  121. : "memory"); \
  122. \
  123. r = (__typeof__(*(p)))((__retx & __mask) >> __s); \
  124. })
  125. #define __arch_cmpxchg(lr_sfx, sc_sfx, prepend, append, r, p, co, o, n) \
  126. ({ \
  127. register unsigned int __rc; \
  128. \
  129. __asm__ __volatile__ ( \
  130. prepend \
  131. "0: lr" lr_sfx " %0, %2\n" \
  132. " bne %0, %z3, 1f\n" \
  133. " sc" sc_sfx " %1, %z4, %2\n" \
  134. " bnez %1, 0b\n" \
  135. append \
  136. "1:\n" \
  137. : "=&r" (r), "=&r" (__rc), "+A" (*(p)) \
  138. : "rJ" (co o), "rJ" (n) \
  139. : "memory"); \
  140. })
  141. #define _arch_cmpxchg(ptr, old, new, sc_sfx, prepend, append) \
  142. ({ \
  143. __typeof__(ptr) __ptr = (ptr); \
  144. __typeof__(*(__ptr)) __old = (old); \
  145. __typeof__(*(__ptr)) __new = (new); \
  146. __typeof__(*(__ptr)) __ret; \
  147. \
  148. switch (sizeof(*__ptr)) { \
  149. case 1: \
  150. case 2: \
  151. __arch_cmpxchg_masked(sc_sfx, prepend, append, \
  152. __ret, __ptr, __old, __new); \
  153. break; \
  154. case 4: \
  155. __arch_cmpxchg(".w", ".w" sc_sfx, prepend, append, \
  156. __ret, __ptr, (long)(int)(long), __old, __new); \
  157. break; \
  158. case 8: \
  159. __arch_cmpxchg(".d", ".d" sc_sfx, prepend, append, \
  160. __ret, __ptr, /**/, __old, __new); \
  161. break; \
  162. default: \
  163. BUILD_BUG(); \
  164. } \
  165. (__typeof__(*(__ptr)))__ret; \
  166. })
  167. #define arch_cmpxchg_relaxed(ptr, o, n) \
  168. _arch_cmpxchg((ptr), (o), (n), "", "", "")
  169. #define arch_cmpxchg_acquire(ptr, o, n) \
  170. _arch_cmpxchg((ptr), (o), (n), "", "", RISCV_ACQUIRE_BARRIER)
  171. #define arch_cmpxchg_release(ptr, o, n) \
  172. _arch_cmpxchg((ptr), (o), (n), "", RISCV_RELEASE_BARRIER, "")
  173. #define arch_cmpxchg(ptr, o, n) \
  174. _arch_cmpxchg((ptr), (o), (n), ".rl", "", " fence rw, rw\n")
  175. #define arch_cmpxchg_local(ptr, o, n) \
  176. arch_cmpxchg_relaxed((ptr), (o), (n))
  177. #define arch_cmpxchg64(ptr, o, n) \
  178. ({ \
  179. BUILD_BUG_ON(sizeof(*(ptr)) != 8); \
  180. arch_cmpxchg((ptr), (o), (n)); \
  181. })
  182. #define arch_cmpxchg64_local(ptr, o, n) \
  183. ({ \
  184. BUILD_BUG_ON(sizeof(*(ptr)) != 8); \
  185. arch_cmpxchg_relaxed((ptr), (o), (n)); \
  186. })
  187. #define arch_cmpxchg64_relaxed(ptr, o, n) \
  188. ({ \
  189. BUILD_BUG_ON(sizeof(*(ptr)) != 8); \
  190. arch_cmpxchg_relaxed((ptr), (o), (n)); \
  191. })
  192. #define arch_cmpxchg64_acquire(ptr, o, n) \
  193. ({ \
  194. BUILD_BUG_ON(sizeof(*(ptr)) != 8); \
  195. arch_cmpxchg_acquire((ptr), (o), (n)); \
  196. })
  197. #define arch_cmpxchg64_release(ptr, o, n) \
  198. ({ \
  199. BUILD_BUG_ON(sizeof(*(ptr)) != 8); \
  200. arch_cmpxchg_release((ptr), (o), (n)); \
  201. })
  202. #ifdef CONFIG_RISCV_ISA_ZAWRS
  203. /*
  204. * Despite wrs.nto being "WRS-with-no-timeout", in the absence of changes to
  205. * @val we expect it to still terminate within a "reasonable" amount of time
  206. * for an implementation-specific other reason, a pending, locally-enabled
  207. * interrupt, or because it has been configured to raise an illegal
  208. * instruction exception.
  209. */
  210. static __always_inline void __cmpwait(volatile void *ptr,
  211. unsigned long val,
  212. int size)
  213. {
  214. unsigned long tmp;
  215. asm goto(ALTERNATIVE("j %l[no_zawrs]", "nop",
  216. 0, RISCV_ISA_EXT_ZAWRS, 1)
  217. : : : : no_zawrs);
  218. switch (size) {
  219. case 4:
  220. asm volatile(
  221. " lr.w %0, %1\n"
  222. " xor %0, %0, %2\n"
  223. " bnez %0, 1f\n"
  224. ZAWRS_WRS_NTO "\n"
  225. "1:"
  226. : "=&r" (tmp), "+A" (*(u32 *)ptr)
  227. : "r" (val));
  228. break;
  229. #if __riscv_xlen == 64
  230. case 8:
  231. asm volatile(
  232. " lr.d %0, %1\n"
  233. " xor %0, %0, %2\n"
  234. " bnez %0, 1f\n"
  235. ZAWRS_WRS_NTO "\n"
  236. "1:"
  237. : "=&r" (tmp), "+A" (*(u64 *)ptr)
  238. : "r" (val));
  239. break;
  240. #endif
  241. default:
  242. BUILD_BUG();
  243. }
  244. return;
  245. no_zawrs:
  246. asm volatile(RISCV_PAUSE : : : "memory");
  247. }
  248. #define __cmpwait_relaxed(ptr, val) \
  249. __cmpwait((ptr), (unsigned long)(val), sizeof(*(ptr)))
  250. #endif
  251. #endif /* _ASM_RISCV_CMPXCHG_H */