rwsem.h 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. #ifndef _S390_RWSEM_H
  2. #define _S390_RWSEM_H
  3. /*
  4. * S390 version
  5. * Copyright IBM Corp. 2002
  6. * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
  7. *
  8. * Based on asm-alpha/semaphore.h and asm-i386/rwsem.h
  9. */
  10. /*
  11. *
  12. * The MSW of the count is the negated number of active writers and waiting
  13. * lockers, and the LSW is the total number of active locks
  14. *
  15. * The lock count is initialized to 0 (no active and no waiting lockers).
  16. *
  17. * When a writer subtracts WRITE_BIAS, it'll get 0xffff0001 for the case of an
  18. * uncontended lock. This can be determined because XADD returns the old value.
  19. * Readers increment by 1 and see a positive value when uncontended, negative
  20. * if there are writers (and maybe) readers waiting (in which case it goes to
  21. * sleep).
  22. *
  23. * The value of WAITING_BIAS supports up to 32766 waiting processes. This can
  24. * be extended to 65534 by manually checking the whole MSW rather than relying
  25. * on the S flag.
  26. *
  27. * The value of ACTIVE_BIAS supports up to 65535 active processes.
  28. *
  29. * This should be totally fair - if anything is waiting, a process that wants a
  30. * lock will go to the back of the queue. When the currently active lock is
  31. * released, if there's a writer at the front of the queue, then that and only
  32. * that will be woken up; if there's a bunch of consequtive readers at the
  33. * front, then they'll all be woken up, but no other readers will be.
  34. */
  35. #ifndef _LINUX_RWSEM_H
  36. #error "please don't include asm/rwsem.h directly, use linux/rwsem.h instead"
  37. #endif
  38. #define RWSEM_UNLOCKED_VALUE 0x0000000000000000L
  39. #define RWSEM_ACTIVE_BIAS 0x0000000000000001L
  40. #define RWSEM_ACTIVE_MASK 0x00000000ffffffffL
  41. #define RWSEM_WAITING_BIAS (-0x0000000100000000L)
  42. #define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS
  43. #define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
  44. /*
  45. * lock for reading
  46. */
  47. static inline void __down_read(struct rw_semaphore *sem)
  48. {
  49. signed long old, new;
  50. asm volatile(
  51. " lg %0,%2\n"
  52. "0: lgr %1,%0\n"
  53. " aghi %1,%4\n"
  54. " csg %0,%1,%2\n"
  55. " jl 0b"
  56. : "=&d" (old), "=&d" (new), "=Q" (sem->count)
  57. : "Q" (sem->count), "i" (RWSEM_ACTIVE_READ_BIAS)
  58. : "cc", "memory");
  59. if (old < 0)
  60. rwsem_down_read_failed(sem);
  61. }
  62. /*
  63. * trylock for reading -- returns 1 if successful, 0 if contention
  64. */
  65. static inline int __down_read_trylock(struct rw_semaphore *sem)
  66. {
  67. signed long old, new;
  68. asm volatile(
  69. " lg %0,%2\n"
  70. "0: ltgr %1,%0\n"
  71. " jm 1f\n"
  72. " aghi %1,%4\n"
  73. " csg %0,%1,%2\n"
  74. " jl 0b\n"
  75. "1:"
  76. : "=&d" (old), "=&d" (new), "=Q" (sem->count)
  77. : "Q" (sem->count), "i" (RWSEM_ACTIVE_READ_BIAS)
  78. : "cc", "memory");
  79. return old >= 0 ? 1 : 0;
  80. }
  81. /*
  82. * lock for writing
  83. */
  84. static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
  85. {
  86. signed long old, new, tmp;
  87. tmp = RWSEM_ACTIVE_WRITE_BIAS;
  88. asm volatile(
  89. " lg %0,%2\n"
  90. "0: lgr %1,%0\n"
  91. " ag %1,%4\n"
  92. " csg %0,%1,%2\n"
  93. " jl 0b"
  94. : "=&d" (old), "=&d" (new), "=Q" (sem->count)
  95. : "Q" (sem->count), "m" (tmp)
  96. : "cc", "memory");
  97. if (old != 0)
  98. rwsem_down_write_failed(sem);
  99. }
  100. static inline void __down_write(struct rw_semaphore *sem)
  101. {
  102. __down_write_nested(sem, 0);
  103. }
  104. /*
  105. * trylock for writing -- returns 1 if successful, 0 if contention
  106. */
  107. static inline int __down_write_trylock(struct rw_semaphore *sem)
  108. {
  109. signed long old;
  110. asm volatile(
  111. " lg %0,%1\n"
  112. "0: ltgr %0,%0\n"
  113. " jnz 1f\n"
  114. " csg %0,%3,%1\n"
  115. " jl 0b\n"
  116. "1:"
  117. : "=&d" (old), "=Q" (sem->count)
  118. : "Q" (sem->count), "d" (RWSEM_ACTIVE_WRITE_BIAS)
  119. : "cc", "memory");
  120. return (old == RWSEM_UNLOCKED_VALUE) ? 1 : 0;
  121. }
  122. /*
  123. * unlock after reading
  124. */
  125. static inline void __up_read(struct rw_semaphore *sem)
  126. {
  127. signed long old, new;
  128. asm volatile(
  129. " lg %0,%2\n"
  130. "0: lgr %1,%0\n"
  131. " aghi %1,%4\n"
  132. " csg %0,%1,%2\n"
  133. " jl 0b"
  134. : "=&d" (old), "=&d" (new), "=Q" (sem->count)
  135. : "Q" (sem->count), "i" (-RWSEM_ACTIVE_READ_BIAS)
  136. : "cc", "memory");
  137. if (new < 0)
  138. if ((new & RWSEM_ACTIVE_MASK) == 0)
  139. rwsem_wake(sem);
  140. }
  141. /*
  142. * unlock after writing
  143. */
  144. static inline void __up_write(struct rw_semaphore *sem)
  145. {
  146. signed long old, new, tmp;
  147. tmp = -RWSEM_ACTIVE_WRITE_BIAS;
  148. asm volatile(
  149. " lg %0,%2\n"
  150. "0: lgr %1,%0\n"
  151. " ag %1,%4\n"
  152. " csg %0,%1,%2\n"
  153. " jl 0b"
  154. : "=&d" (old), "=&d" (new), "=Q" (sem->count)
  155. : "Q" (sem->count), "m" (tmp)
  156. : "cc", "memory");
  157. if (new < 0)
  158. if ((new & RWSEM_ACTIVE_MASK) == 0)
  159. rwsem_wake(sem);
  160. }
  161. /*
  162. * downgrade write lock to read lock
  163. */
  164. static inline void __downgrade_write(struct rw_semaphore *sem)
  165. {
  166. signed long old, new, tmp;
  167. tmp = -RWSEM_WAITING_BIAS;
  168. asm volatile(
  169. " lg %0,%2\n"
  170. "0: lgr %1,%0\n"
  171. " ag %1,%4\n"
  172. " csg %0,%1,%2\n"
  173. " jl 0b"
  174. : "=&d" (old), "=&d" (new), "=Q" (sem->count)
  175. : "Q" (sem->count), "m" (tmp)
  176. : "cc", "memory");
  177. if (new > 1)
  178. rwsem_downgrade_wake(sem);
  179. }
  180. /*
  181. * implement atomic add functionality
  182. */
  183. static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem)
  184. {
  185. signed long old, new;
  186. asm volatile(
  187. " lg %0,%2\n"
  188. "0: lgr %1,%0\n"
  189. " agr %1,%4\n"
  190. " csg %0,%1,%2\n"
  191. " jl 0b"
  192. : "=&d" (old), "=&d" (new), "=Q" (sem->count)
  193. : "Q" (sem->count), "d" (delta)
  194. : "cc", "memory");
  195. }
  196. /*
  197. * implement exchange and add functionality
  198. */
  199. static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem)
  200. {
  201. signed long old, new;
  202. asm volatile(
  203. " lg %0,%2\n"
  204. "0: lgr %1,%0\n"
  205. " agr %1,%4\n"
  206. " csg %0,%1,%2\n"
  207. " jl 0b"
  208. : "=&d" (old), "=&d" (new), "=Q" (sem->count)
  209. : "Q" (sem->count), "d" (delta)
  210. : "cc", "memory");
  211. return new;
  212. }
  213. #endif /* _S390_RWSEM_H */