atomic.h 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. /* SPDX-License-Identifier: GPL-2.0-only */
  2. /*
  3. * Atomic operations for the Hexagon architecture
  4. *
  5. * Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
  6. */
  7. #ifndef _ASM_ATOMIC_H
  8. #define _ASM_ATOMIC_H
  9. #include <linux/types.h>
  10. #include <asm/cmpxchg.h>
  11. #include <asm/barrier.h>
  12. /* Normal writes in our arch don't clear lock reservations */
  13. static inline void arch_atomic_set(atomic_t *v, int new)
  14. {
  15. asm volatile(
  16. "1: r6 = memw_locked(%0);\n"
  17. " memw_locked(%0,p0) = %1;\n"
  18. " if (!P0) jump 1b;\n"
  19. :
  20. : "r" (&v->counter), "r" (new)
  21. : "memory", "p0", "r6"
  22. );
  23. }
  24. #define arch_atomic_set_release(v, i) arch_atomic_set((v), (i))
  25. #define arch_atomic_read(v) READ_ONCE((v)->counter)
  26. #define ATOMIC_OP(op) \
  27. static inline void arch_atomic_##op(int i, atomic_t *v) \
  28. { \
  29. int output; \
  30. \
  31. __asm__ __volatile__ ( \
  32. "1: %0 = memw_locked(%1);\n" \
  33. " %0 = "#op "(%0,%2);\n" \
  34. " memw_locked(%1,P3)=%0;\n" \
  35. " if (!P3) jump 1b;\n" \
  36. : "=&r" (output) \
  37. : "r" (&v->counter), "r" (i) \
  38. : "memory", "p3" \
  39. ); \
  40. } \
  41. #define ATOMIC_OP_RETURN(op) \
  42. static inline int arch_atomic_##op##_return(int i, atomic_t *v) \
  43. { \
  44. int output; \
  45. \
  46. __asm__ __volatile__ ( \
  47. "1: %0 = memw_locked(%1);\n" \
  48. " %0 = "#op "(%0,%2);\n" \
  49. " memw_locked(%1,P3)=%0;\n" \
  50. " if (!P3) jump 1b;\n" \
  51. : "=&r" (output) \
  52. : "r" (&v->counter), "r" (i) \
  53. : "memory", "p3" \
  54. ); \
  55. return output; \
  56. }
  57. #define ATOMIC_FETCH_OP(op) \
  58. static inline int arch_atomic_fetch_##op(int i, atomic_t *v) \
  59. { \
  60. int output, val; \
  61. \
  62. __asm__ __volatile__ ( \
  63. "1: %0 = memw_locked(%2);\n" \
  64. " %1 = "#op "(%0,%3);\n" \
  65. " memw_locked(%2,P3)=%1;\n" \
  66. " if (!P3) jump 1b;\n" \
  67. : "=&r" (output), "=&r" (val) \
  68. : "r" (&v->counter), "r" (i) \
  69. : "memory", "p3" \
  70. ); \
  71. return output; \
  72. }
  73. #define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_OP_RETURN(op) ATOMIC_FETCH_OP(op)
  74. ATOMIC_OPS(add)
  75. ATOMIC_OPS(sub)
  76. #define arch_atomic_add_return arch_atomic_add_return
  77. #define arch_atomic_sub_return arch_atomic_sub_return
  78. #define arch_atomic_fetch_add arch_atomic_fetch_add
  79. #define arch_atomic_fetch_sub arch_atomic_fetch_sub
  80. #undef ATOMIC_OPS
  81. #define ATOMIC_OPS(op) ATOMIC_OP(op) ATOMIC_FETCH_OP(op)
  82. ATOMIC_OPS(and)
  83. ATOMIC_OPS(or)
  84. ATOMIC_OPS(xor)
  85. #define arch_atomic_fetch_and arch_atomic_fetch_and
  86. #define arch_atomic_fetch_or arch_atomic_fetch_or
  87. #define arch_atomic_fetch_xor arch_atomic_fetch_xor
  88. #undef ATOMIC_OPS
  89. #undef ATOMIC_FETCH_OP
  90. #undef ATOMIC_OP_RETURN
  91. #undef ATOMIC_OP
  92. static inline int arch_atomic_fetch_add_unless(atomic_t *v, int a, int u)
  93. {
  94. int __oldval;
  95. register int tmp;
  96. asm volatile(
  97. "1: %0 = memw_locked(%2);"
  98. " {"
  99. " p3 = cmp.eq(%0, %4);"
  100. " if (p3.new) jump:nt 2f;"
  101. " %1 = add(%0, %3);"
  102. " }"
  103. " memw_locked(%2, p3) = %1;"
  104. " {"
  105. " if (!p3) jump 1b;"
  106. " }"
  107. "2:"
  108. : "=&r" (__oldval), "=&r" (tmp)
  109. : "r" (v), "r" (a), "r" (u)
  110. : "memory", "p3"
  111. );
  112. return __oldval;
  113. }
  114. #define arch_atomic_fetch_add_unless arch_atomic_fetch_add_unless
  115. #endif