aboutsummaryrefslogtreecommitdiff
path: root/arch/powerpc/platforms/cell/spufs/run.c
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2006-10-04 17:26:14 +0200
committerPaul Mackerras <paulus@samba.org>2006-10-05 09:21:01 +1000
commit9add11daeee2f6d69f6b86237f197824332a4a3b (patch)
tree526daebd5cac297c288503fe4dafecd02c0f492e /arch/powerpc/platforms/cell/spufs/run.c
parent28347bce8a837258e737873a55d31f2f424a6ea6 (diff)
[POWERPC] spufs: implement error event delivery to user space
This tries to fix spufs so we have an interface closer to what is specified in the man page for events returned in the third argument of spu_run. Fortunately, libspe has never been using the returned contents of that register, as they were the same as the return code of spu_run (duh!). Unlike the specification that we never implemented correctly, we now require a SPU_CREATE_EVENTS_ENABLED flag passed to spu_create, in order to get the new behavior. When this flag is not passed, spu_run will simply ignore the third argument now. Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/platforms/cell/spufs/run.c')
-rw-r--r--arch/powerpc/platforms/cell/spufs/run.c48
1 files changed, 35 insertions, 13 deletions
diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c
index 483c8b76232..63df8cf4ba1 100644
--- a/arch/powerpc/platforms/cell/spufs/run.c
+++ b/arch/powerpc/platforms/cell/spufs/run.c
@@ -14,6 +14,26 @@ void spufs_stop_callback(struct spu *spu)
wake_up_all(&ctx->stop_wq);
}
+void spufs_dma_callback(struct spu *spu, int type)
+{
+ struct spu_context *ctx = spu->ctx;
+
+ if (ctx->flags & SPU_CREATE_EVENTS_ENABLED) {
+ ctx->event_return |= type;
+ wake_up_all(&ctx->stop_wq);
+ } else {
+ switch (type) {
+ case SPE_EVENT_DMA_ALIGNMENT:
+ case SPE_EVENT_INVALID_DMA:
+ force_sig(SIGBUS, /* info, */ current);
+ break;
+ case SPE_EVENT_SPE_ERROR:
+ force_sig(SIGILL, /* info */ current);
+ break;
+ }
+ }
+}
+
static inline int spu_stopped(struct spu_context *ctx, u32 * stat)
{
struct spu *spu;
@@ -28,8 +48,7 @@ static inline int spu_stopped(struct spu_context *ctx, u32 * stat)
return (!(*stat & 0x1) || pte_fault || spu->class_0_pending) ? 1 : 0;
}
-static inline int spu_run_init(struct spu_context *ctx, u32 * npc,
- u32 * status)
+static inline int spu_run_init(struct spu_context *ctx, u32 * npc)
{
int ret;
@@ -72,7 +91,7 @@ static inline int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc,
SPU_STATUS_STOPPED_BY_HALT)) {
return *status;
}
- if ((ret = spu_run_init(ctx, npc, status)) != 0)
+ if ((ret = spu_run_init(ctx, npc)) != 0)
return ret;
return 0;
}
@@ -177,46 +196,49 @@ static inline int spu_process_events(struct spu_context *ctx)
}
long spufs_run_spu(struct file *file, struct spu_context *ctx,
- u32 * npc, u32 * status)
+ u32 *npc, u32 *event)
{
int ret;
+ u32 status;
if (down_interruptible(&ctx->run_sema))
return -ERESTARTSYS;
- ret = spu_run_init(ctx, npc, status);
+ ctx->event_return = 0;
+ ret = spu_run_init(ctx, npc);
if (ret)
goto out;
do {
- ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, status));
+ ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, &status));
if (unlikely(ret))
break;
- if ((*status & SPU_STATUS_STOPPED_BY_STOP) &&
- (*status >> SPU_STOP_STATUS_SHIFT == 0x2104)) {
+ if ((status & SPU_STATUS_STOPPED_BY_STOP) &&
+ (status >> SPU_STOP_STATUS_SHIFT == 0x2104)) {
ret = spu_process_callback(ctx);
if (ret)
break;
- *status &= ~SPU_STATUS_STOPPED_BY_STOP;
+ status &= ~SPU_STATUS_STOPPED_BY_STOP;
}
if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) {
- ret = spu_reacquire_runnable(ctx, npc, status);
+ ret = spu_reacquire_runnable(ctx, npc, &status);
if (ret)
goto out;
continue;
}
ret = spu_process_events(ctx);
- } while (!ret && !(*status & (SPU_STATUS_STOPPED_BY_STOP |
+ } while (!ret && !(status & (SPU_STATUS_STOPPED_BY_STOP |
SPU_STATUS_STOPPED_BY_HALT)));
ctx->ops->runcntl_stop(ctx);
- ret = spu_run_fini(ctx, npc, status);
+ ret = spu_run_fini(ctx, npc, &status);
if (!ret)
- ret = *status;
+ ret = status;
spu_yield(ctx);
out:
+ *event = ctx->event_return;
up(&ctx->run_sema);
return ret;
}