linux/arch/powerpc/platforms/cell/spufs/run.c
Arnd Bergmann ce8ab85412 [PATCH] spufs: move spu_run call to its own file
The logic for sys_spu_run keeps growing and it does
not really belong into file.c any more since we
moved away from using regular file operations to our
own syscall.

No functional change in here.

Signed-off-by: Arnd Bergmann <arndb@de.ibm.com>
Signed-off-by: Paul Mackerras <paulus@samba.org>
2006-01-09 15:44:45 +11:00

131 lines
2.8 KiB
C

#include <linux/wait.h>
#include <linux/ptrace.h>
#include <asm/spu.h>
#include "spufs.h"
/* interrupt-level stop callback function. */
void spufs_stop_callback(struct spu *spu)
{
struct spu_context *ctx = spu->ctx;
wake_up_all(&ctx->stop_wq);
}
static inline int spu_stopped(struct spu_context *ctx, u32 * stat)
{
struct spu *spu;
u64 pte_fault;
*stat = ctx->ops->status_read(ctx);
if (ctx->state != SPU_STATE_RUNNABLE)
return 1;
spu = ctx->spu;
pte_fault = spu->dsisr &
(MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED);
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)
{
int ret;
if ((ret = spu_acquire_runnable(ctx)) != 0)
return ret;
ctx->ops->npc_write(ctx, *npc);
ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE);
return 0;
}
static inline int spu_run_fini(struct spu_context *ctx, u32 * npc,
u32 * status)
{
int ret = 0;
*status = ctx->ops->status_read(ctx);
*npc = ctx->ops->npc_read(ctx);
spu_release(ctx);
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;
}
static inline int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc,
u32 *status)
{
int ret;
if ((ret = spu_run_fini(ctx, npc, status)) != 0)
return ret;
if (*status & (SPU_STATUS_STOPPED_BY_STOP |
SPU_STATUS_STOPPED_BY_HALT)) {
return *status;
}
if ((ret = spu_run_init(ctx, npc, status)) != 0)
return ret;
return 0;
}
static inline int spu_process_events(struct spu_context *ctx)
{
struct spu *spu = ctx->spu;
u64 pte_fault = MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED;
int ret = 0;
if (spu->dsisr & pte_fault)
ret = spu_irq_class_1_bottom(spu);
if (spu->class_0_pending)
ret = spu_irq_class_0_bottom(spu);
if (!ret && signal_pending(current))
ret = -ERESTARTSYS;
return ret;
}
long spufs_run_spu(struct file *file, struct spu_context *ctx,
u32 * npc, u32 * status)
{
int ret;
if (down_interruptible(&ctx->run_sema))
return -ERESTARTSYS;
ret = spu_run_init(ctx, npc, status);
if (ret)
goto out;
do {
ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, status));
if (unlikely(ret))
break;
if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) {
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 |
SPU_STATUS_STOPPED_BY_HALT)));
ctx->ops->runcntl_stop(ctx);
ret = spu_run_fini(ctx, npc, status);
if (!ret)
ret = *status;
spu_yield(ctx);
out:
up(&ctx->run_sema);
return ret;
}