semaphore.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. /* $Id: semaphore.c,v 1.9 2001/11/18 00:12:56 davem Exp $
  2. * semaphore.c: Sparc64 semaphore implementation.
  3. *
  4. * This is basically the PPC semaphore scheme ported to use
  5. * the sparc64 atomic instructions, so see the PPC code for
  6. * credits.
  7. */
  8. #include <linux/sched.h>
  9. #include <linux/errno.h>
  10. #include <linux/init.h>
  11. /*
  12. * Atomically update sem->count.
  13. * This does the equivalent of the following:
  14. *
  15. * old_count = sem->count;
  16. * tmp = MAX(old_count, 0) + incr;
  17. * sem->count = tmp;
  18. * return old_count;
  19. */
  20. static __inline__ int __sem_update_count(struct semaphore *sem, int incr)
  21. {
  22. int old_count, tmp;
  23. __asm__ __volatile__("\n"
  24. " ! __sem_update_count old_count(%0) tmp(%1) incr(%4) &sem->count(%3)\n"
  25. "1: ldsw [%3], %0\n"
  26. " mov %0, %1\n"
  27. " cmp %0, 0\n"
  28. " movl %%icc, 0, %1\n"
  29. " add %1, %4, %1\n"
  30. " cas [%3], %0, %1\n"
  31. " cmp %0, %1\n"
  32. " membar #StoreLoad | #StoreStore\n"
  33. " bne,pn %%icc, 1b\n"
  34. " nop\n"
  35. : "=&r" (old_count), "=&r" (tmp), "=m" (sem->count)
  36. : "r" (&sem->count), "r" (incr), "m" (sem->count)
  37. : "cc");
  38. return old_count;
  39. }
  40. static void __up(struct semaphore *sem)
  41. {
  42. __sem_update_count(sem, 1);
  43. wake_up(&sem->wait);
  44. }
  45. void up(struct semaphore *sem)
  46. {
  47. /* This atomically does:
  48. * old_val = sem->count;
  49. * new_val = sem->count + 1;
  50. * sem->count = new_val;
  51. * if (old_val < 0)
  52. * __up(sem);
  53. *
  54. * The (old_val < 0) test is equivalent to
  55. * the more straightforward (new_val <= 0),
  56. * but it is easier to test the former because
  57. * of how the CAS instruction works.
  58. */
  59. __asm__ __volatile__("\n"
  60. " ! up sem(%0)\n"
  61. " membar #StoreLoad | #LoadLoad\n"
  62. "1: lduw [%0], %%g1\n"
  63. " add %%g1, 1, %%g7\n"
  64. " cas [%0], %%g1, %%g7\n"
  65. " cmp %%g1, %%g7\n"
  66. " bne,pn %%icc, 1b\n"
  67. " addcc %%g7, 1, %%g0\n"
  68. " membar #StoreLoad | #StoreStore\n"
  69. " ble,pn %%icc, 3f\n"
  70. " nop\n"
  71. "2:\n"
  72. " .subsection 2\n"
  73. "3: mov %0, %%g1\n"
  74. " save %%sp, -160, %%sp\n"
  75. " call %1\n"
  76. " mov %%g1, %%o0\n"
  77. " ba,pt %%xcc, 2b\n"
  78. " restore\n"
  79. " .previous\n"
  80. : : "r" (sem), "i" (__up)
  81. : "g1", "g2", "g3", "g7", "memory", "cc");
  82. }
  83. static void __sched __down(struct semaphore * sem)
  84. {
  85. struct task_struct *tsk = current;
  86. DECLARE_WAITQUEUE(wait, tsk);
  87. tsk->state = TASK_UNINTERRUPTIBLE;
  88. add_wait_queue_exclusive(&sem->wait, &wait);
  89. while (__sem_update_count(sem, -1) <= 0) {
  90. schedule();
  91. tsk->state = TASK_UNINTERRUPTIBLE;
  92. }
  93. remove_wait_queue(&sem->wait, &wait);
  94. tsk->state = TASK_RUNNING;
  95. wake_up(&sem->wait);
  96. }
  97. void __sched down(struct semaphore *sem)
  98. {
  99. might_sleep();
  100. /* This atomically does:
  101. * old_val = sem->count;
  102. * new_val = sem->count - 1;
  103. * sem->count = new_val;
  104. * if (old_val < 1)
  105. * __down(sem);
  106. *
  107. * The (old_val < 1) test is equivalent to
  108. * the more straightforward (new_val < 0),
  109. * but it is easier to test the former because
  110. * of how the CAS instruction works.
  111. */
  112. __asm__ __volatile__("\n"
  113. " ! down sem(%0)\n"
  114. "1: lduw [%0], %%g1\n"
  115. " sub %%g1, 1, %%g7\n"
  116. " cas [%0], %%g1, %%g7\n"
  117. " cmp %%g1, %%g7\n"
  118. " bne,pn %%icc, 1b\n"
  119. " cmp %%g7, 1\n"
  120. " membar #StoreLoad | #StoreStore\n"
  121. " bl,pn %%icc, 3f\n"
  122. " nop\n"
  123. "2:\n"
  124. " .subsection 2\n"
  125. "3: mov %0, %%g1\n"
  126. " save %%sp, -160, %%sp\n"
  127. " call %1\n"
  128. " mov %%g1, %%o0\n"
  129. " ba,pt %%xcc, 2b\n"
  130. " restore\n"
  131. " .previous\n"
  132. : : "r" (sem), "i" (__down)
  133. : "g1", "g2", "g3", "g7", "memory", "cc");
  134. }
  135. int down_trylock(struct semaphore *sem)
  136. {
  137. int ret;
  138. /* This atomically does:
  139. * old_val = sem->count;
  140. * new_val = sem->count - 1;
  141. * if (old_val < 1) {
  142. * ret = 1;
  143. * } else {
  144. * sem->count = new_val;
  145. * ret = 0;
  146. * }
  147. *
  148. * The (old_val < 1) test is equivalent to
  149. * the more straightforward (new_val < 0),
  150. * but it is easier to test the former because
  151. * of how the CAS instruction works.
  152. */
  153. __asm__ __volatile__("\n"
  154. " ! down_trylock sem(%1) ret(%0)\n"
  155. "1: lduw [%1], %%g1\n"
  156. " sub %%g1, 1, %%g7\n"
  157. " cmp %%g1, 1\n"
  158. " bl,pn %%icc, 2f\n"
  159. " mov 1, %0\n"
  160. " cas [%1], %%g1, %%g7\n"
  161. " cmp %%g1, %%g7\n"
  162. " bne,pn %%icc, 1b\n"
  163. " mov 0, %0\n"
  164. " membar #StoreLoad | #StoreStore\n"
  165. "2:\n"
  166. : "=&r" (ret)
  167. : "r" (sem)
  168. : "g1", "g7", "memory", "cc");
  169. return ret;
  170. }
  171. static int __sched __down_interruptible(struct semaphore * sem)
  172. {
  173. int retval = 0;
  174. struct task_struct *tsk = current;
  175. DECLARE_WAITQUEUE(wait, tsk);
  176. tsk->state = TASK_INTERRUPTIBLE;
  177. add_wait_queue_exclusive(&sem->wait, &wait);
  178. while (__sem_update_count(sem, -1) <= 0) {
  179. if (signal_pending(current)) {
  180. __sem_update_count(sem, 0);
  181. retval = -EINTR;
  182. break;
  183. }
  184. schedule();
  185. tsk->state = TASK_INTERRUPTIBLE;
  186. }
  187. tsk->state = TASK_RUNNING;
  188. remove_wait_queue(&sem->wait, &wait);
  189. wake_up(&sem->wait);
  190. return retval;
  191. }
  192. int __sched down_interruptible(struct semaphore *sem)
  193. {
  194. int ret = 0;
  195. might_sleep();
  196. /* This atomically does:
  197. * old_val = sem->count;
  198. * new_val = sem->count - 1;
  199. * sem->count = new_val;
  200. * if (old_val < 1)
  201. * ret = __down_interruptible(sem);
  202. *
  203. * The (old_val < 1) test is equivalent to
  204. * the more straightforward (new_val < 0),
  205. * but it is easier to test the former because
  206. * of how the CAS instruction works.
  207. */
  208. __asm__ __volatile__("\n"
  209. " ! down_interruptible sem(%2) ret(%0)\n"
  210. "1: lduw [%2], %%g1\n"
  211. " sub %%g1, 1, %%g7\n"
  212. " cas [%2], %%g1, %%g7\n"
  213. " cmp %%g1, %%g7\n"
  214. " bne,pn %%icc, 1b\n"
  215. " cmp %%g7, 1\n"
  216. " membar #StoreLoad | #StoreStore\n"
  217. " bl,pn %%icc, 3f\n"
  218. " nop\n"
  219. "2:\n"
  220. " .subsection 2\n"
  221. "3: mov %2, %%g1\n"
  222. " save %%sp, -160, %%sp\n"
  223. " call %3\n"
  224. " mov %%g1, %%o0\n"
  225. " ba,pt %%xcc, 2b\n"
  226. " restore\n"
  227. " .previous\n"
  228. : "=r" (ret)
  229. : "0" (ret), "r" (sem), "i" (__down_interruptible)
  230. : "g1", "g2", "g3", "g7", "memory", "cc");
  231. return ret;
  232. }