rwsem.h 4.7 KB

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