cmpxchg.h 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. /* SPDX-License-Identifier: GPL-2.0-only */
  2. /*
  3. * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com)
  4. */
  5. #ifndef __ASM_ARC_CMPXCHG_H
  6. #define __ASM_ARC_CMPXCHG_H
  7. #include <linux/build_bug.h>
  8. #include <linux/types.h>
  9. #include <linux/cmpxchg-emu.h>
  10. #include <asm/barrier.h>
  11. #include <asm/smp.h>
  12. #ifdef CONFIG_ARC_HAS_LLSC
  13. /*
  14. * if (*ptr == @old)
  15. * *ptr = @new
  16. */
  17. #define __cmpxchg(ptr, old, new) \
  18. ({ \
  19. __typeof__(*(ptr)) _prev; \
  20. \
  21. __asm__ __volatile__( \
  22. "1: llock %0, [%1] \n" \
  23. " brne %0, %2, 2f \n" \
  24. " scond %3, [%1] \n" \
  25. " bnz 1b \n" \
  26. "2: \n" \
  27. : "=&r"(_prev) /* Early clobber prevent reg reuse */ \
  28. : "r"(ptr), /* Not "m": llock only supports reg */ \
  29. "ir"(old), \
  30. "r"(new) /* Not "ir": scond can't take LIMM */ \
  31. : "cc", \
  32. "memory"); /* gcc knows memory is clobbered */ \
  33. \
  34. _prev; \
  35. })
  36. #define arch_cmpxchg_relaxed(ptr, old, new) \
  37. ({ \
  38. __typeof__(ptr) _p_ = (ptr); \
  39. __typeof__(*(ptr)) _o_ = (old); \
  40. __typeof__(*(ptr)) _n_ = (new); \
  41. __typeof__(*(ptr)) _prev_; \
  42. \
  43. switch(sizeof((_p_))) { \
  44. case 1: \
  45. _prev_ = (__typeof__(*(ptr)))cmpxchg_emu_u8((volatile u8 *__force)_p_, (uintptr_t)_o_, (uintptr_t)_n_); \
  46. break; \
  47. case 4: \
  48. _prev_ = __cmpxchg(_p_, _o_, _n_); \
  49. break; \
  50. default: \
  51. BUILD_BUG(); \
  52. } \
  53. _prev_; \
  54. })
  55. #else
  56. #define arch_cmpxchg(ptr, old, new) \
  57. ({ \
  58. volatile __typeof__(ptr) _p_ = (ptr); \
  59. __typeof__(*(ptr)) _o_ = (old); \
  60. __typeof__(*(ptr)) _n_ = (new); \
  61. __typeof__(*(ptr)) _prev_; \
  62. unsigned long __flags; \
  63. \
  64. /* \
  65. * spin lock/unlock provide the needed smp_mb() before/after \
  66. */ \
  67. atomic_ops_lock(__flags); \
  68. _prev_ = *_p_; \
  69. if (_prev_ == _o_) \
  70. *_p_ = _n_; \
  71. atomic_ops_unlock(__flags); \
  72. _prev_; \
  73. })
  74. #endif
  75. /*
  76. * xchg
  77. */
  78. #ifdef CONFIG_ARC_HAS_LLSC
  79. #define __arch_xchg(ptr, val) \
  80. ({ \
  81. __asm__ __volatile__( \
  82. " ex %0, [%1] \n" /* set new value */ \
  83. : "+r"(val) \
  84. : "r"(ptr) \
  85. : "memory"); \
  86. _val_; /* get old value */ \
  87. })
  88. #define arch_xchg_relaxed(ptr, val) \
  89. ({ \
  90. __typeof__(ptr) _p_ = (ptr); \
  91. __typeof__(*(ptr)) _val_ = (val); \
  92. \
  93. switch(sizeof(*(_p_))) { \
  94. case 4: \
  95. _val_ = __arch_xchg(_p_, _val_); \
  96. break; \
  97. default: \
  98. BUILD_BUG(); \
  99. } \
  100. _val_; \
  101. })
  102. #else /* !CONFIG_ARC_HAS_LLSC */
  103. /*
  104. * EX instructions is baseline and present in !LLSC too. But in this
  105. * regime it still needs use @atomic_ops_lock spinlock to allow interop
  106. * with cmpxchg() which uses spinlock in !LLSC
  107. * (llist.h use xchg and cmpxchg on sama data)
  108. */
  109. #define arch_xchg(ptr, val) \
  110. ({ \
  111. __typeof__(ptr) _p_ = (ptr); \
  112. __typeof__(*(ptr)) _val_ = (val); \
  113. \
  114. unsigned long __flags; \
  115. \
  116. atomic_ops_lock(__flags); \
  117. \
  118. __asm__ __volatile__( \
  119. " ex %0, [%1] \n" \
  120. : "+r"(_val_) \
  121. : "r"(_p_) \
  122. : "memory"); \
  123. \
  124. atomic_ops_unlock(__flags); \
  125. _val_; \
  126. })
  127. #endif
  128. #endif