qrwlock.h 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  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. #define _QW_WAITING 1 /* A writer is waiting */
  28. #define _QW_LOCKED 0xff /* A writer holds the lock */
  29. #define _QW_WMASK 0xff /* Writer mask */
  30. #define _QR_SHIFT 8 /* Reader count shift */
  31. #define _QR_BIAS (1U << _QR_SHIFT)
  32. /*
  33. * External function declarations
  34. */
  35. extern void queued_read_lock_slowpath(struct qrwlock *lock, u32 cnts);
  36. extern void queued_write_lock_slowpath(struct qrwlock *lock);
  37. /**
  38. * queued_read_can_lock- would read_trylock() succeed?
  39. * @lock: Pointer to queue rwlock structure
  40. */
  41. static inline int queued_read_can_lock(struct qrwlock *lock)
  42. {
  43. return !(atomic_read(&lock->cnts) & _QW_WMASK);
  44. }
  45. /**
  46. * queued_write_can_lock- would write_trylock() succeed?
  47. * @lock: Pointer to queue rwlock structure
  48. */
  49. static inline int queued_write_can_lock(struct qrwlock *lock)
  50. {
  51. return !atomic_read(&lock->cnts);
  52. }
  53. /**
  54. * queued_read_trylock - try to acquire read lock of a queue rwlock
  55. * @lock : Pointer to queue rwlock structure
  56. * Return: 1 if lock acquired, 0 if failed
  57. */
  58. static inline int queued_read_trylock(struct qrwlock *lock)
  59. {
  60. u32 cnts;
  61. cnts = atomic_read(&lock->cnts);
  62. if (likely(!(cnts & _QW_WMASK))) {
  63. cnts = (u32)atomic_add_return_acquire(_QR_BIAS, &lock->cnts);
  64. if (likely(!(cnts & _QW_WMASK)))
  65. return 1;
  66. atomic_sub(_QR_BIAS, &lock->cnts);
  67. }
  68. return 0;
  69. }
  70. /**
  71. * queued_write_trylock - try to acquire write lock of a queue rwlock
  72. * @lock : Pointer to queue rwlock structure
  73. * Return: 1 if lock acquired, 0 if failed
  74. */
  75. static inline int queued_write_trylock(struct qrwlock *lock)
  76. {
  77. u32 cnts;
  78. cnts = atomic_read(&lock->cnts);
  79. if (unlikely(cnts))
  80. return 0;
  81. return likely(atomic_cmpxchg_acquire(&lock->cnts,
  82. cnts, cnts | _QW_LOCKED) == cnts);
  83. }
  84. /**
  85. * queued_read_lock - acquire read lock of a queue rwlock
  86. * @lock: Pointer to queue rwlock structure
  87. */
  88. static inline void queued_read_lock(struct qrwlock *lock)
  89. {
  90. u32 cnts;
  91. cnts = atomic_add_return_acquire(_QR_BIAS, &lock->cnts);
  92. if (likely(!(cnts & _QW_WMASK)))
  93. return;
  94. /* The slowpath will decrement the reader count, if necessary. */
  95. queued_read_lock_slowpath(lock, cnts);
  96. }
  97. /**
  98. * queued_write_lock - acquire write lock of a queue rwlock
  99. * @lock : Pointer to queue rwlock structure
  100. */
  101. static inline void queued_write_lock(struct qrwlock *lock)
  102. {
  103. /* Optimize for the unfair lock case where the fair flag is 0. */
  104. if (atomic_cmpxchg_acquire(&lock->cnts, 0, _QW_LOCKED) == 0)
  105. return;
  106. queued_write_lock_slowpath(lock);
  107. }
  108. /**
  109. * queued_read_unlock - release read lock of a queue rwlock
  110. * @lock : Pointer to queue rwlock structure
  111. */
  112. static inline void queued_read_unlock(struct qrwlock *lock)
  113. {
  114. /*
  115. * Atomically decrement the reader count
  116. */
  117. (void)atomic_sub_return_release(_QR_BIAS, &lock->cnts);
  118. }
  119. /**
  120. * queued_write_unlock - release write lock of a queue rwlock
  121. * @lock : Pointer to queue rwlock structure
  122. */
  123. static inline void queued_write_unlock(struct qrwlock *lock)
  124. {
  125. smp_store_release((u8 *)&lock->cnts, 0);
  126. }
  127. /*
  128. * Remapping rwlock architecture specific functions to the corresponding
  129. * queue rwlock functions.
  130. */
  131. #define arch_read_can_lock(l) queued_read_can_lock(l)
  132. #define arch_write_can_lock(l) queued_write_can_lock(l)
  133. #define arch_read_lock(l) queued_read_lock(l)
  134. #define arch_write_lock(l) queued_write_lock(l)
  135. #define arch_read_trylock(l) queued_read_trylock(l)
  136. #define arch_write_trylock(l) queued_write_trylock(l)
  137. #define arch_read_unlock(l) queued_read_unlock(l)
  138. #define arch_write_unlock(l) queued_write_unlock(l)
  139. #endif /* __ASM_GENERIC_QRWLOCK_H */