spinlock.h 5.3 KB

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