1 #include <linux/wait.h>
2 #include <linux/ptrace.h>
5 #include <asm/unistd.h>
9 /* interrupt-level stop callback function. */
10 void spufs_stop_callback(struct spu *spu)
12 struct spu_context *ctx = spu->ctx;
14 wake_up_all(&ctx->stop_wq);
17 void spufs_dma_callback(struct spu *spu, int type)
19 struct spu_context *ctx = spu->ctx;
21 if (ctx->flags & SPU_CREATE_EVENTS_ENABLED) {
22 ctx->event_return |= type;
23 wake_up_all(&ctx->stop_wq);
26 case SPE_EVENT_DMA_ALIGNMENT:
27 case SPE_EVENT_INVALID_DMA:
28 force_sig(SIGBUS, /* info, */ current);
30 case SPE_EVENT_SPE_ERROR:
31 force_sig(SIGILL, /* info */ current);
37 static inline int spu_stopped(struct spu_context *ctx, u32 * stat)
42 *stat = ctx->ops->status_read(ctx);
43 if (ctx->state != SPU_STATE_RUNNABLE)
46 pte_fault = spu->dsisr &
47 (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED);
48 return (!(*stat & 0x1) || pte_fault || spu->class_0_pending) ? 1 : 0;
51 static inline int spu_run_init(struct spu_context *ctx, u32 * npc)
55 if ((ret = spu_acquire_runnable(ctx)) != 0)
57 ctx->ops->npc_write(ctx, *npc);
58 ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
62 static inline int spu_run_fini(struct spu_context *ctx, u32 * npc,
67 *status = ctx->ops->status_read(ctx);
68 *npc = ctx->ops->npc_read(ctx);
71 if (signal_pending(current))
73 if (unlikely(current->ptrace & PT_PTRACED)) {
74 if ((*status & SPU_STATUS_STOPPED_BY_STOP)
75 && (*status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) {
76 force_sig(SIGTRAP, current);
83 static inline int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc,
88 if ((ret = spu_run_fini(ctx, npc, status)) != 0)
90 if (*status & (SPU_STATUS_STOPPED_BY_STOP |
91 SPU_STATUS_STOPPED_BY_HALT)) {
94 if ((ret = spu_run_init(ctx, npc)) != 0)
100 * SPU syscall restarting is tricky because we violate the basic
101 * assumption that the signal handler is running on the interrupted
102 * thread. Here instead, the handler runs on PowerPC user space code,
103 * while the syscall was called from the SPU.
104 * This means we can only do a very rough approximation of POSIX
107 int spu_handle_restartsys(struct spu_context *ctx, long *spu_ret,
114 case -ERESTARTNOINTR:
116 * Enter the regular syscall restarting for
117 * sys_spu_run, then restart the SPU syscall
123 case -ERESTARTNOHAND:
124 case -ERESTART_RESTARTBLOCK:
126 * Restart block is too hard for now, just return -EINTR
128 * ERESTARTNOHAND comes from sys_pause, we also return
130 * Assume that we need to be restarted ourselves though.
136 printk(KERN_WARNING "%s: unexpected return code %ld\n",
137 __FUNCTION__, *spu_ret);
143 int spu_process_callback(struct spu_context *ctx)
145 struct spu_syscall_block s;
151 /* get syscall block from local store */
152 npc = ctx->ops->npc_read(ctx);
153 ls = ctx->ops->get_ls(ctx);
154 ls_pointer = *(u32*)(ls + npc);
155 if (ls_pointer > (LS_SIZE - sizeof(s)))
157 memcpy(&s, ls + ls_pointer, sizeof (s));
159 /* do actual syscall without pinning the spu */
164 if (s.nr_ret < __NR_syscalls) {
166 /* do actual system call from here */
167 spu_ret = spu_sys_callback(&s);
168 if (spu_ret <= -ERESTARTSYS) {
169 ret = spu_handle_restartsys(ctx, &spu_ret, &npc);
172 if (ret == -ERESTARTSYS)
176 /* write result, jump over indirect pointer */
177 memcpy(ls + ls_pointer, &spu_ret, sizeof (spu_ret));
178 ctx->ops->npc_write(ctx, npc);
179 ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
183 static inline int spu_process_events(struct spu_context *ctx)
185 struct spu *spu = ctx->spu;
186 u64 pte_fault = MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED;
189 if (spu->dsisr & pte_fault)
190 ret = spu_irq_class_1_bottom(spu);
191 if (spu->class_0_pending)
192 ret = spu_irq_class_0_bottom(spu);
193 if (!ret && signal_pending(current))
198 long spufs_run_spu(struct file *file, struct spu_context *ctx,
199 u32 *npc, u32 *event)
204 if (down_interruptible(&ctx->run_sema))
207 ctx->event_return = 0;
208 ret = spu_run_init(ctx, npc);
213 ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, &status));
216 if ((status & SPU_STATUS_STOPPED_BY_STOP) &&
217 (status >> SPU_STOP_STATUS_SHIFT == 0x2104)) {
218 ret = spu_process_callback(ctx);
221 status &= ~SPU_STATUS_STOPPED_BY_STOP;
223 if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) {
224 ret = spu_reacquire_runnable(ctx, npc, &status);
229 ret = spu_process_events(ctx);
231 } while (!ret && !(status & (SPU_STATUS_STOPPED_BY_STOP |
232 SPU_STATUS_STOPPED_BY_HALT)));
234 ctx->ops->runcntl_stop(ctx);
235 ret = spu_run_fini(ctx, npc, &status);
241 *event = ctx->event_return;