atomic.h 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  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. #ifdef CONFIG_CPU_HAS_AMO
  13. #include <asm/atomic-amo.h>
  14. #else
  15. #include <asm/atomic-llsc.h>
  16. #endif
  17. #ifdef CONFIG_GENERIC_ATOMIC64
  18. #include <asm-generic/atomic64.h>
  19. #endif
  20. #if __SIZEOF_LONG__ == 4
  21. #define __LL "ll.w "
  22. #define __SC "sc.w "
  23. #define __AMADD "amadd.w "
  24. #define __AMOR "amor.w "
  25. #define __AMAND_DB "amand_db.w "
  26. #define __AMOR_DB "amor_db.w "
  27. #define __AMXOR_DB "amxor_db.w "
  28. #elif __SIZEOF_LONG__ == 8
  29. #define __LL "ll.d "
  30. #define __SC "sc.d "
  31. #define __AMADD "amadd.d "
  32. #define __AMOR "amor.d "
  33. #define __AMAND_DB "amand_db.d "
  34. #define __AMOR_DB "amor_db.d "
  35. #define __AMXOR_DB "amxor_db.d "
  36. #endif
  37. #define ATOMIC_INIT(i) { (i) }
  38. #define arch_atomic_read(v) READ_ONCE((v)->counter)
  39. #define arch_atomic_set(v, i) WRITE_ONCE((v)->counter, (i))
  40. static inline int arch_atomic_fetch_add_unless(atomic_t *v, int a, int u)
  41. {
  42. int prev, rc;
  43. __asm__ __volatile__ (
  44. "0: ll.w %[p], %[c]\n"
  45. " beq %[p], %[u], 1f\n"
  46. " add.w %[rc], %[p], %[a]\n"
  47. " sc.w %[rc], %[c]\n"
  48. " beqz %[rc], 0b\n"
  49. " b 2f\n"
  50. "1:\n"
  51. __WEAK_LLSC_MB
  52. "2:\n"
  53. : [p]"=&r" (prev), [rc]"=&r" (rc),
  54. [c]"=ZB" (v->counter)
  55. : [a]"r" (a), [u]"r" (u)
  56. : "memory");
  57. return prev;
  58. }
  59. #define arch_atomic_fetch_add_unless arch_atomic_fetch_add_unless
  60. static inline int arch_atomic_sub_if_positive(int i, atomic_t *v)
  61. {
  62. int result;
  63. int temp;
  64. if (__builtin_constant_p(i)) {
  65. __asm__ __volatile__(
  66. "1: ll.w %1, %2 # atomic_sub_if_positive\n"
  67. " addi.w %0, %1, %3 \n"
  68. " move %1, %0 \n"
  69. " bltz %0, 2f \n"
  70. " sc.w %1, %2 \n"
  71. " beqz %1, 1b \n"
  72. "2: \n"
  73. __WEAK_LLSC_MB
  74. : "=&r" (result), "=&r" (temp), "+ZC" (v->counter)
  75. : "I" (-i));
  76. } else {
  77. __asm__ __volatile__(
  78. "1: ll.w %1, %2 # atomic_sub_if_positive\n"
  79. " sub.w %0, %1, %3 \n"
  80. " move %1, %0 \n"
  81. " bltz %0, 2f \n"
  82. " sc.w %1, %2 \n"
  83. " beqz %1, 1b \n"
  84. "2: \n"
  85. __WEAK_LLSC_MB
  86. : "=&r" (result), "=&r" (temp), "+ZC" (v->counter)
  87. : "r" (i));
  88. }
  89. return result;
  90. }
  91. #define arch_atomic_dec_if_positive(v) arch_atomic_sub_if_positive(1, v)
  92. #ifdef CONFIG_64BIT
  93. #define ATOMIC64_INIT(i) { (i) }
  94. #define arch_atomic64_read(v) READ_ONCE((v)->counter)
  95. #define arch_atomic64_set(v, i) WRITE_ONCE((v)->counter, (i))
  96. static inline long arch_atomic64_fetch_add_unless(atomic64_t *v, long a, long u)
  97. {
  98. long prev, rc;
  99. __asm__ __volatile__ (
  100. "0: ll.d %[p], %[c]\n"
  101. " beq %[p], %[u], 1f\n"
  102. " add.d %[rc], %[p], %[a]\n"
  103. " sc.d %[rc], %[c]\n"
  104. " beqz %[rc], 0b\n"
  105. " b 2f\n"
  106. "1:\n"
  107. __WEAK_LLSC_MB
  108. "2:\n"
  109. : [p]"=&r" (prev), [rc]"=&r" (rc),
  110. [c] "=ZB" (v->counter)
  111. : [a]"r" (a), [u]"r" (u)
  112. : "memory");
  113. return prev;
  114. }
  115. #define arch_atomic64_fetch_add_unless arch_atomic64_fetch_add_unless
  116. static inline long arch_atomic64_sub_if_positive(long i, atomic64_t *v)
  117. {
  118. long result;
  119. long temp;
  120. if (__builtin_constant_p(i)) {
  121. __asm__ __volatile__(
  122. "1: ll.d %1, %2 # atomic64_sub_if_positive \n"
  123. " addi.d %0, %1, %3 \n"
  124. " move %1, %0 \n"
  125. " bltz %0, 2f \n"
  126. " sc.d %1, %2 \n"
  127. " beqz %1, 1b \n"
  128. "2: \n"
  129. __WEAK_LLSC_MB
  130. : "=&r" (result), "=&r" (temp), "+ZC" (v->counter)
  131. : "I" (-i));
  132. } else {
  133. __asm__ __volatile__(
  134. "1: ll.d %1, %2 # atomic64_sub_if_positive \n"
  135. " sub.d %0, %1, %3 \n"
  136. " move %1, %0 \n"
  137. " bltz %0, 2f \n"
  138. " sc.d %1, %2 \n"
  139. " beqz %1, 1b \n"
  140. "2: \n"
  141. __WEAK_LLSC_MB
  142. : "=&r" (result), "=&r" (temp), "+ZC" (v->counter)
  143. : "r" (i));
  144. }
  145. return result;
  146. }
  147. #define arch_atomic64_dec_if_positive(v) arch_atomic64_sub_if_positive(1, v)
  148. #endif /* CONFIG_64BIT */
  149. #endif /* _ASM_ATOMIC_H */