spinlock_32.h 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. /*
  2. * Copyright 2010 Tilera Corporation. All Rights Reserved.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation, version 2.
  7. *
  8. * This program is distributed in the hope that it will be useful, but
  9. * WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
  11. * NON INFRINGEMENT. See the GNU General Public License for
  12. * more details.
  13. *
  14. * 32-bit SMP spinlocks.
  15. */
  16. #ifndef _ASM_TILE_SPINLOCK_32_H
  17. #define _ASM_TILE_SPINLOCK_32_H
  18. #include <linux/atomic.h>
  19. #include <asm/page.h>
  20. #include <linux/compiler.h>
  21. /*
  22. * We only use even ticket numbers so the '1' inserted by a tns is
  23. * an unambiguous "ticket is busy" flag.
  24. */
  25. #define TICKET_QUANTUM 2
  26. /*
  27. * SMP ticket spinlocks, allowing only a single CPU anywhere
  28. *
  29. * (the type definitions are in asm/spinlock_types.h)
  30. */
  31. static inline int arch_spin_is_locked(arch_spinlock_t *lock)
  32. {
  33. /*
  34. * Note that even if a new ticket is in the process of being
  35. * acquired, so lock->next_ticket is 1, it's still reasonable
  36. * to claim the lock is held, since it will be momentarily
  37. * if not already. There's no need to wait for a "valid"
  38. * lock->next_ticket to become available.
  39. */
  40. return lock->next_ticket != lock->current_ticket;
  41. }
  42. void arch_spin_lock(arch_spinlock_t *lock);
  43. /* We cannot take an interrupt after getting a ticket, so don't enable them. */
  44. #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
  45. int arch_spin_trylock(arch_spinlock_t *lock);
  46. static inline void arch_spin_unlock(arch_spinlock_t *lock)
  47. {
  48. /* For efficiency, overlap fetching the old ticket with the wmb(). */
  49. int old_ticket = lock->current_ticket;
  50. wmb(); /* guarantee anything modified under the lock is visible */
  51. lock->current_ticket = old_ticket + TICKET_QUANTUM;
  52. }
  53. void arch_spin_unlock_wait(arch_spinlock_t *lock);
  54. /*
  55. * Read-write spinlocks, allowing multiple readers
  56. * but only one writer.
  57. *
  58. * We use a "tns/store-back" technique on a single word to manage
  59. * the lock state, looping around to retry if the tns returns 1.
  60. */
  61. /* Internal layout of the word; do not use. */
  62. #define _WR_NEXT_SHIFT 8
  63. #define _WR_CURR_SHIFT 16
  64. #define _WR_WIDTH 8
  65. #define _RD_COUNT_SHIFT 24
  66. #define _RD_COUNT_WIDTH 8
  67. /**
  68. * arch_read_can_lock() - would read_trylock() succeed?
  69. */
  70. static inline int arch_read_can_lock(arch_rwlock_t *rwlock)
  71. {
  72. return (rwlock->lock << _RD_COUNT_WIDTH) == 0;
  73. }
  74. /**
  75. * arch_write_can_lock() - would write_trylock() succeed?
  76. */
  77. static inline int arch_write_can_lock(arch_rwlock_t *rwlock)
  78. {
  79. return rwlock->lock == 0;
  80. }
  81. /**
  82. * arch_read_lock() - acquire a read lock.
  83. */
  84. void arch_read_lock(arch_rwlock_t *rwlock);
  85. /**
  86. * arch_write_lock() - acquire a write lock.
  87. */
  88. void arch_write_lock(arch_rwlock_t *rwlock);
  89. /**
  90. * arch_read_trylock() - try to acquire a read lock.
  91. */
  92. int arch_read_trylock(arch_rwlock_t *rwlock);
  93. /**
  94. * arch_write_trylock() - try to acquire a write lock.
  95. */
  96. int arch_write_trylock(arch_rwlock_t *rwlock);
  97. /**
  98. * arch_read_unlock() - release a read lock.
  99. */
  100. void arch_read_unlock(arch_rwlock_t *rwlock);
  101. /**
  102. * arch_write_unlock() - release a write lock.
  103. */
  104. void arch_write_unlock(arch_rwlock_t *rwlock);
  105. #define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
  106. #define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
  107. #endif /* _ASM_TILE_SPINLOCK_32_H */