From 2ebb2477f9a61b436dd22b75189857df1a77e585 Mon Sep 17 00:00:00 2001 From: Masato Noguchi Date: Mon, 20 Nov 2006 18:45:04 +0100 Subject: [POWERPC] spufs: Fix missing stop-and-signal When there is pending signals, current spufs_run_spu() always returns -ERESTARTSYS and it is called again automatically. But, if spe already stopped by stop-and-signal or halt instruction, returning -ERESTARTSYS makes stop-and-signal/halt lost and spu run over the end-point. For your convenience, I attached a sample code to restage this bug. If there is no bug, printed NPC will be 0x4000. Signed-off-by: Masato Noguchi Signed-off-by: Arnd Bergmann Signed-off-by: Paul Mackerras --- arch/powerpc/platforms/cell/spufs/run.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) (limited to 'arch') diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c index 88a41d83a79..c88fd7f9ea7 100644 --- a/arch/powerpc/platforms/cell/spufs/run.c +++ b/arch/powerpc/platforms/cell/spufs/run.c @@ -79,13 +79,7 @@ static inline int spu_run_fini(struct spu_context *ctx, u32 * npc, if (signal_pending(current)) ret = -ERESTARTSYS; - if (unlikely(current->ptrace & PT_PTRACED)) { - if ((*status & SPU_STATUS_STOPPED_BY_STOP) - && (*status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) { - force_sig(SIGTRAP, current); - ret = -ERESTARTSYS; - } - } + return ret; } @@ -232,7 +226,7 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx, if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) { ret = spu_reacquire_runnable(ctx, npc, &status); if (ret) - goto out; + goto out2; continue; } ret = spu_process_events(ctx); @@ -242,10 +236,24 @@ long spufs_run_spu(struct file *file, struct spu_context *ctx, ctx->ops->runcntl_stop(ctx); ret = spu_run_fini(ctx, npc, &status); - if (!ret) - ret = status; spu_yield(ctx); +out2: + if ((ret == 0) || + ((ret == -ERESTARTSYS) && + ((status & SPU_STATUS_STOPPED_BY_HALT) || + ((status & SPU_STATUS_STOPPED_BY_STOP) && + (status >> SPU_STOP_STATUS_SHIFT != 0x2104))))) + ret = status; + + if (unlikely(current->ptrace & PT_PTRACED)) { + if ((status & SPU_STATUS_STOPPED_BY_STOP) + && (status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) { + force_sig(SIGTRAP, current); + ret = -ERESTARTSYS; + } + } + out: *event = ctx->event_return; up(&ctx->run_sema); -- cgit v1.2.3