cmpxchg.h 12 KB

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