atomic-llsc.h 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. /*
  3. * Atomic operations (LLSC).
  4. *
  5. * Copyright (C) 2024-2025 Loongson Technology Corporation Limited
  6. */
  7. #ifndef _ASM_ATOMIC_LLSC_H
  8. #define _ASM_ATOMIC_LLSC_H
  9. #include <linux/types.h>
  10. #include <asm/barrier.h>
  11. #include <asm/cmpxchg.h>
  12. #define ATOMIC_OP(op, I, asm_op) \
  13. static inline void arch_atomic_##op(int i, atomic_t *v) \
  14. { \
  15. int temp; \
  16. \
  17. __asm__ __volatile__( \
  18. "1: ll.w %0, %1 #atomic_" #op " \n" \
  19. " " #asm_op " %0, %0, %2 \n" \
  20. " sc.w %0, %1 \n" \
  21. " beq %0, $r0, 1b \n" \
  22. :"=&r" (temp) , "+ZC"(v->counter) \
  23. :"r" (I) \
  24. ); \
  25. }
  26. #define ATOMIC_OP_RETURN(op, I, asm_op) \
  27. static inline int arch_atomic_##op##_return_relaxed(int i, atomic_t *v) \
  28. { \
  29. int result, temp; \
  30. \
  31. __asm__ __volatile__( \
  32. "1: ll.w %1, %2 # atomic_" #op "_return \n" \
  33. " " #asm_op " %0, %1, %3 \n" \
  34. " sc.w %0, %2 \n" \
  35. " beq %0, $r0 ,1b \n" \
  36. " " #asm_op " %0, %1, %3 \n" \
  37. : "=&r" (result), "=&r" (temp), "+ZC"(v->counter) \
  38. : "r" (I)); \
  39. \
  40. return result; \
  41. }
  42. #define ATOMIC_FETCH_OP(op, I, asm_op) \
  43. static inline int arch_atomic_fetch_##op##_relaxed(int i, atomic_t *v) \
  44. { \
  45. int result, temp; \
  46. \
  47. __asm__ __volatile__( \
  48. "1: ll.w %1, %2 # atomic_fetch_" #op " \n" \
  49. " " #asm_op " %0, %1, %3 \n" \
  50. " sc.w %0, %2 \n" \
  51. " beq %0, $r0 ,1b \n" \
  52. " add.w %0, %1 ,$r0 \n" \
  53. : "=&r" (result), "=&r" (temp), "+ZC" (v->counter) \
  54. : "r" (I)); \
  55. \
  56. return result; \
  57. }
  58. #define ATOMIC_OPS(op,I ,asm_op, c_op) \
  59. ATOMIC_OP(op, I, asm_op) \
  60. ATOMIC_OP_RETURN(op, I , asm_op) \
  61. ATOMIC_FETCH_OP(op, I, asm_op)
  62. ATOMIC_OPS(add, i , add.w ,+=)
  63. ATOMIC_OPS(sub, -i , add.w ,+=)
  64. #define arch_atomic_add_return_relaxed arch_atomic_add_return_relaxed
  65. #define arch_atomic_sub_return_relaxed arch_atomic_sub_return_relaxed
  66. #define arch_atomic_fetch_add_relaxed arch_atomic_fetch_add_relaxed
  67. #define arch_atomic_fetch_sub_relaxed arch_atomic_fetch_sub_relaxed
  68. #undef ATOMIC_OPS
  69. #define ATOMIC_OPS(op, I, asm_op) \
  70. ATOMIC_OP(op, I, asm_op) \
  71. ATOMIC_FETCH_OP(op, I, asm_op)
  72. ATOMIC_OPS(and, i, and)
  73. ATOMIC_OPS(or, i, or)
  74. ATOMIC_OPS(xor, i, xor)
  75. #define arch_atomic_fetch_and_relaxed arch_atomic_fetch_and_relaxed
  76. #define arch_atomic_fetch_or_relaxed arch_atomic_fetch_or_relaxed
  77. #define arch_atomic_fetch_xor_relaxed arch_atomic_fetch_xor_relaxed
  78. #undef ATOMIC_OPS
  79. #undef ATOMIC_FETCH_OP
  80. #undef ATOMIC_OP_RETURN
  81. #undef ATOMIC_OP
  82. #ifdef CONFIG_64BIT
  83. #error "64-bit LLSC atomic operations are not supported"
  84. #endif
  85. #endif /* _ASM_ATOMIC_LLSC_H */