spinlock.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. /*
  2. * Out of line spinlock code.
  3. *
  4. * Copyright IBM Corp. 2004, 2006
  5. * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
  6. */
  7. #include <linux/types.h>
  8. #include <linux/export.h>
  9. #include <linux/spinlock.h>
  10. #include <linux/jiffies.h>
  11. #include <linux/init.h>
  12. #include <linux/smp.h>
  13. #include <linux/percpu.h>
  14. #include <asm/alternative.h>
  15. #include <asm/io.h>
  16. int spin_retry = -1;
  17. static int __init spin_retry_init(void)
  18. {
  19. if (spin_retry < 0)
  20. spin_retry = 1000;
  21. return 0;
  22. }
  23. early_initcall(spin_retry_init);
  24. /**
  25. * spin_retry= parameter
  26. */
  27. static int __init spin_retry_setup(char *str)
  28. {
  29. spin_retry = simple_strtoul(str, &str, 0);
  30. return 1;
  31. }
  32. __setup("spin_retry=", spin_retry_setup);
  33. struct spin_wait {
  34. struct spin_wait *next, *prev;
  35. int node_id;
  36. } __aligned(32);
  37. static DEFINE_PER_CPU_ALIGNED(struct spin_wait, spin_wait[4]);
  38. #define _Q_LOCK_CPU_OFFSET 0
  39. #define _Q_LOCK_STEAL_OFFSET 16
  40. #define _Q_TAIL_IDX_OFFSET 18
  41. #define _Q_TAIL_CPU_OFFSET 20
  42. #define _Q_LOCK_CPU_MASK 0x0000ffff
  43. #define _Q_LOCK_STEAL_ADD 0x00010000
  44. #define _Q_LOCK_STEAL_MASK 0x00030000
  45. #define _Q_TAIL_IDX_MASK 0x000c0000
  46. #define _Q_TAIL_CPU_MASK 0xfff00000
  47. #define _Q_LOCK_MASK (_Q_LOCK_CPU_MASK | _Q_LOCK_STEAL_MASK)
  48. #define _Q_TAIL_MASK (_Q_TAIL_IDX_MASK | _Q_TAIL_CPU_MASK)
  49. void arch_spin_lock_setup(int cpu)
  50. {
  51. struct spin_wait *node;
  52. int ix;
  53. node = per_cpu_ptr(&spin_wait[0], cpu);
  54. for (ix = 0; ix < 4; ix++, node++) {
  55. memset(node, 0, sizeof(*node));
  56. node->node_id = ((cpu + 1) << _Q_TAIL_CPU_OFFSET) +
  57. (ix << _Q_TAIL_IDX_OFFSET);
  58. }
  59. }
  60. static inline int arch_load_niai4(int *lock)
  61. {
  62. int owner;
  63. asm volatile(
  64. ALTERNATIVE("", ".long 0xb2fa0040", 49) /* NIAI 4 */
  65. " l %0,%1\n"
  66. : "=d" (owner) : "Q" (*lock) : "memory");
  67. return owner;
  68. }
  69. static inline int arch_cmpxchg_niai8(int *lock, int old, int new)
  70. {
  71. int expected = old;
  72. asm volatile(
  73. ALTERNATIVE("", ".long 0xb2fa0080", 49) /* NIAI 8 */
  74. " cs %0,%3,%1\n"
  75. : "=d" (old), "=Q" (*lock)
  76. : "0" (old), "d" (new), "Q" (*lock)
  77. : "cc", "memory");
  78. return expected == old;
  79. }
  80. static inline struct spin_wait *arch_spin_decode_tail(int lock)
  81. {
  82. int ix, cpu;
  83. ix = (lock & _Q_TAIL_IDX_MASK) >> _Q_TAIL_IDX_OFFSET;
  84. cpu = (lock & _Q_TAIL_CPU_MASK) >> _Q_TAIL_CPU_OFFSET;
  85. return per_cpu_ptr(&spin_wait[ix], cpu - 1);
  86. }
  87. static inline int arch_spin_yield_target(int lock, struct spin_wait *node)
  88. {
  89. if (lock & _Q_LOCK_CPU_MASK)
  90. return lock & _Q_LOCK_CPU_MASK;
  91. if (node == NULL || node->prev == NULL)
  92. return 0; /* 0 -> no target cpu */
  93. while (node->prev)
  94. node = node->prev;
  95. return node->node_id >> _Q_TAIL_CPU_OFFSET;
  96. }
  97. static inline void arch_spin_lock_queued(arch_spinlock_t *lp)
  98. {
  99. struct spin_wait *node, *next;
  100. int lockval, ix, node_id, tail_id, old, new, owner, count;
  101. ix = S390_lowcore.spinlock_index++;
  102. barrier();
  103. lockval = SPINLOCK_LOCKVAL; /* cpu + 1 */
  104. node = this_cpu_ptr(&spin_wait[ix]);
  105. node->prev = node->next = NULL;
  106. node_id = node->node_id;
  107. /* Enqueue the node for this CPU in the spinlock wait queue */
  108. while (1) {
  109. old = READ_ONCE(lp->lock);
  110. if ((old & _Q_LOCK_CPU_MASK) == 0 &&
  111. (old & _Q_LOCK_STEAL_MASK) != _Q_LOCK_STEAL_MASK) {
  112. /*
  113. * The lock is free but there may be waiters.
  114. * With no waiters simply take the lock, if there
  115. * are waiters try to steal the lock. The lock may
  116. * be stolen three times before the next queued
  117. * waiter will get the lock.
  118. */
  119. new = (old ? (old + _Q_LOCK_STEAL_ADD) : 0) | lockval;
  120. if (__atomic_cmpxchg_bool(&lp->lock, old, new))
  121. /* Got the lock */
  122. goto out;
  123. /* lock passing in progress */
  124. continue;
  125. }
  126. /* Make the node of this CPU the new tail. */
  127. new = node_id | (old & _Q_LOCK_MASK);
  128. if (__atomic_cmpxchg_bool(&lp->lock, old, new))
  129. break;
  130. }
  131. /* Set the 'next' pointer of the tail node in the queue */
  132. tail_id = old & _Q_TAIL_MASK;
  133. if (tail_id != 0) {
  134. node->prev = arch_spin_decode_tail(tail_id);
  135. WRITE_ONCE(node->prev->next, node);
  136. }
  137. /* Pass the virtual CPU to the lock holder if it is not running */
  138. owner = arch_spin_yield_target(old, node);
  139. if (owner && arch_vcpu_is_preempted(owner - 1))
  140. smp_yield_cpu(owner - 1);
  141. /* Spin on the CPU local node->prev pointer */
  142. if (tail_id != 0) {
  143. count = spin_retry;
  144. while (READ_ONCE(node->prev) != NULL) {
  145. if (count-- >= 0)
  146. continue;
  147. count = spin_retry;
  148. /* Query running state of lock holder again. */
  149. owner = arch_spin_yield_target(old, node);
  150. if (owner && arch_vcpu_is_preempted(owner - 1))
  151. smp_yield_cpu(owner - 1);
  152. }
  153. }
  154. /* Spin on the lock value in the spinlock_t */
  155. count = spin_retry;
  156. while (1) {
  157. old = READ_ONCE(lp->lock);
  158. owner = old & _Q_LOCK_CPU_MASK;
  159. if (!owner) {
  160. tail_id = old & _Q_TAIL_MASK;
  161. new = ((tail_id != node_id) ? tail_id : 0) | lockval;
  162. if (__atomic_cmpxchg_bool(&lp->lock, old, new))
  163. /* Got the lock */
  164. break;
  165. continue;
  166. }
  167. if (count-- >= 0)
  168. continue;
  169. count = spin_retry;
  170. if (!MACHINE_IS_LPAR || arch_vcpu_is_preempted(owner - 1))
  171. smp_yield_cpu(owner - 1);
  172. }
  173. /* Pass lock_spin job to next CPU in the queue */
  174. if (node_id && tail_id != node_id) {
  175. /* Wait until the next CPU has set up the 'next' pointer */
  176. while ((next = READ_ONCE(node->next)) == NULL)
  177. ;
  178. next->prev = NULL;
  179. }
  180. out:
  181. S390_lowcore.spinlock_index--;
  182. }
  183. static inline void arch_spin_lock_classic(arch_spinlock_t *lp)
  184. {
  185. int lockval, old, new, owner, count;
  186. lockval = SPINLOCK_LOCKVAL; /* cpu + 1 */
  187. /* Pass the virtual CPU to the lock holder if it is not running */
  188. owner = arch_spin_yield_target(ACCESS_ONCE(lp->lock), NULL);
  189. if (owner && arch_vcpu_is_preempted(owner - 1))
  190. smp_yield_cpu(owner - 1);
  191. count = spin_retry;
  192. while (1) {
  193. old = arch_load_niai4(&lp->lock);
  194. owner = old & _Q_LOCK_CPU_MASK;
  195. /* Try to get the lock if it is free. */
  196. if (!owner) {
  197. new = (old & _Q_TAIL_MASK) | lockval;
  198. if (arch_cmpxchg_niai8(&lp->lock, old, new))
  199. /* Got the lock */
  200. return;
  201. continue;
  202. }
  203. if (count-- >= 0)
  204. continue;
  205. count = spin_retry;
  206. if (!MACHINE_IS_LPAR || arch_vcpu_is_preempted(owner - 1))
  207. smp_yield_cpu(owner - 1);
  208. }
  209. }
  210. void arch_spin_lock_wait(arch_spinlock_t *lp)
  211. {
  212. /* Use classic spinlocks + niai if the steal time is >= 10% */
  213. if (test_cpu_flag(CIF_DEDICATED_CPU))
  214. arch_spin_lock_queued(lp);
  215. else
  216. arch_spin_lock_classic(lp);
  217. }
  218. EXPORT_SYMBOL(arch_spin_lock_wait);
  219. int arch_spin_trylock_retry(arch_spinlock_t *lp)
  220. {
  221. int cpu = SPINLOCK_LOCKVAL;
  222. int owner, count;
  223. for (count = spin_retry; count > 0; count--) {
  224. owner = READ_ONCE(lp->lock);
  225. /* Try to get the lock if it is free. */
  226. if (!owner) {
  227. if (__atomic_cmpxchg_bool(&lp->lock, 0, cpu))
  228. return 1;
  229. }
  230. }
  231. return 0;
  232. }
  233. EXPORT_SYMBOL(arch_spin_trylock_retry);
  234. void arch_read_lock_wait(arch_rwlock_t *rw)
  235. {
  236. if (unlikely(in_interrupt())) {
  237. while (READ_ONCE(rw->cnts) & 0x10000)
  238. barrier();
  239. return;
  240. }
  241. /* Remove this reader again to allow recursive read locking */
  242. __atomic_add_const(-1, &rw->cnts);
  243. /* Put the reader into the wait queue */
  244. arch_spin_lock(&rw->wait);
  245. /* Now add this reader to the count value again */
  246. __atomic_add_const(1, &rw->cnts);
  247. /* Loop until the writer is done */
  248. while (READ_ONCE(rw->cnts) & 0x10000)
  249. barrier();
  250. arch_spin_unlock(&rw->wait);
  251. }
  252. EXPORT_SYMBOL(arch_read_lock_wait);
  253. void arch_write_lock_wait(arch_rwlock_t *rw)
  254. {
  255. int old;
  256. /* Add this CPU to the write waiters */
  257. __atomic_add(0x20000, &rw->cnts);
  258. /* Put the writer into the wait queue */
  259. arch_spin_lock(&rw->wait);
  260. while (1) {
  261. old = READ_ONCE(rw->cnts);
  262. if ((old & 0x1ffff) == 0 &&
  263. __atomic_cmpxchg_bool(&rw->cnts, old, old | 0x10000))
  264. /* Got the lock */
  265. break;
  266. barrier();
  267. }
  268. arch_spin_unlock(&rw->wait);
  269. }
  270. EXPORT_SYMBOL(arch_write_lock_wait);
  271. void arch_spin_relax(arch_spinlock_t *lp)
  272. {
  273. int cpu;
  274. cpu = READ_ONCE(lp->lock) & _Q_LOCK_CPU_MASK;
  275. if (!cpu)
  276. return;
  277. if (MACHINE_IS_LPAR && !arch_vcpu_is_preempted(cpu - 1))
  278. return;
  279. smp_yield_cpu(cpu - 1);
  280. }
  281. EXPORT_SYMBOL(arch_spin_relax);