rwsem.h 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. /* SPDX-License-Identifier: GPL-2.0 */
  2. #ifndef _ALPHA_RWSEM_H
  3. #define _ALPHA_RWSEM_H
  4. /*
  5. * Written by Ivan Kokshaysky <ink@jurassic.park.msu.ru>, 2001.
  6. * Based on asm-alpha/semaphore.h and asm-i386/rwsem.h
  7. */
  8. #ifndef _LINUX_RWSEM_H
  9. #error "please don't include asm/rwsem.h directly, use linux/rwsem.h instead"
  10. #endif
  11. #ifdef __KERNEL__
  12. #include <linux/compiler.h>
  13. #define RWSEM_UNLOCKED_VALUE 0x0000000000000000L
  14. #define RWSEM_ACTIVE_BIAS 0x0000000000000001L
  15. #define RWSEM_ACTIVE_MASK 0x00000000ffffffffL
  16. #define RWSEM_WAITING_BIAS (-0x0000000100000000L)
  17. #define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS
  18. #define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
  19. static inline void __down_read(struct rw_semaphore *sem)
  20. {
  21. long oldcount;
  22. #ifndef CONFIG_SMP
  23. oldcount = sem->count.counter;
  24. sem->count.counter += RWSEM_ACTIVE_READ_BIAS;
  25. #else
  26. long temp;
  27. __asm__ __volatile__(
  28. "1: ldq_l %0,%1\n"
  29. " addq %0,%3,%2\n"
  30. " stq_c %2,%1\n"
  31. " beq %2,2f\n"
  32. " mb\n"
  33. ".subsection 2\n"
  34. "2: br 1b\n"
  35. ".previous"
  36. :"=&r" (oldcount), "=m" (sem->count), "=&r" (temp)
  37. :"Ir" (RWSEM_ACTIVE_READ_BIAS), "m" (sem->count) : "memory");
  38. #endif
  39. if (unlikely(oldcount < 0))
  40. rwsem_down_read_failed(sem);
  41. }
  42. /*
  43. * trylock for reading -- returns 1 if successful, 0 if contention
  44. */
  45. static inline int __down_read_trylock(struct rw_semaphore *sem)
  46. {
  47. long old, new, res;
  48. res = atomic_long_read(&sem->count);
  49. do {
  50. new = res + RWSEM_ACTIVE_READ_BIAS;
  51. if (new <= 0)
  52. break;
  53. old = res;
  54. res = atomic_long_cmpxchg(&sem->count, old, new);
  55. } while (res != old);
  56. return res >= 0 ? 1 : 0;
  57. }
  58. static inline long ___down_write(struct rw_semaphore *sem)
  59. {
  60. long oldcount;
  61. #ifndef CONFIG_SMP
  62. oldcount = sem->count.counter;
  63. sem->count.counter += RWSEM_ACTIVE_WRITE_BIAS;
  64. #else
  65. long temp;
  66. __asm__ __volatile__(
  67. "1: ldq_l %0,%1\n"
  68. " addq %0,%3,%2\n"
  69. " stq_c %2,%1\n"
  70. " beq %2,2f\n"
  71. " mb\n"
  72. ".subsection 2\n"
  73. "2: br 1b\n"
  74. ".previous"
  75. :"=&r" (oldcount), "=m" (sem->count), "=&r" (temp)
  76. :"Ir" (RWSEM_ACTIVE_WRITE_BIAS), "m" (sem->count) : "memory");
  77. #endif
  78. return oldcount;
  79. }
  80. static inline void __down_write(struct rw_semaphore *sem)
  81. {
  82. if (unlikely(___down_write(sem)))
  83. rwsem_down_write_failed(sem);
  84. }
  85. static inline int __down_write_killable(struct rw_semaphore *sem)
  86. {
  87. if (unlikely(___down_write(sem)))
  88. if (IS_ERR(rwsem_down_write_failed_killable(sem)))
  89. return -EINTR;
  90. return 0;
  91. }
  92. /*
  93. * trylock for writing -- returns 1 if successful, 0 if contention
  94. */
  95. static inline int __down_write_trylock(struct rw_semaphore *sem)
  96. {
  97. long ret = atomic_long_cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE,
  98. RWSEM_ACTIVE_WRITE_BIAS);
  99. if (ret == RWSEM_UNLOCKED_VALUE)
  100. return 1;
  101. return 0;
  102. }
  103. static inline void __up_read(struct rw_semaphore *sem)
  104. {
  105. long oldcount;
  106. #ifndef CONFIG_SMP
  107. oldcount = sem->count.counter;
  108. sem->count.counter -= RWSEM_ACTIVE_READ_BIAS;
  109. #else
  110. long temp;
  111. __asm__ __volatile__(
  112. " mb\n"
  113. "1: ldq_l %0,%1\n"
  114. " subq %0,%3,%2\n"
  115. " stq_c %2,%1\n"
  116. " beq %2,2f\n"
  117. ".subsection 2\n"
  118. "2: br 1b\n"
  119. ".previous"
  120. :"=&r" (oldcount), "=m" (sem->count), "=&r" (temp)
  121. :"Ir" (RWSEM_ACTIVE_READ_BIAS), "m" (sem->count) : "memory");
  122. #endif
  123. if (unlikely(oldcount < 0))
  124. if ((int)oldcount - RWSEM_ACTIVE_READ_BIAS == 0)
  125. rwsem_wake(sem);
  126. }
  127. static inline void __up_write(struct rw_semaphore *sem)
  128. {
  129. long count;
  130. #ifndef CONFIG_SMP
  131. sem->count.counter -= RWSEM_ACTIVE_WRITE_BIAS;
  132. count = sem->count.counter;
  133. #else
  134. long temp;
  135. __asm__ __volatile__(
  136. " mb\n"
  137. "1: ldq_l %0,%1\n"
  138. " subq %0,%3,%2\n"
  139. " stq_c %2,%1\n"
  140. " beq %2,2f\n"
  141. " subq %0,%3,%0\n"
  142. ".subsection 2\n"
  143. "2: br 1b\n"
  144. ".previous"
  145. :"=&r" (count), "=m" (sem->count), "=&r" (temp)
  146. :"Ir" (RWSEM_ACTIVE_WRITE_BIAS), "m" (sem->count) : "memory");
  147. #endif
  148. if (unlikely(count))
  149. if ((int)count == 0)
  150. rwsem_wake(sem);
  151. }
  152. /*
  153. * downgrade write lock to read lock
  154. */
  155. static inline void __downgrade_write(struct rw_semaphore *sem)
  156. {
  157. long oldcount;
  158. #ifndef CONFIG_SMP
  159. oldcount = sem->count.counter;
  160. sem->count.counter -= RWSEM_WAITING_BIAS;
  161. #else
  162. long temp;
  163. __asm__ __volatile__(
  164. "1: ldq_l %0,%1\n"
  165. " addq %0,%3,%2\n"
  166. " stq_c %2,%1\n"
  167. " beq %2,2f\n"
  168. " mb\n"
  169. ".subsection 2\n"
  170. "2: br 1b\n"
  171. ".previous"
  172. :"=&r" (oldcount), "=m" (sem->count), "=&r" (temp)
  173. :"Ir" (-RWSEM_WAITING_BIAS), "m" (sem->count) : "memory");
  174. #endif
  175. if (unlikely(oldcount < 0))
  176. rwsem_downgrade_wake(sem);
  177. }
  178. #endif /* __KERNEL__ */
  179. #endif /* _ALPHA_RWSEM_H */