barrier.h 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. /*
  3. * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
  4. */
  5. #ifndef __ASM_BARRIER_H
  6. #define __ASM_BARRIER_H
  7. /*
  8. * Hint encoding:
  9. *
  10. * Bit4: ordering or completion (0: completion, 1: ordering)
  11. * Bit3: barrier for previous read (0: true, 1: false)
  12. * Bit2: barrier for previous write (0: true, 1: false)
  13. * Bit1: barrier for succeeding read (0: true, 1: false)
  14. * Bit0: barrier for succeeding write (0: true, 1: false)
  15. *
  16. * Hint 0x700: barrier for "read after read" from the same address
  17. */
  18. #define DBAR(hint) __asm__ __volatile__("dbar %0 " : : "I"(hint) : "memory")
  19. #define crwrw 0b00000
  20. #define cr_r_ 0b00101
  21. #define c_w_w 0b01010
  22. #define orwrw 0b10000
  23. #define or_r_ 0b10101
  24. #define o_w_w 0b11010
  25. #define orw_w 0b10010
  26. #define or_rw 0b10100
  27. #define c_sync() DBAR(crwrw)
  28. #define c_rsync() DBAR(cr_r_)
  29. #define c_wsync() DBAR(c_w_w)
  30. #define o_sync() DBAR(orwrw)
  31. #define o_rsync() DBAR(or_r_)
  32. #define o_wsync() DBAR(o_w_w)
  33. #define ldacq_mb() DBAR(or_rw)
  34. #define strel_mb() DBAR(orw_w)
  35. #define mb() c_sync()
  36. #define rmb() c_rsync()
  37. #define wmb() c_wsync()
  38. #define iob() c_sync()
  39. #define wbflush() c_sync()
  40. #define __smp_mb() o_sync()
  41. #define __smp_rmb() o_rsync()
  42. #define __smp_wmb() o_wsync()
  43. #ifdef CONFIG_SMP
  44. #define __WEAK_LLSC_MB " dbar 0x700 \n"
  45. #else
  46. #define __WEAK_LLSC_MB " \n"
  47. #endif
  48. #define __smp_mb__before_atomic() barrier()
  49. #define __smp_mb__after_atomic() barrier()
  50. /**
  51. * array_index_mask_nospec() - generate a ~0 mask when index < size, 0 otherwise
  52. * @index: array element index
  53. * @size: number of elements in array
  54. *
  55. * Returns:
  56. * 0 - (@index < @size)
  57. */
  58. #define array_index_mask_nospec array_index_mask_nospec
  59. static inline unsigned long array_index_mask_nospec(unsigned long index,
  60. unsigned long size)
  61. {
  62. unsigned long mask;
  63. __asm__ __volatile__(
  64. "sltu %0, %1, %2\n\t"
  65. #if (__SIZEOF_LONG__ == 4)
  66. "sub.w %0, $zero, %0\n\t"
  67. #elif (__SIZEOF_LONG__ == 8)
  68. "sub.d %0, $zero, %0\n\t"
  69. #endif
  70. : "=r" (mask)
  71. : "r" (index), "r" (size)
  72. :);
  73. return mask;
  74. }
  75. #define __smp_load_acquire(p) \
  76. ({ \
  77. typeof(*p) ___p1 = READ_ONCE(*p); \
  78. compiletime_assert_atomic_type(*p); \
  79. ldacq_mb(); \
  80. ___p1; \
  81. })
  82. #define __smp_store_release(p, v) \
  83. do { \
  84. compiletime_assert_atomic_type(*p); \
  85. strel_mb(); \
  86. WRITE_ONCE(*p, v); \
  87. } while (0)
  88. #define __smp_store_mb(p, v) \
  89. do { \
  90. union { typeof(p) __val; char __c[1]; } __u = \
  91. { .__val = (__force typeof(p)) (v) }; \
  92. unsigned long __tmp; \
  93. switch (sizeof(p)) { \
  94. case 1: \
  95. *(volatile __u8 *)&p = *(__u8 *)__u.__c; \
  96. __smp_mb(); \
  97. break; \
  98. case 2: \
  99. *(volatile __u16 *)&p = *(__u16 *)__u.__c; \
  100. __smp_mb(); \
  101. break; \
  102. case 4: \
  103. __asm__ __volatile__( \
  104. "amswap_db.w %[tmp], %[val], %[mem] \n" \
  105. : [mem] "+ZB" (*(u32 *)&p), [tmp] "=&r" (__tmp) \
  106. : [val] "r" (*(__u32 *)__u.__c) \
  107. : ); \
  108. break; \
  109. case 8: \
  110. __asm__ __volatile__( \
  111. "amswap_db.d %[tmp], %[val], %[mem] \n" \
  112. : [mem] "+ZB" (*(u64 *)&p), [tmp] "=&r" (__tmp) \
  113. : [val] "r" (*(__u64 *)__u.__c) \
  114. : ); \
  115. break; \
  116. } \
  117. } while (0)
  118. #include <asm-generic/barrier.h>
  119. #endif /* __ASM_BARRIER_H */