spinlock.h 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430
  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. extern int msm_krait_need_wfe_fixup;
  8. /*
  9. * sev and wfe are ARMv6K extensions. Uniprocessor ARMv6 may not have the K
  10. * extensions, so when running on UP, we have to patch these instructions away.
  11. */
  12. #define ALT_SMP(smp, up) \
  13. "9998: " smp "\n" \
  14. " .pushsection \".alt.smp.init\", \"a\"\n" \
  15. " .long 9998b\n" \
  16. " " up "\n" \
  17. " .popsection\n"
  18. #ifdef CONFIG_THUMB2_KERNEL
  19. #define SEV ALT_SMP("sev.w", "nop.w")
  20. /*
  21. * Both instructions given to the ALT_SMP macro need to be the same size, to
  22. * allow the SMP_ON_UP fixups to function correctly. Hence the explicit encoding
  23. * specifications.
  24. */
  25. #define WFE() ALT_SMP( \
  26. "wfe.w", \
  27. "nop.w" \
  28. )
  29. #else
  30. #define SEV ALT_SMP("sev", "nop")
  31. #define WFE() ALT_SMP("wfe", "nop")
  32. #endif
  33. /*
  34. * The fixup involves disabling FIQs during execution of the WFE instruction.
  35. * This could potentially lead to deadlock if a thread is trying to acquire a
  36. * spinlock which is being released from an FIQ. This should not be a problem
  37. * because FIQs are handled by the secure environment and do not directly
  38. * manipulate spinlocks.
  39. */
  40. #ifdef CONFIG_MSM_KRAIT_WFE_FIXUP
  41. #define WFE_SAFE(fixup, tmp) \
  42. " mrs " tmp ", cpsr\n" \
  43. " cmp " fixup ", #0\n" \
  44. " wfeeq\n" \
  45. " beq 10f\n" \
  46. " cpsid f\n" \
  47. " mrc p15, 7, " fixup ", c15, c0, 5\n" \
  48. " bic " fixup ", " fixup ", #0x10000\n" \
  49. " mcr p15, 7, " fixup ", c15, c0, 5\n" \
  50. " isb\n" \
  51. " wfe\n" \
  52. " orr " fixup ", " fixup ", #0x10000\n" \
  53. " mcr p15, 7, " fixup ", c15, c0, 5\n" \
  54. " isb\n" \
  55. "10: msr cpsr_cf, " tmp "\n"
  56. #else
  57. #define WFE_SAFE(fixup, tmp) " wfe\n"
  58. #endif
  59. static inline void dsb_sev(void)
  60. {
  61. #if __LINUX_ARM_ARCH__ >= 7
  62. __asm__ __volatile__ (
  63. "dsb\n"
  64. SEV
  65. );
  66. #else
  67. __asm__ __volatile__ (
  68. "mcr p15, 0, %0, c7, c10, 4\n"
  69. SEV
  70. : : "r" (0)
  71. );
  72. #endif
  73. }
  74. #ifndef CONFIG_ARM_TICKET_LOCKS
  75. /*
  76. * ARMv6 Spin-locking.
  77. *
  78. * We exclusively read the old value. If it is zero, we may have
  79. * won the lock, so we try exclusively storing it. A memory barrier
  80. * is required after we get a lock, and before we release it, because
  81. * V6 CPUs are assumed to have weakly ordered memory.
  82. *
  83. * Unlocked value: 0
  84. * Locked value: 1
  85. */
  86. #define arch_spin_is_locked(x) ((x)->lock != 0)
  87. #define arch_spin_unlock_wait(lock) \
  88. do { while (arch_spin_is_locked(lock)) cpu_relax(); } while (0)
  89. #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
  90. static inline void arch_spin_lock(arch_spinlock_t *lock)
  91. {
  92. unsigned long tmp, fixup = msm_krait_need_wfe_fixup;
  93. __asm__ __volatile__(
  94. "1: ldrex %[tmp], [%[lock]]\n"
  95. " teq %[tmp], #0\n"
  96. " beq 2f\n"
  97. WFE_SAFE("%[fixup]", "%[tmp]")
  98. "2:\n"
  99. " strexeq %[tmp], %[bit0], [%[lock]]\n"
  100. " teqeq %[tmp], #0\n"
  101. " bne 1b"
  102. : [tmp] "=&r" (tmp), [fixup] "+r" (fixup)
  103. : [lock] "r" (&lock->lock), [bit0] "r" (1)
  104. : "cc");
  105. smp_mb();
  106. }
  107. static inline int arch_spin_trylock(arch_spinlock_t *lock)
  108. {
  109. unsigned long tmp;
  110. __asm__ __volatile__(
  111. " ldrex %0, [%1]\n"
  112. " teq %0, #0\n"
  113. " strexeq %0, %2, [%1]"
  114. : "=&r" (tmp)
  115. : "r" (&lock->lock), "r" (1)
  116. : "cc");
  117. if (tmp == 0) {
  118. smp_mb();
  119. return 1;
  120. } else {
  121. return 0;
  122. }
  123. }
  124. static inline void arch_spin_unlock(arch_spinlock_t *lock)
  125. {
  126. smp_mb();
  127. __asm__ __volatile__(
  128. " str %1, [%0]\n"
  129. :
  130. : "r" (&lock->lock), "r" (0)
  131. : "cc");
  132. dsb_sev();
  133. }
  134. #else
  135. /*
  136. * ARM Ticket spin-locking
  137. *
  138. * Ticket locks are conceptually two parts, one indicating the current head of
  139. * the queue, and the other indicating the current tail. The lock is acquired
  140. * by atomically noting the tail and incrementing it by one (thus adding
  141. * ourself to the queue and noting our position), then waiting until the head
  142. * becomes equal to the the initial value of the tail.
  143. *
  144. * Unlocked value: 0
  145. * Locked value: now_serving != next_ticket
  146. *
  147. * 31 17 16 15 14 0
  148. * +----------------------------------------------------+
  149. * | now_serving | next_ticket |
  150. * +----------------------------------------------------+
  151. */
  152. #define TICKET_SHIFT 16
  153. #define TICKET_BITS 16
  154. #define TICKET_MASK 0xFFFF
  155. #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock)
  156. static inline void arch_spin_lock(arch_spinlock_t *lock)
  157. {
  158. unsigned long tmp, ticket, next_ticket;
  159. unsigned long fixup = msm_krait_need_wfe_fixup;
  160. /* Grab the next ticket and wait for it to be "served" */
  161. __asm__ __volatile__(
  162. "1: ldrex %[ticket], [%[lockaddr]]\n"
  163. " uadd16 %[next_ticket], %[ticket], %[val1]\n"
  164. " strex %[tmp], %[next_ticket], [%[lockaddr]]\n"
  165. " teq %[tmp], #0\n"
  166. " bne 1b\n"
  167. " uxth %[ticket], %[ticket]\n"
  168. "2:\n"
  169. #ifdef CONFIG_CPU_32v6K
  170. " beq 3f\n"
  171. WFE_SAFE("%[fixup]", "%[tmp]")
  172. "3:\n"
  173. #endif
  174. " ldr %[tmp], [%[lockaddr]]\n"
  175. " cmp %[ticket], %[tmp], lsr #16\n"
  176. " bne 2b"
  177. : [ticket]"=&r" (ticket), [tmp]"=&r" (tmp),
  178. [next_ticket]"=&r" (next_ticket), [fixup]"+r" (fixup)
  179. : [lockaddr]"r" (&lock->lock), [val1]"r" (1)
  180. : "cc");
  181. smp_mb();
  182. }
  183. static inline int arch_spin_trylock(arch_spinlock_t *lock)
  184. {
  185. unsigned long tmp, ticket, next_ticket;
  186. /* Grab lock if now_serving == next_ticket and access is exclusive */
  187. __asm__ __volatile__(
  188. " ldrex %[ticket], [%[lockaddr]]\n"
  189. " ror %[tmp], %[ticket], #16\n"
  190. " eors %[tmp], %[tmp], %[ticket]\n"
  191. " bne 1f\n"
  192. " uadd16 %[next_ticket], %[ticket], %[val1]\n"
  193. " strex %[tmp], %[next_ticket], [%[lockaddr]]\n"
  194. "1:"
  195. : [ticket]"=&r" (ticket), [tmp]"=&r" (tmp),
  196. [next_ticket]"=&r" (next_ticket)
  197. : [lockaddr]"r" (&lock->lock), [val1]"r" (1)
  198. : "cc");
  199. if (!tmp)
  200. smp_mb();
  201. return !tmp;
  202. }
  203. static inline void arch_spin_unlock(arch_spinlock_t *lock)
  204. {
  205. unsigned long ticket, tmp;
  206. smp_mb();
  207. /* Bump now_serving by 1 */
  208. __asm__ __volatile__(
  209. "1: ldrex %[ticket], [%[lockaddr]]\n"
  210. " uadd16 %[ticket], %[ticket], %[serving1]\n"
  211. " strex %[tmp], %[ticket], [%[lockaddr]]\n"
  212. " teq %[tmp], #0\n"
  213. " bne 1b"
  214. : [ticket]"=&r" (ticket), [tmp]"=&r" (tmp)
  215. : [lockaddr]"r" (&lock->lock), [serving1]"r" (0x00010000)
  216. : "cc");
  217. dsb_sev();
  218. }
  219. static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
  220. {
  221. unsigned long ticket, tmp, fixup = msm_krait_need_wfe_fixup;
  222. /* Wait for now_serving == next_ticket */
  223. __asm__ __volatile__(
  224. #ifdef CONFIG_CPU_32v6K
  225. " cmpne %[lockaddr], %[lockaddr]\n"
  226. "1:\n"
  227. " beq 2f\n"
  228. WFE_SAFE("%[fixup]", "%[tmp]")
  229. "2:\n"
  230. #else
  231. "1:\n"
  232. #endif
  233. " ldr %[ticket], [%[lockaddr]]\n"
  234. " eor %[ticket], %[ticket], %[ticket], lsr #16\n"
  235. " uxth %[ticket], %[ticket]\n"
  236. " cmp %[ticket], #0\n"
  237. " bne 1b"
  238. : [ticket]"=&r" (ticket), [tmp]"=&r" (tmp),
  239. [fixup]"+r" (fixup)
  240. : [lockaddr]"r" (&lock->lock)
  241. : "cc");
  242. }
  243. static inline int arch_spin_is_locked(arch_spinlock_t *lock)
  244. {
  245. unsigned long tmp = ACCESS_ONCE(lock->lock);
  246. return (((tmp >> TICKET_SHIFT) ^ tmp) & TICKET_MASK) != 0;
  247. }
  248. static inline int arch_spin_is_contended(arch_spinlock_t *lock)
  249. {
  250. unsigned long tmp = ACCESS_ONCE(lock->lock);
  251. return ((tmp - (tmp >> TICKET_SHIFT)) & TICKET_MASK) > 1;
  252. }
  253. #endif
  254. /*
  255. * RWLOCKS
  256. *
  257. *
  258. * Write locks are easy - we just set bit 31. When unlocking, we can
  259. * just write zero since the lock is exclusively held.
  260. */
  261. static inline void arch_write_lock(arch_rwlock_t *rw)
  262. {
  263. unsigned long tmp, fixup = msm_krait_need_wfe_fixup;
  264. __asm__ __volatile__(
  265. "1: ldrex %[tmp], [%[lock]]\n"
  266. " teq %[tmp], #0\n"
  267. " beq 2f\n"
  268. WFE_SAFE("%[fixup]", "%[tmp]")
  269. "2:\n"
  270. " strexeq %[tmp], %[bit31], [%[lock]]\n"
  271. " teq %[tmp], #0\n"
  272. " bne 1b"
  273. : [tmp] "=&r" (tmp), [fixup] "+r" (fixup)
  274. : [lock] "r" (&rw->lock), [bit31] "r" (0x80000000)
  275. : "cc");
  276. smp_mb();
  277. }
  278. static inline int arch_write_trylock(arch_rwlock_t *rw)
  279. {
  280. unsigned long tmp;
  281. __asm__ __volatile__(
  282. "1: ldrex %0, [%1]\n"
  283. " teq %0, #0\n"
  284. " strexeq %0, %2, [%1]"
  285. : "=&r" (tmp)
  286. : "r" (&rw->lock), "r" (0x80000000)
  287. : "cc");
  288. if (tmp == 0) {
  289. smp_mb();
  290. return 1;
  291. } else {
  292. return 0;
  293. }
  294. }
  295. static inline void arch_write_unlock(arch_rwlock_t *rw)
  296. {
  297. smp_mb();
  298. __asm__ __volatile__(
  299. "str %1, [%0]\n"
  300. :
  301. : "r" (&rw->lock), "r" (0)
  302. : "cc");
  303. dsb_sev();
  304. }
  305. /* write_can_lock - would write_trylock() succeed? */
  306. #define arch_write_can_lock(x) ((x)->lock == 0)
  307. /*
  308. * Read locks are a bit more hairy:
  309. * - Exclusively load the lock value.
  310. * - Increment it.
  311. * - Store new lock value if positive, and we still own this location.
  312. * If the value is negative, we've already failed.
  313. * - If we failed to store the value, we want a negative result.
  314. * - If we failed, try again.
  315. * Unlocking is similarly hairy. We may have multiple read locks
  316. * currently active. However, we know we won't have any write
  317. * locks.
  318. */
  319. static inline void arch_read_lock(arch_rwlock_t *rw)
  320. {
  321. unsigned long tmp, tmp2, fixup = msm_krait_need_wfe_fixup;
  322. __asm__ __volatile__(
  323. "1: ldrex %[tmp], [%[lock]]\n"
  324. " adds %[tmp], %[tmp], #1\n"
  325. " strexpl %[tmp2], %[tmp], [%[lock]]\n"
  326. " bpl 2f\n"
  327. WFE_SAFE("%[fixup]", "%[tmp]")
  328. "2:\n"
  329. " rsbpls %[tmp], %[tmp2], #0\n"
  330. " bmi 1b"
  331. : [tmp] "=&r" (tmp), [tmp2] "=&r" (tmp2), [fixup] "+r" (fixup)
  332. : [lock] "r" (&rw->lock)
  333. : "cc");
  334. smp_mb();
  335. }
  336. static inline void arch_read_unlock(arch_rwlock_t *rw)
  337. {
  338. unsigned long tmp, tmp2;
  339. smp_mb();
  340. __asm__ __volatile__(
  341. "1: ldrex %0, [%2]\n"
  342. " sub %0, %0, #1\n"
  343. " strex %1, %0, [%2]\n"
  344. " teq %1, #0\n"
  345. " bne 1b"
  346. : "=&r" (tmp), "=&r" (tmp2)
  347. : "r" (&rw->lock)
  348. : "cc");
  349. if (tmp == 0)
  350. dsb_sev();
  351. }
  352. static inline int arch_read_trylock(arch_rwlock_t *rw)
  353. {
  354. unsigned long tmp, tmp2 = 1;
  355. __asm__ __volatile__(
  356. "1: ldrex %0, [%2]\n"
  357. " adds %0, %0, #1\n"
  358. " strexpl %1, %0, [%2]\n"
  359. : "=&r" (tmp), "+r" (tmp2)
  360. : "r" (&rw->lock)
  361. : "cc");
  362. smp_mb();
  363. return tmp2 == 0;
  364. }
  365. /* read_can_lock - would read_trylock() succeed? */
  366. #define arch_read_can_lock(x) ((x)->lock < 0x80000000)
  367. #define arch_read_lock_flags(lock, flags) arch_read_lock(lock)
  368. #define arch_write_lock_flags(lock, flags) arch_write_lock(lock)
  369. #define arch_spin_relax(lock) cpu_relax()
  370. #define arch_read_relax(lock) cpu_relax()
  371. #define arch_write_relax(lock) cpu_relax()
  372. #endif /* __ASM_SPINLOCK_H */