qrwlock.h 3.8 KB

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