qrwlock.h 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. /*
  2. * Queue read/write lock
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * (C) Copyright 2013-2014 Hewlett-Packard Development Company, L.P.
  15. *
  16. * Authors: Waiman Long <waiman.long@hp.com>
  17. */
  18. #ifndef __ASM_GENERIC_QRWLOCK_H
  19. #define __ASM_GENERIC_QRWLOCK_H
  20. #include <linux/atomic.h>
  21. #include <asm/barrier.h>
  22. #include <asm/processor.h>
  23. #include <asm-generic/qrwlock_types.h>
  24. /*
  25. * Writer states & reader shift and bias.
  26. *
  27. * | +0 | +1 | +2 | +3 |
  28. * ----+----+----+----+----+
  29. * LE | 78 | 56 | 34 | 12 | 0x12345678
  30. * ----+----+----+----+----+
  31. * | wr | rd |
  32. * +----+----+----+----+
  33. *
  34. * ----+----+----+----+----+
  35. * BE | 12 | 34 | 56 | 78 | 0x12345678
  36. * ----+----+----+----+----+
  37. * | rd | wr |
  38. * +----+----+----+----+
  39. */
  40. #define _QW_WAITING 1 /* A writer is waiting */
  41. #define _QW_LOCKED 0xff /* A writer holds the lock */
  42. #define _QW_WMASK 0xff /* Writer mask */
  43. #define _QR_SHIFT 8 /* Reader count shift */
  44. #define _QR_BIAS (1U << _QR_SHIFT)
  45. /*
  46. * External function declarations
  47. */
  48. extern void queued_read_lock_slowpath(struct qrwlock *lock, u32 cnts);
  49. extern void queued_write_lock_slowpath(struct qrwlock *lock);
  50. /**
  51. * queued_read_can_lock- would read_trylock() succeed?
  52. * @lock: Pointer to queue rwlock structure
  53. */
  54. static inline int queued_read_can_lock(struct qrwlock *lock)
  55. {
  56. return !(atomic_read(&lock->cnts) & _QW_WMASK);
  57. }
  58. /**
  59. * queued_write_can_lock- would write_trylock() succeed?
  60. * @lock: Pointer to queue rwlock structure
  61. */
  62. static inline int queued_write_can_lock(struct qrwlock *lock)
  63. {
  64. return !atomic_read(&lock->cnts);
  65. }
  66. /**
  67. * queued_read_trylock - try to acquire read lock of a queue rwlock
  68. * @lock : Pointer to queue rwlock structure
  69. * Return: 1 if lock acquired, 0 if failed
  70. */
  71. static inline int queued_read_trylock(struct qrwlock *lock)
  72. {
  73. u32 cnts;
  74. cnts = atomic_read(&lock->cnts);
  75. if (likely(!(cnts & _QW_WMASK))) {
  76. cnts = (u32)atomic_add_return_acquire(_QR_BIAS, &lock->cnts);
  77. if (likely(!(cnts & _QW_WMASK)))
  78. return 1;
  79. atomic_sub(_QR_BIAS, &lock->cnts);
  80. }
  81. return 0;
  82. }
  83. /**
  84. * queued_write_trylock - try to acquire write lock of a queue rwlock
  85. * @lock : Pointer to queue rwlock structure
  86. * Return: 1 if lock acquired, 0 if failed
  87. */
  88. static inline int queued_write_trylock(struct qrwlock *lock)
  89. {
  90. u32 cnts;
  91. cnts = atomic_read(&lock->cnts);
  92. if (unlikely(cnts))
  93. return 0;
  94. return likely(atomic_cmpxchg_acquire(&lock->cnts,
  95. cnts, cnts | _QW_LOCKED) == cnts);
  96. }
  97. /**
  98. * queued_read_lock - acquire read lock of a queue rwlock
  99. * @lock: Pointer to queue rwlock structure
  100. */
  101. static inline void queued_read_lock(struct qrwlock *lock)
  102. {
  103. u32 cnts;
  104. cnts = atomic_add_return_acquire(_QR_BIAS, &lock->cnts);
  105. if (likely(!(cnts & _QW_WMASK)))
  106. return;
  107. /* The slowpath will decrement the reader count, if necessary. */
  108. queued_read_lock_slowpath(lock, cnts);
  109. }
  110. /**
  111. * queued_write_lock - acquire write lock of a queue rwlock
  112. * @lock : Pointer to queue rwlock structure
  113. */
  114. static inline void queued_write_lock(struct qrwlock *lock)
  115. {
  116. /* Optimize for the unfair lock case where the fair flag is 0. */
  117. if (atomic_cmpxchg_acquire(&lock->cnts, 0, _QW_LOCKED) == 0)
  118. return;
  119. queued_write_lock_slowpath(lock);
  120. }
  121. /**
  122. * queued_read_unlock - release read lock of a queue rwlock
  123. * @lock : Pointer to queue rwlock structure
  124. */
  125. static inline void queued_read_unlock(struct qrwlock *lock)
  126. {
  127. /*
  128. * Atomically decrement the reader count
  129. */
  130. (void)atomic_sub_return_release(_QR_BIAS, &lock->cnts);
  131. }
  132. /**
  133. * __qrwlock_write_byte - retrieve the write byte address of a queue rwlock
  134. * @lock : Pointer to queue rwlock structure
  135. * Return: the write byte address of a queue rwlock
  136. */
  137. static inline u8 *__qrwlock_write_byte(struct qrwlock *lock)
  138. {
  139. return (u8 *)lock + 3 * IS_BUILTIN(CONFIG_CPU_BIG_ENDIAN);
  140. }
  141. /**
  142. * queued_write_unlock - release write lock of a queue rwlock
  143. * @lock : Pointer to queue rwlock structure
  144. */
  145. static inline void queued_write_unlock(struct qrwlock *lock)
  146. {
  147. smp_store_release(__qrwlock_write_byte(lock), 0);
  148. }
  149. /*
  150. * Remapping rwlock architecture specific functions to the corresponding
  151. * queue rwlock functions.
  152. */
  153. #define arch_read_can_lock(l) queued_read_can_lock(l)
  154. #define arch_write_can_lock(l) queued_write_can_lock(l)
  155. #define arch_read_lock(l) queued_read_lock(l)
  156. #define arch_write_lock(l) queued_write_lock(l)
  157. #define arch_read_trylock(l) queued_read_trylock(l)
  158. #define arch_write_trylock(l) queued_write_trylock(l)
  159. #define arch_read_unlock(l) queued_read_unlock(l)
  160. #define arch_write_unlock(l) queued_write_unlock(l)
  161. #endif /* __ASM_GENERIC_QRWLOCK_H */