rwsem.h 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. #ifndef _S390_RWSEM_H
  2. #define _S390_RWSEM_H
  3. /*
  4. * include/asm-s390/rwsem.h
  5. *
  6. * S390 version
  7. * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
  8. * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
  9. *
  10. * Based on asm-alpha/semaphore.h and asm-i386/rwsem.h
  11. */
  12. /*
  13. *
  14. * The MSW of the count is the negated number of active writers and waiting
  15. * lockers, and the LSW is the total number of active locks
  16. *
  17. * The lock count is initialized to 0 (no active and no waiting lockers).
  18. *
  19. * When a writer subtracts WRITE_BIAS, it'll get 0xffff0001 for the case of an
  20. * uncontended lock. This can be determined because XADD returns the old value.
  21. * Readers increment by 1 and see a positive value when uncontended, negative
  22. * if there are writers (and maybe) readers waiting (in which case it goes to
  23. * sleep).
  24. *
  25. * The value of WAITING_BIAS supports up to 32766 waiting processes. This can
  26. * be extended to 65534 by manually checking the whole MSW rather than relying
  27. * on the S flag.
  28. *
  29. * The value of ACTIVE_BIAS supports up to 65535 active processes.
  30. *
  31. * This should be totally fair - if anything is waiting, a process that wants a
  32. * lock will go to the back of the queue. When the currently active lock is
  33. * released, if there's a writer at the front of the queue, then that and only
  34. * that will be woken up; if there's a bunch of consequtive readers at the
  35. * front, then they'll all be woken up, but no other readers will be.
  36. */
  37. #ifndef _LINUX_RWSEM_H
  38. #error "please don't include asm/rwsem.h directly, use linux/rwsem.h instead"
  39. #endif
  40. #ifdef __KERNEL__
  41. extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *);
  42. extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *);
  43. extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *);
  44. extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *);
  45. extern struct rw_semaphore *rwsem_downgrade_write(struct rw_semaphore *);
  46. #ifndef __s390x__
  47. #define RWSEM_UNLOCKED_VALUE 0x00000000
  48. #define RWSEM_ACTIVE_BIAS 0x00000001
  49. #define RWSEM_ACTIVE_MASK 0x0000ffff
  50. #define RWSEM_WAITING_BIAS (-0x00010000)
  51. #else /* __s390x__ */
  52. #define RWSEM_UNLOCKED_VALUE 0x0000000000000000L
  53. #define RWSEM_ACTIVE_BIAS 0x0000000000000001L
  54. #define RWSEM_ACTIVE_MASK 0x00000000ffffffffL
  55. #define RWSEM_WAITING_BIAS (-0x0000000100000000L)
  56. #endif /* __s390x__ */
  57. #define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS
  58. #define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
  59. /*
  60. * lock for reading
  61. */
  62. static inline void __down_read(struct rw_semaphore *sem)
  63. {
  64. signed long old, new;
  65. asm volatile(
  66. #ifndef __s390x__
  67. " l %0,%2\n"
  68. "0: lr %1,%0\n"
  69. " ahi %1,%4\n"
  70. " cs %0,%1,%2\n"
  71. " jl 0b"
  72. #else /* __s390x__ */
  73. " lg %0,%2\n"
  74. "0: lgr %1,%0\n"
  75. " aghi %1,%4\n"
  76. " csg %0,%1,%2\n"
  77. " jl 0b"
  78. #endif /* __s390x__ */
  79. : "=&d" (old), "=&d" (new), "=Q" (sem->count)
  80. : "Q" (sem->count), "i" (RWSEM_ACTIVE_READ_BIAS)
  81. : "cc", "memory");
  82. if (old < 0)
  83. rwsem_down_read_failed(sem);
  84. }
  85. /*
  86. * trylock for reading -- returns 1 if successful, 0 if contention
  87. */
  88. static inline int __down_read_trylock(struct rw_semaphore *sem)
  89. {
  90. signed long old, new;
  91. asm volatile(
  92. #ifndef __s390x__
  93. " l %0,%2\n"
  94. "0: ltr %1,%0\n"
  95. " jm 1f\n"
  96. " ahi %1,%4\n"
  97. " cs %0,%1,%2\n"
  98. " jl 0b\n"
  99. "1:"
  100. #else /* __s390x__ */
  101. " lg %0,%2\n"
  102. "0: ltgr %1,%0\n"
  103. " jm 1f\n"
  104. " aghi %1,%4\n"
  105. " csg %0,%1,%2\n"
  106. " jl 0b\n"
  107. "1:"
  108. #endif /* __s390x__ */
  109. : "=&d" (old), "=&d" (new), "=Q" (sem->count)
  110. : "Q" (sem->count), "i" (RWSEM_ACTIVE_READ_BIAS)
  111. : "cc", "memory");
  112. return old >= 0 ? 1 : 0;
  113. }
  114. /*
  115. * lock for writing
  116. */
  117. static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
  118. {
  119. signed long old, new, tmp;
  120. tmp = RWSEM_ACTIVE_WRITE_BIAS;
  121. asm volatile(
  122. #ifndef __s390x__
  123. " l %0,%2\n"
  124. "0: lr %1,%0\n"
  125. " a %1,%4\n"
  126. " cs %0,%1,%2\n"
  127. " jl 0b"
  128. #else /* __s390x__ */
  129. " lg %0,%2\n"
  130. "0: lgr %1,%0\n"
  131. " ag %1,%4\n"
  132. " csg %0,%1,%2\n"
  133. " jl 0b"
  134. #endif /* __s390x__ */
  135. : "=&d" (old), "=&d" (new), "=Q" (sem->count)
  136. : "Q" (sem->count), "m" (tmp)
  137. : "cc", "memory");
  138. if (old != 0)
  139. rwsem_down_write_failed(sem);
  140. }
  141. static inline void __down_write(struct rw_semaphore *sem)
  142. {
  143. __down_write_nested(sem, 0);
  144. }
  145. /*
  146. * trylock for writing -- returns 1 if successful, 0 if contention
  147. */
  148. static inline int __down_write_trylock(struct rw_semaphore *sem)
  149. {
  150. signed long old;
  151. asm volatile(
  152. #ifndef __s390x__
  153. " l %0,%1\n"
  154. "0: ltr %0,%0\n"
  155. " jnz 1f\n"
  156. " cs %0,%3,%1\n"
  157. " jl 0b\n"
  158. #else /* __s390x__ */
  159. " lg %0,%1\n"
  160. "0: ltgr %0,%0\n"
  161. " jnz 1f\n"
  162. " csg %0,%3,%1\n"
  163. " jl 0b\n"
  164. #endif /* __s390x__ */
  165. "1:"
  166. : "=&d" (old), "=Q" (sem->count)
  167. : "Q" (sem->count), "d" (RWSEM_ACTIVE_WRITE_BIAS)
  168. : "cc", "memory");
  169. return (old == RWSEM_UNLOCKED_VALUE) ? 1 : 0;
  170. }
  171. /*
  172. * unlock after reading
  173. */
  174. static inline void __up_read(struct rw_semaphore *sem)
  175. {
  176. signed long old, new;
  177. asm volatile(
  178. #ifndef __s390x__
  179. " l %0,%2\n"
  180. "0: lr %1,%0\n"
  181. " ahi %1,%4\n"
  182. " cs %0,%1,%2\n"
  183. " jl 0b"
  184. #else /* __s390x__ */
  185. " lg %0,%2\n"
  186. "0: lgr %1,%0\n"
  187. " aghi %1,%4\n"
  188. " csg %0,%1,%2\n"
  189. " jl 0b"
  190. #endif /* __s390x__ */
  191. : "=&d" (old), "=&d" (new), "=Q" (sem->count)
  192. : "Q" (sem->count), "i" (-RWSEM_ACTIVE_READ_BIAS)
  193. : "cc", "memory");
  194. if (new < 0)
  195. if ((new & RWSEM_ACTIVE_MASK) == 0)
  196. rwsem_wake(sem);
  197. }
  198. /*
  199. * unlock after writing
  200. */
  201. static inline void __up_write(struct rw_semaphore *sem)
  202. {
  203. signed long old, new, tmp;
  204. tmp = -RWSEM_ACTIVE_WRITE_BIAS;
  205. asm volatile(
  206. #ifndef __s390x__
  207. " l %0,%2\n"
  208. "0: lr %1,%0\n"
  209. " a %1,%4\n"
  210. " cs %0,%1,%2\n"
  211. " jl 0b"
  212. #else /* __s390x__ */
  213. " lg %0,%2\n"
  214. "0: lgr %1,%0\n"
  215. " ag %1,%4\n"
  216. " csg %0,%1,%2\n"
  217. " jl 0b"
  218. #endif /* __s390x__ */
  219. : "=&d" (old), "=&d" (new), "=Q" (sem->count)
  220. : "Q" (sem->count), "m" (tmp)
  221. : "cc", "memory");
  222. if (new < 0)
  223. if ((new & RWSEM_ACTIVE_MASK) == 0)
  224. rwsem_wake(sem);
  225. }
  226. /*
  227. * downgrade write lock to read lock
  228. */
  229. static inline void __downgrade_write(struct rw_semaphore *sem)
  230. {
  231. signed long old, new, tmp;
  232. tmp = -RWSEM_WAITING_BIAS;
  233. asm volatile(
  234. #ifndef __s390x__
  235. " l %0,%2\n"
  236. "0: lr %1,%0\n"
  237. " a %1,%4\n"
  238. " cs %0,%1,%2\n"
  239. " jl 0b"
  240. #else /* __s390x__ */
  241. " lg %0,%2\n"
  242. "0: lgr %1,%0\n"
  243. " ag %1,%4\n"
  244. " csg %0,%1,%2\n"
  245. " jl 0b"
  246. #endif /* __s390x__ */
  247. : "=&d" (old), "=&d" (new), "=Q" (sem->count)
  248. : "Q" (sem->count), "m" (tmp)
  249. : "cc", "memory");
  250. if (new > 1)
  251. rwsem_downgrade_wake(sem);
  252. }
  253. /*
  254. * implement atomic add functionality
  255. */
  256. static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem)
  257. {
  258. signed long old, new;
  259. asm volatile(
  260. #ifndef __s390x__
  261. " l %0,%2\n"
  262. "0: lr %1,%0\n"
  263. " ar %1,%4\n"
  264. " cs %0,%1,%2\n"
  265. " jl 0b"
  266. #else /* __s390x__ */
  267. " lg %0,%2\n"
  268. "0: lgr %1,%0\n"
  269. " agr %1,%4\n"
  270. " csg %0,%1,%2\n"
  271. " jl 0b"
  272. #endif /* __s390x__ */
  273. : "=&d" (old), "=&d" (new), "=Q" (sem->count)
  274. : "Q" (sem->count), "d" (delta)
  275. : "cc", "memory");
  276. }
  277. /*
  278. * implement exchange and add functionality
  279. */
  280. static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem)
  281. {
  282. signed long old, new;
  283. asm volatile(
  284. #ifndef __s390x__
  285. " l %0,%2\n"
  286. "0: lr %1,%0\n"
  287. " ar %1,%4\n"
  288. " cs %0,%1,%2\n"
  289. " jl 0b"
  290. #else /* __s390x__ */
  291. " lg %0,%2\n"
  292. "0: lgr %1,%0\n"
  293. " agr %1,%4\n"
  294. " csg %0,%1,%2\n"
  295. " jl 0b"
  296. #endif /* __s390x__ */
  297. : "=&d" (old), "=&d" (new), "=Q" (sem->count)
  298. : "Q" (sem->count), "d" (delta)
  299. : "cc", "memory");
  300. return new;
  301. }
  302. #endif /* __KERNEL__ */
  303. #endif /* _S390_RWSEM_H */