atomic.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. /*
  3. * Atomic operations.
  4. *
  5. * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
  6. */
  7. #ifndef _ASM_ATOMIC_H
  8. #define _ASM_ATOMIC_H
  9. #include <linux/types.h>
  10. #include <asm/barrier.h>
  11. #include <asm/cmpxchg.h>
  12. #if __SIZEOF_LONG__ == 4
  13. #define __LL "ll.w "
  14. #define __SC "sc.w "
  15. #define __AMADD "amadd.w "
  16. #define __AMOR "amor.w "
  17. #define __AMAND_DB "amand_db.w "
  18. #define __AMOR_DB "amor_db.w "
  19. #define __AMXOR_DB "amxor_db.w "
  20. #elif __SIZEOF_LONG__ == 8
  21. #define __LL "ll.d "
  22. #define __SC "sc.d "
  23. #define __AMADD "amadd.d "
  24. #define __AMOR "amor.d "
  25. #define __AMAND_DB "amand_db.d "
  26. #define __AMOR_DB "amor_db.d "
  27. #define __AMXOR_DB "amxor_db.d "
  28. #endif
  29. #define ATOMIC_INIT(i) { (i) }
  30. #define arch_atomic_read(v) READ_ONCE((v)->counter)
  31. #define arch_atomic_set(v, i) WRITE_ONCE((v)->counter, (i))
  32. #define ATOMIC_OP(op, I, asm_op) \
  33. static inline void arch_atomic_##op(int i, atomic_t *v) \
  34. { \
  35. __asm__ __volatile__( \
  36. "am"#asm_op".w" " $zero, %1, %0 \n" \
  37. : "+ZB" (v->counter) \
  38. : "r" (I) \
  39. : "memory"); \
  40. }
  41. #define ATOMIC_OP_RETURN(op, I, asm_op, c_op, mb, suffix) \
  42. static inline int arch_atomic_##op##_return##suffix(int i, atomic_t *v) \
  43. { \
  44. int result; \
  45. \
  46. __asm__ __volatile__( \
  47. "am"#asm_op#mb".w" " %1, %2, %0 \n" \
  48. : "+ZB" (v->counter), "=&r" (result) \
  49. : "r" (I) \
  50. : "memory"); \
  51. \
  52. return result c_op I; \
  53. }
  54. #define ATOMIC_FETCH_OP(op, I, asm_op, mb, suffix) \
  55. static inline int arch_atomic_fetch_##op##suffix(int i, atomic_t *v) \
  56. { \
  57. int result; \
  58. \
  59. __asm__ __volatile__( \
  60. "am"#asm_op#mb".w" " %1, %2, %0 \n" \
  61. : "+ZB" (v->counter), "=&r" (result) \
  62. : "r" (I) \
  63. : "memory"); \
  64. \
  65. return result; \
  66. }
  67. #define ATOMIC_OPS(op, I, asm_op, c_op) \
  68. ATOMIC_OP(op, I, asm_op) \
  69. ATOMIC_OP_RETURN(op, I, asm_op, c_op, _db, ) \
  70. ATOMIC_OP_RETURN(op, I, asm_op, c_op, , _relaxed) \
  71. ATOMIC_FETCH_OP(op, I, asm_op, _db, ) \
  72. ATOMIC_FETCH_OP(op, I, asm_op, , _relaxed)
  73. ATOMIC_OPS(add, i, add, +)
  74. ATOMIC_OPS(sub, -i, add, +)
  75. #define arch_atomic_add_return arch_atomic_add_return
  76. #define arch_atomic_add_return_acquire arch_atomic_add_return
  77. #define arch_atomic_add_return_release arch_atomic_add_return
  78. #define arch_atomic_add_return_relaxed arch_atomic_add_return_relaxed
  79. #define arch_atomic_sub_return arch_atomic_sub_return
  80. #define arch_atomic_sub_return_acquire arch_atomic_sub_return
  81. #define arch_atomic_sub_return_release arch_atomic_sub_return
  82. #define arch_atomic_sub_return_relaxed arch_atomic_sub_return_relaxed
  83. #define arch_atomic_fetch_add arch_atomic_fetch_add
  84. #define arch_atomic_fetch_add_acquire arch_atomic_fetch_add
  85. #define arch_atomic_fetch_add_release arch_atomic_fetch_add
  86. #define arch_atomic_fetch_add_relaxed arch_atomic_fetch_add_relaxed
  87. #define arch_atomic_fetch_sub arch_atomic_fetch_sub
  88. #define arch_atomic_fetch_sub_acquire arch_atomic_fetch_sub
  89. #define arch_atomic_fetch_sub_release arch_atomic_fetch_sub
  90. #define arch_atomic_fetch_sub_relaxed arch_atomic_fetch_sub_relaxed
  91. #undef ATOMIC_OPS
  92. #define ATOMIC_OPS(op, I, asm_op) \
  93. ATOMIC_OP(op, I, asm_op) \
  94. ATOMIC_FETCH_OP(op, I, asm_op, _db, ) \
  95. ATOMIC_FETCH_OP(op, I, asm_op, , _relaxed)
  96. ATOMIC_OPS(and, i, and)
  97. ATOMIC_OPS(or, i, or)
  98. ATOMIC_OPS(xor, i, xor)
  99. #define arch_atomic_fetch_and arch_atomic_fetch_and
  100. #define arch_atomic_fetch_and_acquire arch_atomic_fetch_and
  101. #define arch_atomic_fetch_and_release arch_atomic_fetch_and
  102. #define arch_atomic_fetch_and_relaxed arch_atomic_fetch_and_relaxed
  103. #define arch_atomic_fetch_or arch_atomic_fetch_or
  104. #define arch_atomic_fetch_or_acquire arch_atomic_fetch_or
  105. #define arch_atomic_fetch_or_release arch_atomic_fetch_or
  106. #define arch_atomic_fetch_or_relaxed arch_atomic_fetch_or_relaxed
  107. #define arch_atomic_fetch_xor arch_atomic_fetch_xor
  108. #define arch_atomic_fetch_xor_acquire arch_atomic_fetch_xor
  109. #define arch_atomic_fetch_xor_release arch_atomic_fetch_xor
  110. #define arch_atomic_fetch_xor_relaxed arch_atomic_fetch_xor_relaxed
  111. #undef ATOMIC_OPS
  112. #undef ATOMIC_FETCH_OP
  113. #undef ATOMIC_OP_RETURN
  114. #undef ATOMIC_OP
  115. static inline int arch_atomic_fetch_add_unless(atomic_t *v, int a, int u)
  116. {
  117. int prev, rc;
  118. __asm__ __volatile__ (
  119. "0: ll.w %[p], %[c]\n"
  120. " beq %[p], %[u], 1f\n"
  121. " add.w %[rc], %[p], %[a]\n"
  122. " sc.w %[rc], %[c]\n"
  123. " beqz %[rc], 0b\n"
  124. " b 2f\n"
  125. "1:\n"
  126. __WEAK_LLSC_MB
  127. "2:\n"
  128. : [p]"=&r" (prev), [rc]"=&r" (rc),
  129. [c]"=ZB" (v->counter)
  130. : [a]"r" (a), [u]"r" (u)
  131. : "memory");
  132. return prev;
  133. }
  134. #define arch_atomic_fetch_add_unless arch_atomic_fetch_add_unless
  135. static inline int arch_atomic_sub_if_positive(int i, atomic_t *v)
  136. {
  137. int result;
  138. int temp;
  139. if (__builtin_constant_p(i)) {
  140. __asm__ __volatile__(
  141. "1: ll.w %1, %2 # atomic_sub_if_positive\n"
  142. " addi.w %0, %1, %3 \n"
  143. " move %1, %0 \n"
  144. " bltz %0, 2f \n"
  145. " sc.w %1, %2 \n"
  146. " beqz %1, 1b \n"
  147. "2: \n"
  148. __WEAK_LLSC_MB
  149. : "=&r" (result), "=&r" (temp), "+ZC" (v->counter)
  150. : "I" (-i));
  151. } else {
  152. __asm__ __volatile__(
  153. "1: ll.w %1, %2 # atomic_sub_if_positive\n"
  154. " sub.w %0, %1, %3 \n"
  155. " move %1, %0 \n"
  156. " bltz %0, 2f \n"
  157. " sc.w %1, %2 \n"
  158. " beqz %1, 1b \n"
  159. "2: \n"
  160. __WEAK_LLSC_MB
  161. : "=&r" (result), "=&r" (temp), "+ZC" (v->counter)
  162. : "r" (i));
  163. }
  164. return result;
  165. }
  166. #define arch_atomic_dec_if_positive(v) arch_atomic_sub_if_positive(1, v)
  167. #ifdef CONFIG_64BIT
  168. #define ATOMIC64_INIT(i) { (i) }
  169. #define arch_atomic64_read(v) READ_ONCE((v)->counter)
  170. #define arch_atomic64_set(v, i) WRITE_ONCE((v)->counter, (i))
  171. #define ATOMIC64_OP(op, I, asm_op) \
  172. static inline void arch_atomic64_##op(long i, atomic64_t *v) \
  173. { \
  174. __asm__ __volatile__( \
  175. "am"#asm_op".d " " $zero, %1, %0 \n" \
  176. : "+ZB" (v->counter) \
  177. : "r" (I) \
  178. : "memory"); \
  179. }
  180. #define ATOMIC64_OP_RETURN(op, I, asm_op, c_op, mb, suffix) \
  181. static inline long arch_atomic64_##op##_return##suffix(long i, atomic64_t *v) \
  182. { \
  183. long result; \
  184. __asm__ __volatile__( \
  185. "am"#asm_op#mb".d " " %1, %2, %0 \n" \
  186. : "+ZB" (v->counter), "=&r" (result) \
  187. : "r" (I) \
  188. : "memory"); \
  189. \
  190. return result c_op I; \
  191. }
  192. #define ATOMIC64_FETCH_OP(op, I, asm_op, mb, suffix) \
  193. static inline long arch_atomic64_fetch_##op##suffix(long i, atomic64_t *v) \
  194. { \
  195. long result; \
  196. \
  197. __asm__ __volatile__( \
  198. "am"#asm_op#mb".d " " %1, %2, %0 \n" \
  199. : "+ZB" (v->counter), "=&r" (result) \
  200. : "r" (I) \
  201. : "memory"); \
  202. \
  203. return result; \
  204. }
  205. #define ATOMIC64_OPS(op, I, asm_op, c_op) \
  206. ATOMIC64_OP(op, I, asm_op) \
  207. ATOMIC64_OP_RETURN(op, I, asm_op, c_op, _db, ) \
  208. ATOMIC64_OP_RETURN(op, I, asm_op, c_op, , _relaxed) \
  209. ATOMIC64_FETCH_OP(op, I, asm_op, _db, ) \
  210. ATOMIC64_FETCH_OP(op, I, asm_op, , _relaxed)
  211. ATOMIC64_OPS(add, i, add, +)
  212. ATOMIC64_OPS(sub, -i, add, +)
  213. #define arch_atomic64_add_return arch_atomic64_add_return
  214. #define arch_atomic64_add_return_acquire arch_atomic64_add_return
  215. #define arch_atomic64_add_return_release arch_atomic64_add_return
  216. #define arch_atomic64_add_return_relaxed arch_atomic64_add_return_relaxed
  217. #define arch_atomic64_sub_return arch_atomic64_sub_return
  218. #define arch_atomic64_sub_return_acquire arch_atomic64_sub_return
  219. #define arch_atomic64_sub_return_release arch_atomic64_sub_return
  220. #define arch_atomic64_sub_return_relaxed arch_atomic64_sub_return_relaxed
  221. #define arch_atomic64_fetch_add arch_atomic64_fetch_add
  222. #define arch_atomic64_fetch_add_acquire arch_atomic64_fetch_add
  223. #define arch_atomic64_fetch_add_release arch_atomic64_fetch_add
  224. #define arch_atomic64_fetch_add_relaxed arch_atomic64_fetch_add_relaxed
  225. #define arch_atomic64_fetch_sub arch_atomic64_fetch_sub
  226. #define arch_atomic64_fetch_sub_acquire arch_atomic64_fetch_sub
  227. #define arch_atomic64_fetch_sub_release arch_atomic64_fetch_sub
  228. #define arch_atomic64_fetch_sub_relaxed arch_atomic64_fetch_sub_relaxed
  229. #undef ATOMIC64_OPS
  230. #define ATOMIC64_OPS(op, I, asm_op) \
  231. ATOMIC64_OP(op, I, asm_op) \
  232. ATOMIC64_FETCH_OP(op, I, asm_op, _db, ) \
  233. ATOMIC64_FETCH_OP(op, I, asm_op, , _relaxed)
  234. ATOMIC64_OPS(and, i, and)
  235. ATOMIC64_OPS(or, i, or)
  236. ATOMIC64_OPS(xor, i, xor)
  237. #define arch_atomic64_fetch_and arch_atomic64_fetch_and
  238. #define arch_atomic64_fetch_and_acquire arch_atomic64_fetch_and
  239. #define arch_atomic64_fetch_and_release arch_atomic64_fetch_and
  240. #define arch_atomic64_fetch_and_relaxed arch_atomic64_fetch_and_relaxed
  241. #define arch_atomic64_fetch_or arch_atomic64_fetch_or
  242. #define arch_atomic64_fetch_or_acquire arch_atomic64_fetch_or
  243. #define arch_atomic64_fetch_or_release arch_atomic64_fetch_or
  244. #define arch_atomic64_fetch_or_relaxed arch_atomic64_fetch_or_relaxed
  245. #define arch_atomic64_fetch_xor arch_atomic64_fetch_xor
  246. #define arch_atomic64_fetch_xor_acquire arch_atomic64_fetch_xor
  247. #define arch_atomic64_fetch_xor_release arch_atomic64_fetch_xor
  248. #define arch_atomic64_fetch_xor_relaxed arch_atomic64_fetch_xor_relaxed
  249. #undef ATOMIC64_OPS
  250. #undef ATOMIC64_FETCH_OP
  251. #undef ATOMIC64_OP_RETURN
  252. #undef ATOMIC64_OP
  253. static inline long arch_atomic64_fetch_add_unless(atomic64_t *v, long a, long u)
  254. {
  255. long prev, rc;
  256. __asm__ __volatile__ (
  257. "0: ll.d %[p], %[c]\n"
  258. " beq %[p], %[u], 1f\n"
  259. " add.d %[rc], %[p], %[a]\n"
  260. " sc.d %[rc], %[c]\n"
  261. " beqz %[rc], 0b\n"
  262. " b 2f\n"
  263. "1:\n"
  264. __WEAK_LLSC_MB
  265. "2:\n"
  266. : [p]"=&r" (prev), [rc]"=&r" (rc),
  267. [c] "=ZB" (v->counter)
  268. : [a]"r" (a), [u]"r" (u)
  269. : "memory");
  270. return prev;
  271. }
  272. #define arch_atomic64_fetch_add_unless arch_atomic64_fetch_add_unless
  273. static inline long arch_atomic64_sub_if_positive(long i, atomic64_t *v)
  274. {
  275. long result;
  276. long temp;
  277. if (__builtin_constant_p(i)) {
  278. __asm__ __volatile__(
  279. "1: ll.d %1, %2 # atomic64_sub_if_positive \n"
  280. " addi.d %0, %1, %3 \n"
  281. " move %1, %0 \n"
  282. " bltz %0, 2f \n"
  283. " sc.d %1, %2 \n"
  284. " beqz %1, 1b \n"
  285. "2: \n"
  286. __WEAK_LLSC_MB
  287. : "=&r" (result), "=&r" (temp), "+ZC" (v->counter)
  288. : "I" (-i));
  289. } else {
  290. __asm__ __volatile__(
  291. "1: ll.d %1, %2 # atomic64_sub_if_positive \n"
  292. " sub.d %0, %1, %3 \n"
  293. " move %1, %0 \n"
  294. " bltz %0, 2f \n"
  295. " sc.d %1, %2 \n"
  296. " beqz %1, 1b \n"
  297. "2: \n"
  298. __WEAK_LLSC_MB
  299. : "=&r" (result), "=&r" (temp), "+ZC" (v->counter)
  300. : "r" (i));
  301. }
  302. return result;
  303. }
  304. #define arch_atomic64_dec_if_positive(v) arch_atomic64_sub_if_positive(1, v)
  305. #endif /* CONFIG_64BIT */
  306. #endif /* _ASM_ATOMIC_H */