aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorMasato Noguchi <Masato.Noguchi@jp.sony.com>2006-11-20 18:45:04 +0100
committerPaul Mackerras <paulus@samba.org>2006-12-04 20:39:55 +1100
commit2ebb2477f9a61b436dd22b75189857df1a77e585 (patch)
treed0f9fbfd2f63c83adcf71ab316096d25c5f50433 /arch
parent[POWERPC] spufs: Return correct event for data storage interrupt (diff)
downloadlinux-dev-2ebb2477f9a61b436dd22b75189857df1a77e585.tar.xz
linux-dev-2ebb2477f9a61b436dd22b75189857df1a77e585.zip
[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 <Masato.Noguchi@jp.sony.com> Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/platforms/cell/spufs/run.c28
1 files changed, 18 insertions, 10 deletions
diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c
index 88a41d83a79b..c88fd7f9ea74 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);