cmpxchg.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. #ifndef _ASM_POWERPC_CMPXCHG_H_
  3. #define _ASM_POWERPC_CMPXCHG_H_
  4. #ifdef __KERNEL__
  5. #include <linux/compiler.h>
  6. #include <asm/synch.h>
  7. #include <linux/bug.h>
  8. #ifdef __BIG_ENDIAN
  9. #define BITOFF_CAL(size, off) ((sizeof(u32) - size - off) * BITS_PER_BYTE)
  10. #else
  11. #define BITOFF_CAL(size, off) (off * BITS_PER_BYTE)
  12. #endif
  13. #define XCHG_GEN(type, sfx, cl) \
  14. static inline u32 __xchg_##type##sfx(volatile void *p, u32 val) \
  15. { \
  16. unsigned int prev, prev_mask, tmp, bitoff, off; \
  17. \
  18. off = (unsigned long)p % sizeof(u32); \
  19. bitoff = BITOFF_CAL(sizeof(type), off); \
  20. p -= off; \
  21. val <<= bitoff; \
  22. prev_mask = (u32)(type)-1 << bitoff; \
  23. \
  24. __asm__ __volatile__( \
  25. "1: lwarx %0,0,%3\n" \
  26. " andc %1,%0,%5\n" \
  27. " or %1,%1,%4\n" \
  28. " stwcx. %1,0,%3\n" \
  29. " bne- 1b\n" \
  30. : "=&r" (prev), "=&r" (tmp), "+m" (*(u32*)p) \
  31. : "r" (p), "r" (val), "r" (prev_mask) \
  32. : "cc", cl); \
  33. \
  34. return prev >> bitoff; \
  35. }
  36. #define CMPXCHG_GEN(type, sfx, br, br2, cl) \
  37. static inline \
  38. u32 __cmpxchg_##type##sfx(volatile void *p, u32 old, u32 new) \
  39. { \
  40. unsigned int prev, prev_mask, tmp, bitoff, off; \
  41. \
  42. off = (unsigned long)p % sizeof(u32); \
  43. bitoff = BITOFF_CAL(sizeof(type), off); \
  44. p -= off; \
  45. old <<= bitoff; \
  46. new <<= bitoff; \
  47. prev_mask = (u32)(type)-1 << bitoff; \
  48. \
  49. __asm__ __volatile__( \
  50. br \
  51. "1: lwarx %0,0,%3\n" \
  52. " and %1,%0,%6\n" \
  53. " cmpw 0,%1,%4\n" \
  54. " bne- 2f\n" \
  55. " andc %1,%0,%6\n" \
  56. " or %1,%1,%5\n" \
  57. " stwcx. %1,0,%3\n" \
  58. " bne- 1b\n" \
  59. br2 \
  60. "\n" \
  61. "2:" \
  62. : "=&r" (prev), "=&r" (tmp), "+m" (*(u32*)p) \
  63. : "r" (p), "r" (old), "r" (new), "r" (prev_mask) \
  64. : "cc", cl); \
  65. \
  66. return prev >> bitoff; \
  67. }
  68. /*
  69. * Atomic exchange
  70. *
  71. * Changes the memory location '*p' to be val and returns
  72. * the previous value stored there.
  73. */
  74. XCHG_GEN(u8, _local, "memory");
  75. XCHG_GEN(u8, _relaxed, "cc");
  76. XCHG_GEN(u16, _local, "memory");
  77. XCHG_GEN(u16, _relaxed, "cc");
  78. static __always_inline unsigned long
  79. __xchg_u32_local(volatile void *p, unsigned long val)
  80. {
  81. unsigned long prev;
  82. __asm__ __volatile__(
  83. "1: lwarx %0,0,%2 \n"
  84. " stwcx. %3,0,%2 \n\
  85. bne- 1b"
  86. : "=&r" (prev), "+m" (*(volatile unsigned int *)p)
  87. : "r" (p), "r" (val)
  88. : "cc", "memory");
  89. return prev;
  90. }
  91. static __always_inline unsigned long
  92. __xchg_u32_relaxed(u32 *p, unsigned long val)
  93. {
  94. unsigned long prev;
  95. __asm__ __volatile__(
  96. "1: lwarx %0,0,%2\n"
  97. " stwcx. %3,0,%2\n"
  98. " bne- 1b"
  99. : "=&r" (prev), "+m" (*p)
  100. : "r" (p), "r" (val)
  101. : "cc");
  102. return prev;
  103. }
  104. #ifdef CONFIG_PPC64
  105. static __always_inline unsigned long
  106. __xchg_u64_local(volatile void *p, unsigned long val)
  107. {
  108. unsigned long prev;
  109. __asm__ __volatile__(
  110. "1: ldarx %0,0,%2 \n"
  111. " stdcx. %3,0,%2 \n\
  112. bne- 1b"
  113. : "=&r" (prev), "+m" (*(volatile unsigned long *)p)
  114. : "r" (p), "r" (val)
  115. : "cc", "memory");
  116. return prev;
  117. }
  118. static __always_inline unsigned long
  119. __xchg_u64_relaxed(u64 *p, unsigned long val)
  120. {
  121. unsigned long prev;
  122. __asm__ __volatile__(
  123. "1: ldarx %0,0,%2\n"
  124. " stdcx. %3,0,%2\n"
  125. " bne- 1b"
  126. : "=&r" (prev), "+m" (*p)
  127. : "r" (p), "r" (val)
  128. : "cc");
  129. return prev;
  130. }
  131. #endif
  132. static __always_inline unsigned long
  133. __xchg_local(void *ptr, unsigned long x, unsigned int size)
  134. {
  135. switch (size) {
  136. case 1:
  137. return __xchg_u8_local(ptr, x);
  138. case 2:
  139. return __xchg_u16_local(ptr, x);
  140. case 4:
  141. return __xchg_u32_local(ptr, x);
  142. #ifdef CONFIG_PPC64
  143. case 8:
  144. return __xchg_u64_local(ptr, x);
  145. #endif
  146. }
  147. BUILD_BUG_ON_MSG(1, "Unsupported size for __xchg");
  148. return x;
  149. }
  150. static __always_inline unsigned long
  151. __xchg_relaxed(void *ptr, unsigned long x, unsigned int size)
  152. {
  153. switch (size) {
  154. case 1:
  155. return __xchg_u8_relaxed(ptr, x);
  156. case 2:
  157. return __xchg_u16_relaxed(ptr, x);
  158. case 4:
  159. return __xchg_u32_relaxed(ptr, x);
  160. #ifdef CONFIG_PPC64
  161. case 8:
  162. return __xchg_u64_relaxed(ptr, x);
  163. #endif
  164. }
  165. BUILD_BUG_ON_MSG(1, "Unsupported size for __xchg_local");
  166. return x;
  167. }
  168. #define arch_xchg_local(ptr,x) \
  169. ({ \
  170. __typeof__(*(ptr)) _x_ = (x); \
  171. (__typeof__(*(ptr))) __xchg_local((ptr), \
  172. (unsigned long)_x_, sizeof(*(ptr))); \
  173. })
  174. #define arch_xchg_relaxed(ptr, x) \
  175. ({ \
  176. __typeof__(*(ptr)) _x_ = (x); \
  177. (__typeof__(*(ptr))) __xchg_relaxed((ptr), \
  178. (unsigned long)_x_, sizeof(*(ptr))); \
  179. })
  180. /*
  181. * Compare and exchange - if *p == old, set it to new,
  182. * and return the old value of *p.
  183. */
  184. CMPXCHG_GEN(u8, , PPC_ATOMIC_ENTRY_BARRIER, PPC_ATOMIC_EXIT_BARRIER, "memory");
  185. CMPXCHG_GEN(u8, _local, , , "memory");
  186. CMPXCHG_GEN(u8, _acquire, , PPC_ACQUIRE_BARRIER, "memory");
  187. CMPXCHG_GEN(u8, _relaxed, , , "cc");
  188. CMPXCHG_GEN(u16, , PPC_ATOMIC_ENTRY_BARRIER, PPC_ATOMIC_EXIT_BARRIER, "memory");
  189. CMPXCHG_GEN(u16, _local, , , "memory");
  190. CMPXCHG_GEN(u16, _acquire, , PPC_ACQUIRE_BARRIER, "memory");
  191. CMPXCHG_GEN(u16, _relaxed, , , "cc");
  192. static __always_inline unsigned long
  193. __cmpxchg_u32(volatile unsigned int *p, unsigned long old, unsigned long new)
  194. {
  195. unsigned int prev;
  196. __asm__ __volatile__ (
  197. PPC_ATOMIC_ENTRY_BARRIER
  198. "1: lwarx %0,0,%2 # __cmpxchg_u32\n\
  199. cmpw 0,%0,%3\n\
  200. bne- 2f\n"
  201. " stwcx. %4,0,%2\n\
  202. bne- 1b"
  203. PPC_ATOMIC_EXIT_BARRIER
  204. "\n\
  205. 2:"
  206. : "=&r" (prev), "+m" (*p)
  207. : "r" (p), "r" (old), "r" (new)
  208. : "cc", "memory");
  209. return prev;
  210. }
  211. static __always_inline unsigned long
  212. __cmpxchg_u32_local(volatile unsigned int *p, unsigned long old,
  213. unsigned long new)
  214. {
  215. unsigned int prev;
  216. __asm__ __volatile__ (
  217. "1: lwarx %0,0,%2 # __cmpxchg_u32\n\
  218. cmpw 0,%0,%3\n\
  219. bne- 2f\n"
  220. " stwcx. %4,0,%2\n\
  221. bne- 1b"
  222. "\n\
  223. 2:"
  224. : "=&r" (prev), "+m" (*p)
  225. : "r" (p), "r" (old), "r" (new)
  226. : "cc", "memory");
  227. return prev;
  228. }
  229. static __always_inline unsigned long
  230. __cmpxchg_u32_relaxed(u32 *p, unsigned long old, unsigned long new)
  231. {
  232. unsigned long prev;
  233. __asm__ __volatile__ (
  234. "1: lwarx %0,0,%2 # __cmpxchg_u32_relaxed\n"
  235. " cmpw 0,%0,%3\n"
  236. " bne- 2f\n"
  237. " stwcx. %4,0,%2\n"
  238. " bne- 1b\n"
  239. "2:"
  240. : "=&r" (prev), "+m" (*p)
  241. : "r" (p), "r" (old), "r" (new)
  242. : "cc");
  243. return prev;
  244. }
  245. /*
  246. * cmpxchg family don't have order guarantee if cmp part fails, therefore we
  247. * can avoid superfluous barriers if we use assembly code to implement
  248. * cmpxchg() and cmpxchg_acquire(), however we don't do the similar for
  249. * cmpxchg_release() because that will result in putting a barrier in the
  250. * middle of a ll/sc loop, which is probably a bad idea. For example, this
  251. * might cause the conditional store more likely to fail.
  252. */
  253. static __always_inline unsigned long
  254. __cmpxchg_u32_acquire(u32 *p, unsigned long old, unsigned long new)
  255. {
  256. unsigned long prev;
  257. __asm__ __volatile__ (
  258. "1: lwarx %0,0,%2 # __cmpxchg_u32_acquire\n"
  259. " cmpw 0,%0,%3\n"
  260. " bne- 2f\n"
  261. " stwcx. %4,0,%2\n"
  262. " bne- 1b\n"
  263. PPC_ACQUIRE_BARRIER
  264. "\n"
  265. "2:"
  266. : "=&r" (prev), "+m" (*p)
  267. : "r" (p), "r" (old), "r" (new)
  268. : "cc", "memory");
  269. return prev;
  270. }
  271. #ifdef CONFIG_PPC64
  272. static __always_inline unsigned long
  273. __cmpxchg_u64(volatile unsigned long *p, unsigned long old, unsigned long new)
  274. {
  275. unsigned long prev;
  276. __asm__ __volatile__ (
  277. PPC_ATOMIC_ENTRY_BARRIER
  278. "1: ldarx %0,0,%2 # __cmpxchg_u64\n\
  279. cmpd 0,%0,%3\n\
  280. bne- 2f\n\
  281. stdcx. %4,0,%2\n\
  282. bne- 1b"
  283. PPC_ATOMIC_EXIT_BARRIER
  284. "\n\
  285. 2:"
  286. : "=&r" (prev), "+m" (*p)
  287. : "r" (p), "r" (old), "r" (new)
  288. : "cc", "memory");
  289. return prev;
  290. }
  291. static __always_inline unsigned long
  292. __cmpxchg_u64_local(volatile unsigned long *p, unsigned long old,
  293. unsigned long new)
  294. {
  295. unsigned long prev;
  296. __asm__ __volatile__ (
  297. "1: ldarx %0,0,%2 # __cmpxchg_u64\n\
  298. cmpd 0,%0,%3\n\
  299. bne- 2f\n\
  300. stdcx. %4,0,%2\n\
  301. bne- 1b"
  302. "\n\
  303. 2:"
  304. : "=&r" (prev), "+m" (*p)
  305. : "r" (p), "r" (old), "r" (new)
  306. : "cc", "memory");
  307. return prev;
  308. }
  309. static __always_inline unsigned long
  310. __cmpxchg_u64_relaxed(u64 *p, unsigned long old, unsigned long new)
  311. {
  312. unsigned long prev;
  313. __asm__ __volatile__ (
  314. "1: ldarx %0,0,%2 # __cmpxchg_u64_relaxed\n"
  315. " cmpd 0,%0,%3\n"
  316. " bne- 2f\n"
  317. " stdcx. %4,0,%2\n"
  318. " bne- 1b\n"
  319. "2:"
  320. : "=&r" (prev), "+m" (*p)
  321. : "r" (p), "r" (old), "r" (new)
  322. : "cc");
  323. return prev;
  324. }
  325. static __always_inline unsigned long
  326. __cmpxchg_u64_acquire(u64 *p, unsigned long old, unsigned long new)
  327. {
  328. unsigned long prev;
  329. __asm__ __volatile__ (
  330. "1: ldarx %0,0,%2 # __cmpxchg_u64_acquire\n"
  331. " cmpd 0,%0,%3\n"
  332. " bne- 2f\n"
  333. " stdcx. %4,0,%2\n"
  334. " bne- 1b\n"
  335. PPC_ACQUIRE_BARRIER
  336. "\n"
  337. "2:"
  338. : "=&r" (prev), "+m" (*p)
  339. : "r" (p), "r" (old), "r" (new)
  340. : "cc", "memory");
  341. return prev;
  342. }
  343. #endif
  344. static __always_inline unsigned long
  345. __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new,
  346. unsigned int size)
  347. {
  348. switch (size) {
  349. case 1:
  350. return __cmpxchg_u8(ptr, old, new);
  351. case 2:
  352. return __cmpxchg_u16(ptr, old, new);
  353. case 4:
  354. return __cmpxchg_u32(ptr, old, new);
  355. #ifdef CONFIG_PPC64
  356. case 8:
  357. return __cmpxchg_u64(ptr, old, new);
  358. #endif
  359. }
  360. BUILD_BUG_ON_MSG(1, "Unsupported size for __cmpxchg");
  361. return old;
  362. }
  363. static __always_inline unsigned long
  364. __cmpxchg_local(void *ptr, unsigned long old, unsigned long new,
  365. unsigned int size)
  366. {
  367. switch (size) {
  368. case 1:
  369. return __cmpxchg_u8_local(ptr, old, new);
  370. case 2:
  371. return __cmpxchg_u16_local(ptr, old, new);
  372. case 4:
  373. return __cmpxchg_u32_local(ptr, old, new);
  374. #ifdef CONFIG_PPC64
  375. case 8:
  376. return __cmpxchg_u64_local(ptr, old, new);
  377. #endif
  378. }
  379. BUILD_BUG_ON_MSG(1, "Unsupported size for __cmpxchg_local");
  380. return old;
  381. }
  382. static __always_inline unsigned long
  383. __cmpxchg_relaxed(void *ptr, unsigned long old, unsigned long new,
  384. unsigned int size)
  385. {
  386. switch (size) {
  387. case 1:
  388. return __cmpxchg_u8_relaxed(ptr, old, new);
  389. case 2:
  390. return __cmpxchg_u16_relaxed(ptr, old, new);
  391. case 4:
  392. return __cmpxchg_u32_relaxed(ptr, old, new);
  393. #ifdef CONFIG_PPC64
  394. case 8:
  395. return __cmpxchg_u64_relaxed(ptr, old, new);
  396. #endif
  397. }
  398. BUILD_BUG_ON_MSG(1, "Unsupported size for __cmpxchg_relaxed");
  399. return old;
  400. }
  401. static __always_inline unsigned long
  402. __cmpxchg_acquire(void *ptr, unsigned long old, unsigned long new,
  403. unsigned int size)
  404. {
  405. switch (size) {
  406. case 1:
  407. return __cmpxchg_u8_acquire(ptr, old, new);
  408. case 2:
  409. return __cmpxchg_u16_acquire(ptr, old, new);
  410. case 4:
  411. return __cmpxchg_u32_acquire(ptr, old, new);
  412. #ifdef CONFIG_PPC64
  413. case 8:
  414. return __cmpxchg_u64_acquire(ptr, old, new);
  415. #endif
  416. }
  417. BUILD_BUG_ON_MSG(1, "Unsupported size for __cmpxchg_acquire");
  418. return old;
  419. }
  420. #define arch_cmpxchg(ptr, o, n) \
  421. ({ \
  422. __typeof__(*(ptr)) _o_ = (o); \
  423. __typeof__(*(ptr)) _n_ = (n); \
  424. (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_, \
  425. (unsigned long)_n_, sizeof(*(ptr))); \
  426. })
  427. #define arch_cmpxchg_local(ptr, o, n) \
  428. ({ \
  429. __typeof__(*(ptr)) _o_ = (o); \
  430. __typeof__(*(ptr)) _n_ = (n); \
  431. (__typeof__(*(ptr))) __cmpxchg_local((ptr), (unsigned long)_o_, \
  432. (unsigned long)_n_, sizeof(*(ptr))); \
  433. })
  434. #define arch_cmpxchg_relaxed(ptr, o, n) \
  435. ({ \
  436. __typeof__(*(ptr)) _o_ = (o); \
  437. __typeof__(*(ptr)) _n_ = (n); \
  438. (__typeof__(*(ptr))) __cmpxchg_relaxed((ptr), \
  439. (unsigned long)_o_, (unsigned long)_n_, \
  440. sizeof(*(ptr))); \
  441. })
  442. #define arch_cmpxchg_acquire(ptr, o, n) \
  443. ({ \
  444. __typeof__(*(ptr)) _o_ = (o); \
  445. __typeof__(*(ptr)) _n_ = (n); \
  446. (__typeof__(*(ptr))) __cmpxchg_acquire((ptr), \
  447. (unsigned long)_o_, (unsigned long)_n_, \
  448. sizeof(*(ptr))); \
  449. })
  450. #ifdef CONFIG_PPC64
  451. #define arch_cmpxchg64(ptr, o, n) \
  452. ({ \
  453. BUILD_BUG_ON(sizeof(*(ptr)) != 8); \
  454. arch_cmpxchg((ptr), (o), (n)); \
  455. })
  456. #define arch_cmpxchg64_local(ptr, o, n) \
  457. ({ \
  458. BUILD_BUG_ON(sizeof(*(ptr)) != 8); \
  459. arch_cmpxchg_local((ptr), (o), (n)); \
  460. })
  461. #define arch_cmpxchg64_relaxed(ptr, o, n) \
  462. ({ \
  463. BUILD_BUG_ON(sizeof(*(ptr)) != 8); \
  464. arch_cmpxchg_relaxed((ptr), (o), (n)); \
  465. })
  466. #define arch_cmpxchg64_acquire(ptr, o, n) \
  467. ({ \
  468. BUILD_BUG_ON(sizeof(*(ptr)) != 8); \
  469. arch_cmpxchg_acquire((ptr), (o), (n)); \
  470. })
  471. #else
  472. #include <asm-generic/cmpxchg-local.h>
  473. #define arch_cmpxchg64_local(ptr, o, n) __generic_cmpxchg64_local((ptr), (o), (n))
  474. #endif
  475. #endif /* __KERNEL__ */
  476. #endif /* _ASM_POWERPC_CMPXCHG_H_ */