run.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. #include <linux/wait.h>
  2. #include <linux/ptrace.h>
  3. #include <asm/spu.h>
  4. #include "spufs.h"
  5. /* interrupt-level stop callback function. */
  6. void spufs_stop_callback(struct spu *spu)
  7. {
  8. struct spu_context *ctx = spu->ctx;
  9. wake_up_all(&ctx->stop_wq);
  10. }
  11. static inline int spu_stopped(struct spu_context *ctx, u32 * stat)
  12. {
  13. struct spu *spu;
  14. u64 pte_fault;
  15. *stat = ctx->ops->status_read(ctx);
  16. if (ctx->state != SPU_STATE_RUNNABLE)
  17. return 1;
  18. spu = ctx->spu;
  19. pte_fault = spu->dsisr &
  20. (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED);
  21. return (!(*stat & 0x1) || pte_fault || spu->class_0_pending) ? 1 : 0;
  22. }
  23. static inline int spu_run_init(struct spu_context *ctx, u32 * npc,
  24. u32 * status)
  25. {
  26. int ret;
  27. if ((ret = spu_acquire_runnable(ctx)) != 0)
  28. return ret;
  29. ctx->ops->npc_write(ctx, *npc);
  30. ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
  31. return 0;
  32. }
  33. static inline int spu_run_fini(struct spu_context *ctx, u32 * npc,
  34. u32 * status)
  35. {
  36. int ret = 0;
  37. *status = ctx->ops->status_read(ctx);
  38. *npc = ctx->ops->npc_read(ctx);
  39. spu_release(ctx);
  40. if (signal_pending(current))
  41. ret = -ERESTARTSYS;
  42. if (unlikely(current->ptrace & PT_PTRACED)) {
  43. if ((*status & SPU_STATUS_STOPPED_BY_STOP)
  44. && (*status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) {
  45. force_sig(SIGTRAP, current);
  46. ret = -ERESTARTSYS;
  47. }
  48. }
  49. return ret;
  50. }
  51. static inline int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc,
  52. u32 *status)
  53. {
  54. int ret;
  55. if ((ret = spu_run_fini(ctx, npc, status)) != 0)
  56. return ret;
  57. if (*status & (SPU_STATUS_STOPPED_BY_STOP |
  58. SPU_STATUS_STOPPED_BY_HALT)) {
  59. return *status;
  60. }
  61. if ((ret = spu_run_init(ctx, npc, status)) != 0)
  62. return ret;
  63. return 0;
  64. }
  65. /*
  66. * SPU syscall restarting is tricky because we violate the basic
  67. * assumption that the signal handler is running on the interrupted
  68. * thread. Here instead, the handler runs on PowerPC user space code,
  69. * while the syscall was called from the SPU.
  70. * This means we can only do a very rough approximation of POSIX
  71. * signal semantics.
  72. */
  73. int spu_handle_restartsys(struct spu_context *ctx, long *spu_ret,
  74. unsigned int *npc)
  75. {
  76. int ret;
  77. switch (*spu_ret) {
  78. case -ERESTARTSYS:
  79. case -ERESTARTNOINTR:
  80. /*
  81. * Enter the regular syscall restarting for
  82. * sys_spu_run, then restart the SPU syscall
  83. * callback.
  84. */
  85. *npc -= 8;
  86. ret = -ERESTARTSYS;
  87. break;
  88. case -ERESTARTNOHAND:
  89. case -ERESTART_RESTARTBLOCK:
  90. /*
  91. * Restart block is too hard for now, just return -EINTR
  92. * to the SPU.
  93. * ERESTARTNOHAND comes from sys_pause, we also return
  94. * -EINTR from there.
  95. * Assume that we need to be restarted ourselves though.
  96. */
  97. *spu_ret = -EINTR;
  98. ret = -ERESTARTSYS;
  99. break;
  100. default:
  101. printk(KERN_WARNING "%s: unexpected return code %ld\n",
  102. __FUNCTION__, *spu_ret);
  103. ret = 0;
  104. }
  105. return ret;
  106. }
  107. int spu_process_callback(struct spu_context *ctx)
  108. {
  109. struct spu_syscall_block s;
  110. u32 ls_pointer, npc;
  111. char *ls;
  112. long spu_ret;
  113. int ret;
  114. /* get syscall block from local store */
  115. npc = ctx->ops->npc_read(ctx);
  116. ls = ctx->ops->get_ls(ctx);
  117. ls_pointer = *(u32*)(ls + npc);
  118. if (ls_pointer > (LS_SIZE - sizeof(s)))
  119. return -EFAULT;
  120. memcpy(&s, ls + ls_pointer, sizeof (s));
  121. /* do actual syscall without pinning the spu */
  122. ret = 0;
  123. spu_ret = -ENOSYS;
  124. npc += 4;
  125. if (s.nr_ret < __NR_syscalls) {
  126. spu_release(ctx);
  127. /* do actual system call from here */
  128. spu_ret = spu_sys_callback(&s);
  129. if (spu_ret <= -ERESTARTSYS) {
  130. ret = spu_handle_restartsys(ctx, &spu_ret, &npc);
  131. }
  132. spu_acquire(ctx);
  133. if (ret == -ERESTARTSYS)
  134. return ret;
  135. }
  136. /* write result, jump over indirect pointer */
  137. memcpy(ls + ls_pointer, &spu_ret, sizeof (spu_ret));
  138. ctx->ops->npc_write(ctx, npc);
  139. ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
  140. return ret;
  141. }
  142. static inline int spu_process_events(struct spu_context *ctx)
  143. {
  144. struct spu *spu = ctx->spu;
  145. u64 pte_fault = MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED;
  146. int ret = 0;
  147. if (spu->dsisr & pte_fault)
  148. ret = spu_irq_class_1_bottom(spu);
  149. if (spu->class_0_pending)
  150. ret = spu_irq_class_0_bottom(spu);
  151. if (!ret && signal_pending(current))
  152. ret = -ERESTARTSYS;
  153. return ret;
  154. }
  155. long spufs_run_spu(struct file *file, struct spu_context *ctx,
  156. u32 * npc, u32 * status)
  157. {
  158. int ret;
  159. if (down_interruptible(&ctx->run_sema))
  160. return -ERESTARTSYS;
  161. ret = spu_run_init(ctx, npc, status);
  162. if (ret)
  163. goto out;
  164. do {
  165. ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, status));
  166. if (unlikely(ret))
  167. break;
  168. if ((*status & SPU_STATUS_STOPPED_BY_STOP) &&
  169. (*status >> SPU_STOP_STATUS_SHIFT == 0x2104)) {
  170. ret = spu_process_callback(ctx);
  171. if (ret)
  172. break;
  173. *status &= ~SPU_STATUS_STOPPED_BY_STOP;
  174. }
  175. if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) {
  176. ret = spu_reacquire_runnable(ctx, npc, status);
  177. if (ret)
  178. goto out;
  179. continue;
  180. }
  181. ret = spu_process_events(ctx);
  182. } while (!ret && !(*status & (SPU_STATUS_STOPPED_BY_STOP |
  183. SPU_STATUS_STOPPED_BY_HALT)));
  184. ctx->ops->runcntl_stop(ctx);
  185. ret = spu_run_fini(ctx, npc, status);
  186. if (!ret)
  187. ret = *status;
  188. spu_yield(ctx);
  189. out:
  190. up(&ctx->run_sema);
  191. return ret;
  192. }