debuglocks.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. /* $Id: debuglocks.c,v 1.9 2001/11/17 00:10:48 davem Exp $
  2. * debuglocks.c: Debugging versions of SMP locking primitives.
  3. *
  4. * Copyright (C) 1998 David S. Miller (davem@redhat.com)
  5. */
  6. #include <linux/config.h>
  7. #include <linux/kernel.h>
  8. #include <linux/sched.h>
  9. #include <linux/spinlock.h>
  10. #include <asm/system.h>
  11. #ifdef CONFIG_SMP
  12. #define GET_CALLER(PC) __asm__ __volatile__("mov %%i7, %0" : "=r" (PC))
  13. static inline void show (char *str, spinlock_t *lock, unsigned long caller)
  14. {
  15. int cpu = smp_processor_id();
  16. printk("%s(%p) CPU#%d stuck at %08x, owner PC(%08x):CPU(%x)\n",
  17. str, lock, cpu, (unsigned int) caller,
  18. lock->owner_pc, lock->owner_cpu);
  19. }
  20. static inline void show_read (char *str, rwlock_t *lock, unsigned long caller)
  21. {
  22. int cpu = smp_processor_id();
  23. printk("%s(%p) CPU#%d stuck at %08x, writer PC(%08x):CPU(%x)\n",
  24. str, lock, cpu, (unsigned int) caller,
  25. lock->writer_pc, lock->writer_cpu);
  26. }
  27. static inline void show_write (char *str, rwlock_t *lock, unsigned long caller)
  28. {
  29. int cpu = smp_processor_id();
  30. int i;
  31. printk("%s(%p) CPU#%d stuck at %08x\n",
  32. str, lock, cpu, (unsigned int) caller);
  33. printk("Writer: PC(%08x):CPU(%x)\n",
  34. lock->writer_pc, lock->writer_cpu);
  35. printk("Readers:");
  36. for (i = 0; i < NR_CPUS; i++)
  37. if (lock->reader_pc[i])
  38. printk(" %d[%08x]", i, lock->reader_pc[i]);
  39. printk("\n");
  40. }
  41. #undef INIT_STUCK
  42. #define INIT_STUCK 100000000
  43. void _do_spin_lock(spinlock_t *lock, char *str)
  44. {
  45. unsigned long caller, val;
  46. int stuck = INIT_STUCK;
  47. int cpu = get_cpu();
  48. int shown = 0;
  49. GET_CALLER(caller);
  50. again:
  51. __asm__ __volatile__("ldstub [%1], %0"
  52. : "=r" (val)
  53. : "r" (&(lock->lock))
  54. : "memory");
  55. membar("#StoreLoad | #StoreStore");
  56. if (val) {
  57. while (lock->lock) {
  58. if (!--stuck) {
  59. if (shown++ <= 2)
  60. show(str, lock, caller);
  61. stuck = INIT_STUCK;
  62. }
  63. membar("#LoadLoad");
  64. }
  65. goto again;
  66. }
  67. lock->owner_pc = ((unsigned int)caller);
  68. lock->owner_cpu = cpu;
  69. current->thread.smp_lock_count++;
  70. current->thread.smp_lock_pc = ((unsigned int)caller);
  71. put_cpu();
  72. }
  73. int _do_spin_trylock(spinlock_t *lock)
  74. {
  75. unsigned long val, caller;
  76. int cpu = get_cpu();
  77. GET_CALLER(caller);
  78. __asm__ __volatile__("ldstub [%1], %0"
  79. : "=r" (val)
  80. : "r" (&(lock->lock))
  81. : "memory");
  82. membar("#StoreLoad | #StoreStore");
  83. if (!val) {
  84. lock->owner_pc = ((unsigned int)caller);
  85. lock->owner_cpu = cpu;
  86. current->thread.smp_lock_count++;
  87. current->thread.smp_lock_pc = ((unsigned int)caller);
  88. }
  89. put_cpu();
  90. return val == 0;
  91. }
  92. void _do_spin_unlock(spinlock_t *lock)
  93. {
  94. lock->owner_pc = 0;
  95. lock->owner_cpu = NO_PROC_ID;
  96. membar("#StoreStore | #LoadStore");
  97. lock->lock = 0;
  98. current->thread.smp_lock_count--;
  99. }
  100. /* Keep INIT_STUCK the same... */
  101. void _do_read_lock (rwlock_t *rw, char *str)
  102. {
  103. unsigned long caller, val;
  104. int stuck = INIT_STUCK;
  105. int cpu = get_cpu();
  106. int shown = 0;
  107. GET_CALLER(caller);
  108. wlock_again:
  109. /* Wait for any writer to go away. */
  110. while (((long)(rw->lock)) < 0) {
  111. if (!--stuck) {
  112. if (shown++ <= 2)
  113. show_read(str, rw, caller);
  114. stuck = INIT_STUCK;
  115. }
  116. membar("#LoadLoad");
  117. }
  118. /* Try once to increment the counter. */
  119. __asm__ __volatile__(
  120. " ldx [%0], %%g1\n"
  121. " brlz,a,pn %%g1, 2f\n"
  122. " mov 1, %0\n"
  123. " add %%g1, 1, %%g7\n"
  124. " casx [%0], %%g1, %%g7\n"
  125. " sub %%g1, %%g7, %0\n"
  126. "2:" : "=r" (val)
  127. : "0" (&(rw->lock))
  128. : "g1", "g7", "memory");
  129. membar("#StoreLoad | #StoreStore");
  130. if (val)
  131. goto wlock_again;
  132. rw->reader_pc[cpu] = ((unsigned int)caller);
  133. current->thread.smp_lock_count++;
  134. current->thread.smp_lock_pc = ((unsigned int)caller);
  135. put_cpu();
  136. }
  137. void _do_read_unlock (rwlock_t *rw, char *str)
  138. {
  139. unsigned long caller, val;
  140. int stuck = INIT_STUCK;
  141. int cpu = get_cpu();
  142. int shown = 0;
  143. GET_CALLER(caller);
  144. /* Drop our identity _first_. */
  145. rw->reader_pc[cpu] = 0;
  146. current->thread.smp_lock_count--;
  147. runlock_again:
  148. /* Spin trying to decrement the counter using casx. */
  149. __asm__ __volatile__(
  150. " membar #StoreLoad | #LoadLoad\n"
  151. " ldx [%0], %%g1\n"
  152. " sub %%g1, 1, %%g7\n"
  153. " casx [%0], %%g1, %%g7\n"
  154. " membar #StoreLoad | #StoreStore\n"
  155. " sub %%g1, %%g7, %0\n"
  156. : "=r" (val)
  157. : "0" (&(rw->lock))
  158. : "g1", "g7", "memory");
  159. if (val) {
  160. if (!--stuck) {
  161. if (shown++ <= 2)
  162. show_read(str, rw, caller);
  163. stuck = INIT_STUCK;
  164. }
  165. goto runlock_again;
  166. }
  167. put_cpu();
  168. }
  169. void _do_write_lock (rwlock_t *rw, char *str)
  170. {
  171. unsigned long caller, val;
  172. int stuck = INIT_STUCK;
  173. int cpu = get_cpu();
  174. int shown = 0;
  175. GET_CALLER(caller);
  176. wlock_again:
  177. /* Spin while there is another writer. */
  178. while (((long)rw->lock) < 0) {
  179. if (!--stuck) {
  180. if (shown++ <= 2)
  181. show_write(str, rw, caller);
  182. stuck = INIT_STUCK;
  183. }
  184. membar("#LoadLoad");
  185. }
  186. /* Try to acuire the write bit. */
  187. __asm__ __volatile__(
  188. " mov 1, %%g3\n"
  189. " sllx %%g3, 63, %%g3\n"
  190. " ldx [%0], %%g1\n"
  191. " brlz,pn %%g1, 1f\n"
  192. " or %%g1, %%g3, %%g7\n"
  193. " casx [%0], %%g1, %%g7\n"
  194. " membar #StoreLoad | #StoreStore\n"
  195. " ba,pt %%xcc, 2f\n"
  196. " sub %%g1, %%g7, %0\n"
  197. "1: mov 1, %0\n"
  198. "2:" : "=r" (val)
  199. : "0" (&(rw->lock))
  200. : "g3", "g1", "g7", "memory");
  201. if (val) {
  202. /* We couldn't get the write bit. */
  203. if (!--stuck) {
  204. if (shown++ <= 2)
  205. show_write(str, rw, caller);
  206. stuck = INIT_STUCK;
  207. }
  208. goto wlock_again;
  209. }
  210. if ((rw->lock & ((1UL<<63)-1UL)) != 0UL) {
  211. /* Readers still around, drop the write
  212. * lock, spin, and try again.
  213. */
  214. if (!--stuck) {
  215. if (shown++ <= 2)
  216. show_write(str, rw, caller);
  217. stuck = INIT_STUCK;
  218. }
  219. __asm__ __volatile__(
  220. " mov 1, %%g3\n"
  221. " sllx %%g3, 63, %%g3\n"
  222. "1: ldx [%0], %%g1\n"
  223. " andn %%g1, %%g3, %%g7\n"
  224. " casx [%0], %%g1, %%g7\n"
  225. " cmp %%g1, %%g7\n"
  226. " membar #StoreLoad | #StoreStore\n"
  227. " bne,pn %%xcc, 1b\n"
  228. " nop"
  229. : /* no outputs */
  230. : "r" (&(rw->lock))
  231. : "g3", "g1", "g7", "cc", "memory");
  232. while(rw->lock != 0) {
  233. if (!--stuck) {
  234. if (shown++ <= 2)
  235. show_write(str, rw, caller);
  236. stuck = INIT_STUCK;
  237. }
  238. membar("#LoadLoad");
  239. }
  240. goto wlock_again;
  241. }
  242. /* We have it, say who we are. */
  243. rw->writer_pc = ((unsigned int)caller);
  244. rw->writer_cpu = cpu;
  245. current->thread.smp_lock_count++;
  246. current->thread.smp_lock_pc = ((unsigned int)caller);
  247. put_cpu();
  248. }
  249. void _do_write_unlock(rwlock_t *rw)
  250. {
  251. unsigned long caller, val;
  252. int stuck = INIT_STUCK;
  253. int shown = 0;
  254. GET_CALLER(caller);
  255. /* Drop our identity _first_ */
  256. rw->writer_pc = 0;
  257. rw->writer_cpu = NO_PROC_ID;
  258. current->thread.smp_lock_count--;
  259. wlock_again:
  260. __asm__ __volatile__(
  261. " membar #StoreLoad | #LoadLoad\n"
  262. " mov 1, %%g3\n"
  263. " sllx %%g3, 63, %%g3\n"
  264. " ldx [%0], %%g1\n"
  265. " andn %%g1, %%g3, %%g7\n"
  266. " casx [%0], %%g1, %%g7\n"
  267. " membar #StoreLoad | #StoreStore\n"
  268. " sub %%g1, %%g7, %0\n"
  269. : "=r" (val)
  270. : "0" (&(rw->lock))
  271. : "g3", "g1", "g7", "memory");
  272. if (val) {
  273. if (!--stuck) {
  274. if (shown++ <= 2)
  275. show_write("write_unlock", rw, caller);
  276. stuck = INIT_STUCK;
  277. }
  278. goto wlock_again;
  279. }
  280. }
  281. int _do_write_trylock (rwlock_t *rw, char *str)
  282. {
  283. unsigned long caller, val;
  284. int cpu = get_cpu();
  285. GET_CALLER(caller);
  286. /* Try to acuire the write bit. */
  287. __asm__ __volatile__(
  288. " mov 1, %%g3\n"
  289. " sllx %%g3, 63, %%g3\n"
  290. " ldx [%0], %%g1\n"
  291. " brlz,pn %%g1, 1f\n"
  292. " or %%g1, %%g3, %%g7\n"
  293. " casx [%0], %%g1, %%g7\n"
  294. " membar #StoreLoad | #StoreStore\n"
  295. " ba,pt %%xcc, 2f\n"
  296. " sub %%g1, %%g7, %0\n"
  297. "1: mov 1, %0\n"
  298. "2:" : "=r" (val)
  299. : "0" (&(rw->lock))
  300. : "g3", "g1", "g7", "memory");
  301. if (val) {
  302. put_cpu();
  303. return 0;
  304. }
  305. if ((rw->lock & ((1UL<<63)-1UL)) != 0UL) {
  306. /* Readers still around, drop the write
  307. * lock, return failure.
  308. */
  309. __asm__ __volatile__(
  310. " mov 1, %%g3\n"
  311. " sllx %%g3, 63, %%g3\n"
  312. "1: ldx [%0], %%g1\n"
  313. " andn %%g1, %%g3, %%g7\n"
  314. " casx [%0], %%g1, %%g7\n"
  315. " cmp %%g1, %%g7\n"
  316. " membar #StoreLoad | #StoreStore\n"
  317. " bne,pn %%xcc, 1b\n"
  318. " nop"
  319. : /* no outputs */
  320. : "r" (&(rw->lock))
  321. : "g3", "g1", "g7", "cc", "memory");
  322. put_cpu();
  323. return 0;
  324. }
  325. /* We have it, say who we are. */
  326. rw->writer_pc = ((unsigned int)caller);
  327. rw->writer_cpu = cpu;
  328. current->thread.smp_lock_count++;
  329. current->thread.smp_lock_pc = ((unsigned int)caller);
  330. put_cpu();
  331. return 1;
  332. }
  333. #endif /* CONFIG_SMP */