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
;