spinlock.h 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. #ifndef __ASM_SPINLOCK_H
  2. #define __ASM_SPINLOCK_H
  3. #if __LINUX_ARM_ARCH__ < 6
  4. #error SMP not supported on pre-ARMv6 CPUs
  5. #endif
  6. #include <asm/processor.h>
  7. /*
  8. * sev and wfe are ARMv6K extensions. Uniprocessor ARMv6 may not have the K
  9. * extensions, so when running on UP, we have to patch these instructions away.
  10. */
  11. #define ALT_SMP(smp, up) \
  12. "9998: " smp "\n" \
  13. " .pushsection \".alt.smp.init\", \"a\"\n" \
  14. " .long 9998b\n" \
  15. " " up "\n" \
  16. " .popsection\n"
  17. #ifdef CONFIG_THUMB2_KERNEL
  18. #define SEV ALT_SMP("sev.w", "nop.w")
  19. /*
  20. * For Thumb-2, special care is needed to ensure that the conditional WFE
  21. * instruction really does assemble to exactly 4 bytes (as required by
  22. * the SMP_ON_UP fixup code). By itself "wfene" might cause the
  23. * assembler to insert a extra (16-bit) IT instruction, depending on the
  24. * presence or absence of neighbouring conditional instructions.
  25. *
  26. * To avoid this unpredictableness, an approprite IT is inserted explicitly:
  27. * the assembler won't change IT instructions which are explicitly present
  28. * in the input.
  29. */
  30. #define WFE(cond) ALT_SMP( \
  31. "it " cond "\n\t" \
  32. "wfe" cond ".n", \
  33. \
  34. "nop.w" \
  35. )
  36. #else
  37. #define SEV ALT_SMP("sev", "nop")
  38. #define WFE(cond) ALT_SMP("wfe" cond, "nop")
  39. #endif
  40. static inline void dsb_sev(void)
  41. {
  42. #if __LINUX_ARM_ARCH__ >= 7
  43. __asm__ __volatile__ (
  44. "dsb\n"
  45. SEV
  46. );
  47. #else
  48. __asm__ __volatile__ (
  49. "mcr p15, 0, %0, c7, c10, 4\n"
  50. SEV
  51. : : "r" (0)
  52. );
  53. #endif
  54. }
  55. /*
  56. * ARMv6 Spin-locking.
  57. *
  58. * We exclusively read the old value. If it is zero, we may have
  59. * won the lock, so we try exclusively storing it. A memory barrier
  60. * is required after we get a lock, and before we release it, because
  61. * V6 CPUs are assumed to have weakly ordered memory.
  62. *
  63. * Unlocked value: 0
  64. * Locked value: 1
  65. */
  66. #define arch_spin_is_locked(x) ((x)->lock != 0)
  67. #define arch_spin_unlock_wait(lock) \
  68. do { while (arch_spin_is_locked(lock)) cpu_relax(); } while (0)
  69. #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
  70. static inline void arch_spin_lock(arch_spinlock_t *lock)
  71. {
  72. unsigned long tmp;
  73. __asm__ __volatile__(
  74. "1: ldrex %0, [%1]\n"
  75. " teq %0, #0\n"
  76. WFE("ne")
  77. " strexeq %0, %2, [%1]\n"
  78. " teqeq %0, #0\n"
  79. " bne 1b"
  80. : "=&r" (tmp)
  81. : "r" (&lock->lock), "r" (1)
  82. : "cc");
  83. smp_mb();
  84. }
  85. static inline int arch_spin_trylock(arch_spinlock_t *lock)
  86. {
  87. unsigned long tmp;
  88. __asm__ __volatile__(
  89. " ldrex %0, [%1]\n"
  90. " teq %0, #0\n"
  91. " strexeq %0, %2, [%1]"
  92. : "=&r" (tmp)
  93. : "r" (&lock->lock), "r" (1)
  94. : "cc");
  95. if (tmp == 0) {
  96. smp_mb();
  97. return 1;
  98. } else {
  99. return 0;
  100. }
  101. }
  102. static inline void arch_spin_unlock(arch_spinlock_t *lock)
  103. {
  104. smp_mb();
  105. __asm__ __volatile__(
  106. " str %1, [%0]\n"
  107. :
  108. : "r" (&lock->lock), "r" (0)
  109. : "cc");
  110. dsb_sev();
  111. }
  112. /*
  113. * RWLOCKS
  114. *
  115. *
  116. * Write locks are easy - we just set bit 31. When unlocking, we can
  117. * just write zero since the lock is exclusively held.
  118. */
  119. static inline void arch_write_lock(arch_rwlock_t *rw)
  120. {
  121. unsigned long tmp;
  122. __asm__ __volatile__(
  123. "1: ldrex %0, [%1]\n"
  124. " teq %0, #0\n"
  125. WFE("ne")
  126. " strexeq %0, %2, [%1]\n"
  127. " teq %0, #0\n"
  128. " bne 1b"
  129. : "=&r" (tmp)
  130. : "r" (&rw->lock), "r" (0x80000000)
  131. : "cc");
  132. smp_mb();
  133. }
  134. static inline int arch_write_trylock(arch_rwlock_t *rw)
  135. {
  136. unsigned long tmp;
  137. __asm__ __volatile__(
  138. "1: ldrex %0, [%1]\n"
  139. " teq %0, #0\n"
  140. " strexeq %0, %2, [%1]"
  141. : "=&r" (tmp)
  142. : "r" (&rw->lock), "r" (0x80000000)
  143. : "cc");
  144. if (tmp == 0) {
  145. smp_mb();
  146. return 1;
  147. } else {
  148. return 0;
  149. }
  150. }
  151. static inline void arch_write_unlock(arch_rwlock_t *rw)
  152. {
  153. smp_mb();
  154. __asm__ __volatile__(
  155. "str %1, [%0]\n"
  156. :
  157. : "r" (&rw->lock), "r" (0)
  158. : "cc");
  159. dsb_sev();
  160. }
  161. /* write_can_lock - would write_trylock() succeed? */
  162. #define arch_write_can_lock(x) ((x)->lock == 0)
  163. /*
  164. * Read locks are a bit more hairy:
  165. * - Exclusively load the lock value.
  166. * - Increment it.
  167. * - Store new lock value if positive, and we still own this location.
  168. * If the value is negative, we've already failed.
  169. * - If we failed to store the value, we want a negative result.
  170. * - If we failed, try again.
  171. * Unlocking is similarly hairy. We may have multiple read locks
  172. * currently active. However, we know we won't have any write
  173. * locks.
  174. */
  175. static inline void arch_read_lock(arch_rwlock_t *rw)
  176. {
  177. unsigned long tmp, tmp2;
  178. __asm__ __volatile__(
  179. "1: ldrex %0, [%2]\n"
  180. " adds %0, %0, #1\n"
  181. " strexpl %1, %0, [%2]\n"
  182. WFE("mi")
  183. " rsbpls %0, %1, #0\n"
  184. " bmi 1b"
  185. : "=&r" (tmp), "=&r" (tmp2)
  186. : "r" (&rw->lock)
  187. : "cc");
  188. smp_mb();
  189. }
  190. static inline void arch_read_unlock(arch_rwlock_t *rw)
  191. {
  192. unsigned long tmp, tmp2;
  193. smp_mb();
  194. __asm__ __volatile__(
  195. "1: ldrex %0, [%2]\n"
  196. " sub %0, %0, #1\n"
  197. " strex %1, %0, [%2]\n"
  198. " teq %1, #0\n"
  199. " bne 1b"
  200. : "=&r" (tmp), "=&r" (tmp2)
  201. : "r" (&rw->lock)
  202. : "cc");
  203. if (tmp == 0)
  204. dsb_sev();
  205. }
  206. static inline int arch_read_trylock(arch_rwlock_t *rw)
  207. {
  208. unsigned long tmp, tmp2 = 1;
  209. __asm__ __volatile__(
  210. "1: ldrex %0, [%2]\n"
  211. " adds %0, %0, #1\n"
  212. " strexpl %1, %0, [%2]\n"
  213. : "=&r" (tmp), "+r" (tmp2)
  214. : "r" (&rw->lock)
  215. : "cc");
  216. smp_mb();
  217. return tmp2 == 0;
  218. }
  219. /* read_can_lock - would read_trylock() succeed? */
  220. #define arch_read_can_lock(x) ((x)->lock < 0x80000000)
  221. #define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
  222. #define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
  223. #define arch_spin_relax(lock) cpu_relax()
  224. #define arch_read_relax(lock) cpu_relax()
  225. #define arch_write_relax(lock) cpu_relax()
  226. #endif /* __ASM_SPINLOCK_H */