1ce8ab854SArnd Bergmann #include <linux/wait.h> 2ce8ab854SArnd Bergmann #include <linux/ptrace.h> 3ce8ab854SArnd Bergmann 4ce8ab854SArnd Bergmann #include <asm/spu.h> 5ce8ab854SArnd Bergmann 6ce8ab854SArnd Bergmann #include "spufs.h" 7ce8ab854SArnd Bergmann 8ce8ab854SArnd Bergmann /* interrupt-level stop callback function. */ 9ce8ab854SArnd Bergmann void spufs_stop_callback(struct spu *spu) 10ce8ab854SArnd Bergmann { 11ce8ab854SArnd Bergmann struct spu_context *ctx = spu->ctx; 12ce8ab854SArnd Bergmann 13ce8ab854SArnd Bergmann wake_up_all(&ctx->stop_wq); 14ce8ab854SArnd Bergmann } 15ce8ab854SArnd Bergmann 16ce8ab854SArnd Bergmann static inline int spu_stopped(struct spu_context *ctx, u32 * stat) 17ce8ab854SArnd Bergmann { 18ce8ab854SArnd Bergmann struct spu *spu; 19ce8ab854SArnd Bergmann u64 pte_fault; 20ce8ab854SArnd Bergmann 21ce8ab854SArnd Bergmann *stat = ctx->ops->status_read(ctx); 22ce8ab854SArnd Bergmann if (ctx->state != SPU_STATE_RUNNABLE) 23ce8ab854SArnd Bergmann return 1; 24ce8ab854SArnd Bergmann spu = ctx->spu; 25ce8ab854SArnd Bergmann pte_fault = spu->dsisr & 26ce8ab854SArnd Bergmann (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED); 27ce8ab854SArnd Bergmann return (!(*stat & 0x1) || pte_fault || spu->class_0_pending) ? 1 : 0; 28ce8ab854SArnd Bergmann } 29ce8ab854SArnd Bergmann 30ce8ab854SArnd Bergmann static inline int spu_run_init(struct spu_context *ctx, u32 * npc, 31ce8ab854SArnd Bergmann u32 * status) 32ce8ab854SArnd Bergmann { 33ce8ab854SArnd Bergmann int ret; 34ce8ab854SArnd Bergmann 35ce8ab854SArnd Bergmann if ((ret = spu_acquire_runnable(ctx)) != 0) 36ce8ab854SArnd Bergmann return ret; 37ce8ab854SArnd Bergmann ctx->ops->npc_write(ctx, *npc); 38ce8ab854SArnd Bergmann ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE); 39ce8ab854SArnd Bergmann return 0; 40ce8ab854SArnd Bergmann } 41ce8ab854SArnd Bergmann 42ce8ab854SArnd Bergmann static inline int spu_run_fini(struct spu_context *ctx, u32 * npc, 43ce8ab854SArnd Bergmann u32 * status) 44ce8ab854SArnd Bergmann { 45ce8ab854SArnd Bergmann int ret = 0; 46ce8ab854SArnd Bergmann 47ce8ab854SArnd Bergmann *status = ctx->ops->status_read(ctx); 48ce8ab854SArnd Bergmann *npc = ctx->ops->npc_read(ctx); 49ce8ab854SArnd Bergmann spu_release(ctx); 50ce8ab854SArnd Bergmann 51ce8ab854SArnd Bergmann if (signal_pending(current)) 52ce8ab854SArnd Bergmann ret = -ERESTARTSYS; 53ce8ab854SArnd Bergmann if (unlikely(current->ptrace & PT_PTRACED)) { 54ce8ab854SArnd Bergmann if ((*status & SPU_STATUS_STOPPED_BY_STOP) 55ce8ab854SArnd Bergmann && (*status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) { 56ce8ab854SArnd Bergmann force_sig(SIGTRAP, current); 57ce8ab854SArnd Bergmann ret = -ERESTARTSYS; 58ce8ab854SArnd Bergmann } 59ce8ab854SArnd Bergmann } 60ce8ab854SArnd Bergmann return ret; 61ce8ab854SArnd Bergmann } 62ce8ab854SArnd Bergmann 63ce8ab854SArnd Bergmann static inline int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc, 64ce8ab854SArnd Bergmann u32 *status) 65ce8ab854SArnd Bergmann { 66ce8ab854SArnd Bergmann int ret; 67ce8ab854SArnd Bergmann 68ce8ab854SArnd Bergmann if ((ret = spu_run_fini(ctx, npc, status)) != 0) 69ce8ab854SArnd Bergmann return ret; 70ce8ab854SArnd Bergmann if (*status & (SPU_STATUS_STOPPED_BY_STOP | 71ce8ab854SArnd Bergmann SPU_STATUS_STOPPED_BY_HALT)) { 72ce8ab854SArnd Bergmann return *status; 73ce8ab854SArnd Bergmann } 74ce8ab854SArnd Bergmann if ((ret = spu_run_init(ctx, npc, status)) != 0) 75ce8ab854SArnd Bergmann return ret; 76ce8ab854SArnd Bergmann return 0; 77ce8ab854SArnd Bergmann } 78ce8ab854SArnd Bergmann 79ce8ab854SArnd Bergmann static inline int spu_process_events(struct spu_context *ctx) 80ce8ab854SArnd Bergmann { 81ce8ab854SArnd Bergmann struct spu *spu = ctx->spu; 82ce8ab854SArnd Bergmann u64 pte_fault = MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED; 83ce8ab854SArnd Bergmann int ret = 0; 84ce8ab854SArnd Bergmann 85ce8ab854SArnd Bergmann if (spu->dsisr & pte_fault) 86ce8ab854SArnd Bergmann ret = spu_irq_class_1_bottom(spu); 87ce8ab854SArnd Bergmann if (spu->class_0_pending) 88ce8ab854SArnd Bergmann ret = spu_irq_class_0_bottom(spu); 89ce8ab854SArnd Bergmann if (!ret && signal_pending(current)) 90ce8ab854SArnd Bergmann ret = -ERESTARTSYS; 91ce8ab854SArnd Bergmann return ret; 92ce8ab854SArnd Bergmann } 93ce8ab854SArnd Bergmann 94ce8ab854SArnd Bergmann long spufs_run_spu(struct file *file, struct spu_context *ctx, 95ce8ab854SArnd Bergmann u32 * npc, u32 * status) 96ce8ab854SArnd Bergmann { 97ce8ab854SArnd Bergmann int ret; 98ce8ab854SArnd Bergmann 99ce8ab854SArnd Bergmann if (down_interruptible(&ctx->run_sema)) 100ce8ab854SArnd Bergmann return -ERESTARTSYS; 101ce8ab854SArnd Bergmann 102ce8ab854SArnd Bergmann ret = spu_run_init(ctx, npc, status); 103ce8ab854SArnd Bergmann if (ret) 104ce8ab854SArnd Bergmann goto out; 105ce8ab854SArnd Bergmann 106ce8ab854SArnd Bergmann do { 107ce8ab854SArnd Bergmann ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, status)); 108ce8ab854SArnd Bergmann if (unlikely(ret)) 109ce8ab854SArnd Bergmann break; 110ce8ab854SArnd Bergmann if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) { 111ce8ab854SArnd Bergmann ret = spu_reacquire_runnable(ctx, npc, status); 112ce8ab854SArnd Bergmann if (ret) 113ce8ab854SArnd Bergmann goto out; 114ce8ab854SArnd Bergmann continue; 115ce8ab854SArnd Bergmann } 116ce8ab854SArnd Bergmann ret = spu_process_events(ctx); 117ce8ab854SArnd Bergmann 118ce8ab854SArnd Bergmann } while (!ret && !(*status & (SPU_STATUS_STOPPED_BY_STOP | 119ce8ab854SArnd Bergmann SPU_STATUS_STOPPED_BY_HALT))); 120ce8ab854SArnd Bergmann 121ce8ab854SArnd Bergmann ctx->ops->runcntl_stop(ctx); 122ce8ab854SArnd Bergmann ret = spu_run_fini(ctx, npc, status); 123ce8ab854SArnd Bergmann if (!ret) 124ce8ab854SArnd Bergmann ret = *status; 125ce8ab854SArnd Bergmann spu_yield(ctx); 126ce8ab854SArnd Bergmann 127ce8ab854SArnd Bergmann out: 128ce8ab854SArnd Bergmann up(&ctx->run_sema); 129ce8ab854SArnd Bergmann return ret; 130ce8ab854SArnd Bergmann } 131ce8ab854SArnd Bergmann 132