debuglocks.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. /* $Id: debuglocks.c,v 1.11 2001/09/20 00:35:31 davem Exp $
  2. * debuglocks.c: Debugging versions of SMP locking primitives.
  3. *
  4. * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
  5. * Copyright (C) 1998-99 Anton Blanchard (anton@progsoc.uts.edu.au)
  6. */
  7. #include <linux/kernel.h>
  8. #include <linux/sched.h>
  9. #include <linux/threads.h> /* For NR_CPUS */
  10. #include <linux/spinlock.h>
  11. #include <asm/psr.h>
  12. #include <asm/system.h>
  13. #ifdef CONFIG_SMP
  14. /* Some notes on how these debugging routines work. When a lock is acquired
  15. * an extra debugging member lock->owner_pc is set to the caller of the lock
  16. * acquisition routine. Right before releasing a lock, the debugging program
  17. * counter is cleared to zero.
  18. *
  19. * Furthermore, since PC's are 4 byte aligned on Sparc, we stuff the CPU
  20. * number of the owner in the lowest two bits.
  21. */
  22. #define STORE_CALLER(A) __asm__ __volatile__("mov %%i7, %0" : "=r" (A));
  23. static inline void show(char *str, spinlock_t *lock, unsigned long caller)
  24. {
  25. int cpu = smp_processor_id();
  26. printk("%s(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n",str,
  27. lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3);
  28. }
  29. static inline void show_read(char *str, rwlock_t *lock, unsigned long caller)
  30. {
  31. int cpu = smp_processor_id();
  32. printk("%s(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)\n", str,
  33. lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3);
  34. }
  35. static inline void show_write(char *str, rwlock_t *lock, unsigned long caller)
  36. {
  37. int cpu = smp_processor_id();
  38. int i;
  39. printk("%s(%p) CPU#%d stuck at %08lx, owner PC(%08lx):CPU(%lx)", str,
  40. lock, cpu, caller, lock->owner_pc & ~3, lock->owner_pc & 3);
  41. for(i = 0; i < NR_CPUS; i++)
  42. printk(" reader[%d]=%08lx", i, lock->reader_pc[i]);
  43. printk("\n");
  44. }
  45. #undef INIT_STUCK
  46. #define INIT_STUCK 100000000
  47. void _do_spin_lock(spinlock_t *lock, char *str)
  48. {
  49. unsigned long caller;
  50. unsigned long val;
  51. int cpu = smp_processor_id();
  52. int stuck = INIT_STUCK;
  53. STORE_CALLER(caller);
  54. again:
  55. __asm__ __volatile__("ldstub [%1], %0" : "=r" (val) : "r" (&(lock->lock)));
  56. if(val) {
  57. while(lock->lock) {
  58. if (!--stuck) {
  59. show(str, lock, caller);
  60. stuck = INIT_STUCK;
  61. }
  62. barrier();
  63. }
  64. goto again;
  65. }
  66. lock->owner_pc = (cpu & 3) | (caller & ~3);
  67. }
  68. int _spin_trylock(spinlock_t *lock)
  69. {
  70. unsigned long val;
  71. unsigned long caller;
  72. int cpu = smp_processor_id();
  73. STORE_CALLER(caller);
  74. __asm__ __volatile__("ldstub [%1], %0" : "=r" (val) : "r" (&(lock->lock)));
  75. if(!val) {
  76. /* We got it, record our identity for debugging. */
  77. lock->owner_pc = (cpu & 3) | (caller & ~3);
  78. }
  79. return val == 0;
  80. }
  81. void _do_spin_unlock(spinlock_t *lock)
  82. {
  83. lock->owner_pc = 0;
  84. barrier();
  85. lock->lock = 0;
  86. }
  87. void _do_read_lock(rwlock_t *rw, char *str)
  88. {
  89. unsigned long caller;
  90. unsigned long val;
  91. int cpu = smp_processor_id();
  92. int stuck = INIT_STUCK;
  93. STORE_CALLER(caller);
  94. wlock_again:
  95. __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock)));
  96. if(val) {
  97. while(rw->lock & 0xff) {
  98. if (!--stuck) {
  99. show_read(str, rw, caller);
  100. stuck = INIT_STUCK;
  101. }
  102. barrier();
  103. }
  104. goto wlock_again;
  105. }
  106. rw->reader_pc[cpu] = caller;
  107. barrier();
  108. rw->lock++;
  109. }
  110. void _do_read_unlock(rwlock_t *rw, char *str)
  111. {
  112. unsigned long caller;
  113. unsigned long val;
  114. int cpu = smp_processor_id();
  115. int stuck = INIT_STUCK;
  116. STORE_CALLER(caller);
  117. wlock_again:
  118. __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock)));
  119. if(val) {
  120. while(rw->lock & 0xff) {
  121. if (!--stuck) {
  122. show_read(str, rw, caller);
  123. stuck = INIT_STUCK;
  124. }
  125. barrier();
  126. }
  127. goto wlock_again;
  128. }
  129. rw->reader_pc[cpu] = 0;
  130. barrier();
  131. rw->lock -= 0x1ff;
  132. }
  133. void _do_write_lock(rwlock_t *rw, char *str)
  134. {
  135. unsigned long caller;
  136. unsigned long val;
  137. int cpu = smp_processor_id();
  138. int stuck = INIT_STUCK;
  139. STORE_CALLER(caller);
  140. wlock_again:
  141. __asm__ __volatile__("ldstub [%1 + 3], %0" : "=r" (val) : "r" (&(rw->lock)));
  142. if(val) {
  143. wlock_wait:
  144. while(rw->lock) {
  145. if (!--stuck) {
  146. show_write(str, rw, caller);
  147. stuck = INIT_STUCK;
  148. }
  149. barrier();
  150. }
  151. goto wlock_again;
  152. }
  153. if (rw->lock & ~0xff) {
  154. *(((unsigned char *)&rw->lock)+3) = 0;
  155. barrier();
  156. goto wlock_wait;
  157. }
  158. barrier();
  159. rw->owner_pc = (cpu & 3) | (caller & ~3);
  160. }
  161. void _do_write_unlock(rwlock_t *rw)
  162. {
  163. rw->owner_pc = 0;
  164. barrier();
  165. rw->lock = 0;
  166. }
  167. #endif /* SMP */