10afacde3Sarnd@arndb.de #define DEBUG 20afacde3Sarnd@arndb.de 3ce8ab854SArnd Bergmann #include <linux/wait.h> 4ce8ab854SArnd Bergmann #include <linux/ptrace.h> 5ce8ab854SArnd Bergmann 6ce8ab854SArnd Bergmann #include <asm/spu.h> 7c6730ed4SJeremy Kerr #include <asm/spu_priv1.h> 8c6730ed4SJeremy Kerr #include <asm/io.h> 9cfff5b23SDave Jones #include <asm/unistd.h> 10ce8ab854SArnd Bergmann 11ce8ab854SArnd Bergmann #include "spufs.h" 12ce8ab854SArnd Bergmann 13ce8ab854SArnd Bergmann /* interrupt-level stop callback function. */ 14f3d69e05SLuke Browning void spufs_stop_callback(struct spu *spu, int irq) 15ce8ab854SArnd Bergmann { 16ce8ab854SArnd Bergmann struct spu_context *ctx = spu->ctx; 17ce8ab854SArnd Bergmann 18d6ad39bcSJeremy Kerr /* 19d6ad39bcSJeremy Kerr * It should be impossible to preempt a context while an exception 20d6ad39bcSJeremy Kerr * is being processed, since the context switch code is specially 21d6ad39bcSJeremy Kerr * coded to deal with interrupts ... But, just in case, sanity check 22d6ad39bcSJeremy Kerr * the context pointer. It is OK to return doing nothing since 23d6ad39bcSJeremy Kerr * the exception will be regenerated when the context is resumed. 24d6ad39bcSJeremy Kerr */ 25d6ad39bcSJeremy Kerr if (ctx) { 26d6ad39bcSJeremy Kerr /* Copy exception arguments into module specific structure */ 27f3d69e05SLuke Browning switch(irq) { 28f3d69e05SLuke Browning case 0 : 29d6ad39bcSJeremy Kerr ctx->csa.class_0_pending = spu->class_0_pending; 30f3d69e05SLuke Browning ctx->csa.class_0_dar = spu->class_0_dar; 31f3d69e05SLuke Browning break; 32f3d69e05SLuke Browning case 1 : 33f3d69e05SLuke Browning ctx->csa.class_1_dsisr = spu->class_1_dsisr; 34f3d69e05SLuke Browning ctx->csa.class_1_dar = spu->class_1_dar; 35f3d69e05SLuke Browning break; 36f3d69e05SLuke Browning case 2 : 37f3d69e05SLuke Browning break; 38f3d69e05SLuke Browning } 39d6ad39bcSJeremy Kerr 40d6ad39bcSJeremy Kerr /* ensure that the exception status has hit memory before a 41d6ad39bcSJeremy Kerr * thread waiting on the context's stop queue is woken */ 42d6ad39bcSJeremy Kerr smp_wmb(); 43d6ad39bcSJeremy Kerr 44ce8ab854SArnd Bergmann wake_up_all(&ctx->stop_wq); 45ce8ab854SArnd Bergmann } 46d6ad39bcSJeremy Kerr } 47d6ad39bcSJeremy Kerr 48e65c2f6fSLuke Browning int spu_stopped(struct spu_context *ctx, u32 *stat) 49ce8ab854SArnd Bergmann { 50e65c2f6fSLuke Browning u64 dsisr; 51e65c2f6fSLuke Browning u32 stopped; 52ce8ab854SArnd Bergmann 53e65c2f6fSLuke Browning stopped = SPU_STATUS_INVALID_INSTR | SPU_STATUS_SINGLE_STEP | 54e65c2f6fSLuke Browning SPU_STATUS_STOPPED_BY_HALT | SPU_STATUS_STOPPED_BY_STOP; 55d84050f4SLuke Browning 56d84050f4SLuke Browning top: 57d84050f4SLuke Browning *stat = ctx->ops->status_read(ctx); 58d84050f4SLuke Browning if (*stat & stopped) { 59d84050f4SLuke Browning /* 60d84050f4SLuke Browning * If the spu hasn't finished stopping, we need to 61d84050f4SLuke Browning * re-read the register to get the stopped value. 62d84050f4SLuke Browning */ 63d84050f4SLuke Browning if (*stat & SPU_STATUS_RUNNING) 64d84050f4SLuke Browning goto top; 65d84050f4SLuke Browning return 1; 66d84050f4SLuke Browning } 67d84050f4SLuke Browning 68d84050f4SLuke Browning if (test_bit(SPU_SCHED_NOTIFY_ACTIVE, &ctx->sched_flags)) 69e65c2f6fSLuke Browning return 1; 70e65c2f6fSLuke Browning 71f3d69e05SLuke Browning dsisr = ctx->csa.class_1_dsisr; 72e65c2f6fSLuke Browning if (dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED)) 73e65c2f6fSLuke Browning return 1; 74e65c2f6fSLuke Browning 75e65c2f6fSLuke Browning if (ctx->csa.class_0_pending) 76e65c2f6fSLuke Browning return 1; 77e65c2f6fSLuke Browning 78e65c2f6fSLuke Browning return 0; 79ce8ab854SArnd Bergmann } 80ce8ab854SArnd Bergmann 81c6730ed4SJeremy Kerr static int spu_setup_isolated(struct spu_context *ctx) 82c6730ed4SJeremy Kerr { 83c6730ed4SJeremy Kerr int ret; 84c6730ed4SJeremy Kerr u64 __iomem *mfc_cntl; 85c6730ed4SJeremy Kerr u64 sr1; 86c6730ed4SJeremy Kerr u32 status; 87c6730ed4SJeremy Kerr unsigned long timeout; 88c6730ed4SJeremy Kerr const u32 status_loading = SPU_STATUS_RUNNING 89c6730ed4SJeremy Kerr | SPU_STATUS_ISOLATED_STATE | SPU_STATUS_ISOLATED_LOAD_STATUS; 90c6730ed4SJeremy Kerr 917ec18ab9SChristoph Hellwig ret = -ENODEV; 92c6730ed4SJeremy Kerr if (!isolated_loader) 93c6730ed4SJeremy Kerr goto out; 94c6730ed4SJeremy Kerr 957ec18ab9SChristoph Hellwig /* 967ec18ab9SChristoph Hellwig * We need to exclude userspace access to the context. 977ec18ab9SChristoph Hellwig * 987ec18ab9SChristoph Hellwig * To protect against memory access we invalidate all ptes 997ec18ab9SChristoph Hellwig * and make sure the pagefault handlers block on the mutex. 1007ec18ab9SChristoph Hellwig */ 1017ec18ab9SChristoph Hellwig spu_unmap_mappings(ctx); 1027ec18ab9SChristoph Hellwig 103c6730ed4SJeremy Kerr mfc_cntl = &ctx->spu->priv2->mfc_control_RW; 104c6730ed4SJeremy Kerr 105c6730ed4SJeremy Kerr /* purge the MFC DMA queue to ensure no spurious accesses before we 106c6730ed4SJeremy Kerr * enter kernel mode */ 107c6730ed4SJeremy Kerr timeout = jiffies + HZ; 108c6730ed4SJeremy Kerr out_be64(mfc_cntl, MFC_CNTL_PURGE_DMA_REQUEST); 109c6730ed4SJeremy Kerr while ((in_be64(mfc_cntl) & MFC_CNTL_PURGE_DMA_STATUS_MASK) 110c6730ed4SJeremy Kerr != MFC_CNTL_PURGE_DMA_COMPLETE) { 111c6730ed4SJeremy Kerr if (time_after(jiffies, timeout)) { 112c6730ed4SJeremy Kerr printk(KERN_ERR "%s: timeout flushing MFC DMA queue\n", 113e48b1b45SHarvey Harrison __func__); 114c6730ed4SJeremy Kerr ret = -EIO; 1157ec18ab9SChristoph Hellwig goto out; 116c6730ed4SJeremy Kerr } 117c6730ed4SJeremy Kerr cond_resched(); 118c6730ed4SJeremy Kerr } 119c6730ed4SJeremy Kerr 120c6730ed4SJeremy Kerr /* put the SPE in kernel mode to allow access to the loader */ 121c6730ed4SJeremy Kerr sr1 = spu_mfc_sr1_get(ctx->spu); 122c6730ed4SJeremy Kerr sr1 &= ~MFC_STATE1_PROBLEM_STATE_MASK; 123c6730ed4SJeremy Kerr spu_mfc_sr1_set(ctx->spu, sr1); 124c6730ed4SJeremy Kerr 125c6730ed4SJeremy Kerr /* start the loader */ 126c6730ed4SJeremy Kerr ctx->ops->signal1_write(ctx, (unsigned long)isolated_loader >> 32); 127c6730ed4SJeremy Kerr ctx->ops->signal2_write(ctx, 128c6730ed4SJeremy Kerr (unsigned long)isolated_loader & 0xffffffff); 129c6730ed4SJeremy Kerr 130c6730ed4SJeremy Kerr ctx->ops->runcntl_write(ctx, 131c6730ed4SJeremy Kerr SPU_RUNCNTL_RUNNABLE | SPU_RUNCNTL_ISOLATE); 132c6730ed4SJeremy Kerr 133c6730ed4SJeremy Kerr ret = 0; 134c6730ed4SJeremy Kerr timeout = jiffies + HZ; 135c6730ed4SJeremy Kerr while (((status = ctx->ops->status_read(ctx)) & status_loading) == 136c6730ed4SJeremy Kerr status_loading) { 137c6730ed4SJeremy Kerr if (time_after(jiffies, timeout)) { 138c6730ed4SJeremy Kerr printk(KERN_ERR "%s: timeout waiting for loader\n", 139e48b1b45SHarvey Harrison __func__); 140c6730ed4SJeremy Kerr ret = -EIO; 141c6730ed4SJeremy Kerr goto out_drop_priv; 142c6730ed4SJeremy Kerr } 143c6730ed4SJeremy Kerr cond_resched(); 144c6730ed4SJeremy Kerr } 145c6730ed4SJeremy Kerr 146c6730ed4SJeremy Kerr if (!(status & SPU_STATUS_RUNNING)) { 147c6730ed4SJeremy Kerr /* If isolated LOAD has failed: run SPU, we will get a stop-and 148c6730ed4SJeremy Kerr * signal later. */ 149e48b1b45SHarvey Harrison pr_debug("%s: isolated LOAD failed\n", __func__); 150c6730ed4SJeremy Kerr ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE); 151c6730ed4SJeremy Kerr ret = -EACCES; 1527ec18ab9SChristoph Hellwig goto out_drop_priv; 1537ec18ab9SChristoph Hellwig } 154c6730ed4SJeremy Kerr 1557ec18ab9SChristoph Hellwig if (!(status & SPU_STATUS_ISOLATED_STATE)) { 156c6730ed4SJeremy Kerr /* This isn't allowed by the CBEA, but check anyway */ 157e48b1b45SHarvey Harrison pr_debug("%s: SPU fell out of isolated mode?\n", __func__); 158c6730ed4SJeremy Kerr ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_STOP); 159c6730ed4SJeremy Kerr ret = -EINVAL; 1607ec18ab9SChristoph Hellwig goto out_drop_priv; 161c6730ed4SJeremy Kerr } 162c6730ed4SJeremy Kerr 163c6730ed4SJeremy Kerr out_drop_priv: 164c6730ed4SJeremy Kerr /* Finished accessing the loader. Drop kernel mode */ 165c6730ed4SJeremy Kerr sr1 |= MFC_STATE1_PROBLEM_STATE_MASK; 166c6730ed4SJeremy Kerr spu_mfc_sr1_set(ctx->spu, sr1); 167c6730ed4SJeremy Kerr 168c6730ed4SJeremy Kerr out: 169c6730ed4SJeremy Kerr return ret; 170c6730ed4SJeremy Kerr } 171c6730ed4SJeremy Kerr 172aa45e256SChristoph Hellwig static int spu_run_init(struct spu_context *ctx, u32 *npc) 173ce8ab854SArnd Bergmann { 174e65c2f6fSLuke Browning unsigned long runcntl = SPU_RUNCNTL_RUNNABLE; 17591569531SLuke Browning int ret; 176cc210b3eSLuke Browning 17727ec41d3SAndre Detsch spuctx_switch_state(ctx, SPU_UTIL_SYSTEM); 17827ec41d3SAndre Detsch 17991569531SLuke Browning /* 180e65c2f6fSLuke Browning * NOSCHED is synchronous scheduling with respect to the caller. 181e65c2f6fSLuke Browning * The caller waits for the context to be loaded. 18291569531SLuke Browning */ 183e65c2f6fSLuke Browning if (ctx->flags & SPU_CREATE_NOSCHED) { 18491569531SLuke Browning if (ctx->state == SPU_STATE_SAVED) { 18591569531SLuke Browning ret = spu_activate(ctx, 0); 186c6730ed4SJeremy Kerr if (ret) 187ce8ab854SArnd Bergmann return ret; 1880afacde3Sarnd@arndb.de } 189e65c2f6fSLuke Browning } 190c6730ed4SJeremy Kerr 191e65c2f6fSLuke Browning /* 192e65c2f6fSLuke Browning * Apply special setup as required. 193e65c2f6fSLuke Browning */ 194e65c2f6fSLuke Browning if (ctx->flags & SPU_CREATE_ISOLATE) { 19591569531SLuke Browning if (!(ctx->ops->status_read(ctx) & SPU_STATUS_ISOLATED_STATE)) { 19691569531SLuke Browning ret = spu_setup_isolated(ctx); 19791569531SLuke Browning if (ret) 19891569531SLuke Browning return ret; 19991569531SLuke Browning } 20091569531SLuke Browning 20191569531SLuke Browning /* 20291569531SLuke Browning * If userspace has set the runcntrl register (eg, to 20391569531SLuke Browning * issue an isolated exit), we need to re-set it here 20491569531SLuke Browning */ 205c6730ed4SJeremy Kerr runcntl = ctx->ops->runcntl_read(ctx) & 206c6730ed4SJeremy Kerr (SPU_RUNCNTL_RUNNABLE | SPU_RUNCNTL_ISOLATE); 207c6730ed4SJeremy Kerr if (runcntl == 0) 208c6730ed4SJeremy Kerr runcntl = SPU_RUNCNTL_RUNNABLE; 2092eb1b120SChristoph Hellwig } else { 210cc210b3eSLuke Browning unsigned long privcntl; 211cc210b3eSLuke Browning 21205169237SBenjamin Herrenschmidt if (test_thread_flag(TIF_SINGLESTEP)) 213cc210b3eSLuke Browning privcntl = SPU_PRIVCNTL_MODE_SINGLE_STEP; 214cc210b3eSLuke Browning else 215cc210b3eSLuke Browning privcntl = SPU_PRIVCNTL_MODE_NORMAL; 216cc210b3eSLuke Browning 217cc210b3eSLuke Browning ctx->ops->privcntl_write(ctx, privcntl); 218d9dd421fSJeremy Kerr ctx->ops->npc_write(ctx, *npc); 219d9dd421fSJeremy Kerr } 220d9dd421fSJeremy Kerr 221e65c2f6fSLuke Browning ctx->ops->runcntl_write(ctx, runcntl); 22291569531SLuke Browning 223d9dd421fSJeremy Kerr if (ctx->flags & SPU_CREATE_NOSCHED) { 224d9dd421fSJeremy Kerr spuctx_switch_state(ctx, SPU_UTIL_USER); 225d9dd421fSJeremy Kerr } else { 226d9dd421fSJeremy Kerr 22791569531SLuke Browning if (ctx->state == SPU_STATE_SAVED) { 22891569531SLuke Browning ret = spu_activate(ctx, 0); 22991569531SLuke Browning if (ret) 23091569531SLuke Browning return ret; 231e65c2f6fSLuke Browning } else { 23227ec41d3SAndre Detsch spuctx_switch_state(ctx, SPU_UTIL_USER); 233e65c2f6fSLuke Browning } 23491569531SLuke Browning } 23527ec41d3SAndre Detsch 236ce7c191bSJeremy Kerr set_bit(SPU_SCHED_SPU_RUN, &ctx->sched_flags); 237aa45e256SChristoph Hellwig return 0; 238ce8ab854SArnd Bergmann } 239ce8ab854SArnd Bergmann 240aa45e256SChristoph Hellwig static int spu_run_fini(struct spu_context *ctx, u32 *npc, 241ce8ab854SArnd Bergmann u32 *status) 242ce8ab854SArnd Bergmann { 243ce8ab854SArnd Bergmann int ret = 0; 244ce8ab854SArnd Bergmann 245e65c2f6fSLuke Browning spu_del_from_rq(ctx); 246e65c2f6fSLuke Browning 247ce8ab854SArnd Bergmann *status = ctx->ops->status_read(ctx); 248ce8ab854SArnd Bergmann *npc = ctx->ops->npc_read(ctx); 24927ec41d3SAndre Detsch 25027ec41d3SAndre Detsch spuctx_switch_state(ctx, SPU_UTIL_IDLE_LOADED); 251ce7c191bSJeremy Kerr clear_bit(SPU_SCHED_SPU_RUN, &ctx->sched_flags); 252f5ed0eb6SJeremy Kerr spu_switch_log_notify(NULL, ctx, SWITCH_LOG_EXIT, *status); 253ce8ab854SArnd Bergmann spu_release(ctx); 254ce8ab854SArnd Bergmann 255ce8ab854SArnd Bergmann if (signal_pending(current)) 256ce8ab854SArnd Bergmann ret = -ERESTARTSYS; 2572ebb2477SMasato Noguchi 258ce8ab854SArnd Bergmann return ret; 259ce8ab854SArnd Bergmann } 260ce8ab854SArnd Bergmann 2612dd14934SArnd Bergmann /* 2622dd14934SArnd Bergmann * SPU syscall restarting is tricky because we violate the basic 2632dd14934SArnd Bergmann * assumption that the signal handler is running on the interrupted 2642dd14934SArnd Bergmann * thread. Here instead, the handler runs on PowerPC user space code, 2652dd14934SArnd Bergmann * while the syscall was called from the SPU. 2662dd14934SArnd Bergmann * This means we can only do a very rough approximation of POSIX 2672dd14934SArnd Bergmann * signal semantics. 2682dd14934SArnd Bergmann */ 2691238819aSSebastian Siewior static int spu_handle_restartsys(struct spu_context *ctx, long *spu_ret, 2702dd14934SArnd Bergmann unsigned int *npc) 2712dd14934SArnd Bergmann { 2722dd14934SArnd Bergmann int ret; 2732dd14934SArnd Bergmann 2742dd14934SArnd Bergmann switch (*spu_ret) { 2752dd14934SArnd Bergmann case -ERESTARTSYS: 2762dd14934SArnd Bergmann case -ERESTARTNOINTR: 2772dd14934SArnd Bergmann /* 2782dd14934SArnd Bergmann * Enter the regular syscall restarting for 2792dd14934SArnd Bergmann * sys_spu_run, then restart the SPU syscall 2802dd14934SArnd Bergmann * callback. 2812dd14934SArnd Bergmann */ 2822dd14934SArnd Bergmann *npc -= 8; 2832dd14934SArnd Bergmann ret = -ERESTARTSYS; 2842dd14934SArnd Bergmann break; 2852dd14934SArnd Bergmann case -ERESTARTNOHAND: 2862dd14934SArnd Bergmann case -ERESTART_RESTARTBLOCK: 2872dd14934SArnd Bergmann /* 2882dd14934SArnd Bergmann * Restart block is too hard for now, just return -EINTR 2892dd14934SArnd Bergmann * to the SPU. 2902dd14934SArnd Bergmann * ERESTARTNOHAND comes from sys_pause, we also return 2912dd14934SArnd Bergmann * -EINTR from there. 2922dd14934SArnd Bergmann * Assume that we need to be restarted ourselves though. 2932dd14934SArnd Bergmann */ 2942dd14934SArnd Bergmann *spu_ret = -EINTR; 2952dd14934SArnd Bergmann ret = -ERESTARTSYS; 2962dd14934SArnd Bergmann break; 2972dd14934SArnd Bergmann default: 2982dd14934SArnd Bergmann printk(KERN_WARNING "%s: unexpected return code %ld\n", 299e48b1b45SHarvey Harrison __func__, *spu_ret); 3002dd14934SArnd Bergmann ret = 0; 3012dd14934SArnd Bergmann } 3022dd14934SArnd Bergmann return ret; 3032dd14934SArnd Bergmann } 3042dd14934SArnd Bergmann 3051238819aSSebastian Siewior static int spu_process_callback(struct spu_context *ctx) 3062dd14934SArnd Bergmann { 3072dd14934SArnd Bergmann struct spu_syscall_block s; 3082dd14934SArnd Bergmann u32 ls_pointer, npc; 3099e2fe2ceSAkinobu Mita void __iomem *ls; 3102dd14934SArnd Bergmann long spu_ret; 311d29694f0SJeremy Kerr int ret; 3122dd14934SArnd Bergmann 3132dd14934SArnd Bergmann /* get syscall block from local store */ 3149e2fe2ceSAkinobu Mita npc = ctx->ops->npc_read(ctx) & ~3; 3159e2fe2ceSAkinobu Mita ls = (void __iomem *)ctx->ops->get_ls(ctx); 3169e2fe2ceSAkinobu Mita ls_pointer = in_be32(ls + npc); 3172dd14934SArnd Bergmann if (ls_pointer > (LS_SIZE - sizeof(s))) 3182dd14934SArnd Bergmann return -EFAULT; 3199e2fe2ceSAkinobu Mita memcpy_fromio(&s, ls + ls_pointer, sizeof(s)); 3202dd14934SArnd Bergmann 3212dd14934SArnd Bergmann /* do actual syscall without pinning the spu */ 3222dd14934SArnd Bergmann ret = 0; 3232dd14934SArnd Bergmann spu_ret = -ENOSYS; 3242dd14934SArnd Bergmann npc += 4; 3252dd14934SArnd Bergmann 3262dd14934SArnd Bergmann if (s.nr_ret < __NR_syscalls) { 3272dd14934SArnd Bergmann spu_release(ctx); 3282dd14934SArnd Bergmann /* do actual system call from here */ 3292dd14934SArnd Bergmann spu_ret = spu_sys_callback(&s); 3302dd14934SArnd Bergmann if (spu_ret <= -ERESTARTSYS) { 3312dd14934SArnd Bergmann ret = spu_handle_restartsys(ctx, &spu_ret, &npc); 3322dd14934SArnd Bergmann } 333d29694f0SJeremy Kerr mutex_lock(&ctx->state_mutex); 3342dd14934SArnd Bergmann if (ret == -ERESTARTSYS) 3352dd14934SArnd Bergmann return ret; 3362dd14934SArnd Bergmann } 3372dd14934SArnd Bergmann 3384eb5aef5SJeremy Kerr /* need to re-get the ls, as it may have changed when we released the 3394eb5aef5SJeremy Kerr * spu */ 3404eb5aef5SJeremy Kerr ls = (void __iomem *)ctx->ops->get_ls(ctx); 3414eb5aef5SJeremy Kerr 3422dd14934SArnd Bergmann /* write result, jump over indirect pointer */ 3439e2fe2ceSAkinobu Mita memcpy_toio(ls + ls_pointer, &spu_ret, sizeof(spu_ret)); 3442dd14934SArnd Bergmann ctx->ops->npc_write(ctx, npc); 3452dd14934SArnd Bergmann ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE); 3462dd14934SArnd Bergmann return ret; 3472dd14934SArnd Bergmann } 3482dd14934SArnd Bergmann 34950af32a9SJeremy Kerr long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *event) 350ce8ab854SArnd Bergmann { 351ce8ab854SArnd Bergmann int ret; 35236aaccc1SBob Nelson struct spu *spu; 3539add11daSArnd Bergmann u32 status; 354ce8ab854SArnd Bergmann 355e45d48a3SChristoph Hellwig if (mutex_lock_interruptible(&ctx->run_mutex)) 356ce8ab854SArnd Bergmann return -ERESTARTSYS; 357ce8ab854SArnd Bergmann 3589add11daSArnd Bergmann ctx->event_return = 0; 359aa45e256SChristoph Hellwig 360c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 361c9101bdbSChristoph Hellwig if (ret) 362c9101bdbSChristoph Hellwig goto out_unlock; 3632cf2b3b4SChristoph Hellwig 364c0bace5cSJeremy Kerr spu_enable_spu(ctx); 365c0bace5cSJeremy Kerr 3662cf2b3b4SChristoph Hellwig spu_update_sched_info(ctx); 367aa45e256SChristoph Hellwig 368aa45e256SChristoph Hellwig ret = spu_run_init(ctx, npc); 369aa45e256SChristoph Hellwig if (ret) { 370aa45e256SChristoph Hellwig spu_release(ctx); 371ce8ab854SArnd Bergmann goto out; 372aa45e256SChristoph Hellwig } 373ce8ab854SArnd Bergmann 374ce8ab854SArnd Bergmann do { 3759add11daSArnd Bergmann ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, &status)); 376eebead5bSChristoph Hellwig if (unlikely(ret)) { 377eebead5bSChristoph Hellwig /* 378eebead5bSChristoph Hellwig * This is nasty: we need the state_mutex for all the 379eebead5bSChristoph Hellwig * bookkeeping even if the syscall was interrupted by 380eebead5bSChristoph Hellwig * a signal. ewww. 381eebead5bSChristoph Hellwig */ 382eebead5bSChristoph Hellwig mutex_lock(&ctx->state_mutex); 383ce8ab854SArnd Bergmann break; 384eebead5bSChristoph Hellwig } 38536aaccc1SBob Nelson spu = ctx->spu; 38636aaccc1SBob Nelson if (unlikely(test_and_clear_bit(SPU_SCHED_NOTIFY_ACTIVE, 38736aaccc1SBob Nelson &ctx->sched_flags))) { 38836aaccc1SBob Nelson if (!(status & SPU_STATUS_STOPPED_BY_STOP)) { 38936aaccc1SBob Nelson spu_switch_notify(spu, ctx); 39036aaccc1SBob Nelson continue; 39136aaccc1SBob Nelson } 39236aaccc1SBob Nelson } 39327ec41d3SAndre Detsch 39427ec41d3SAndre Detsch spuctx_switch_state(ctx, SPU_UTIL_SYSTEM); 39527ec41d3SAndre Detsch 3969add11daSArnd Bergmann if ((status & SPU_STATUS_STOPPED_BY_STOP) && 3979add11daSArnd Bergmann (status >> SPU_STOP_STATUS_SHIFT == 0x2104)) { 3982dd14934SArnd Bergmann ret = spu_process_callback(ctx); 3992dd14934SArnd Bergmann if (ret) 4002dd14934SArnd Bergmann break; 4019add11daSArnd Bergmann status &= ~SPU_STATUS_STOPPED_BY_STOP; 4022dd14934SArnd Bergmann } 40357dace23SArnd Bergmann ret = spufs_handle_class1(ctx); 40457dace23SArnd Bergmann if (ret) 40557dace23SArnd Bergmann break; 40657dace23SArnd Bergmann 407d6ad39bcSJeremy Kerr ret = spufs_handle_class0(ctx); 408d6ad39bcSJeremy Kerr if (ret) 409d6ad39bcSJeremy Kerr break; 410d6ad39bcSJeremy Kerr 411d6ad39bcSJeremy Kerr if (signal_pending(current)) 412d6ad39bcSJeremy Kerr ret = -ERESTARTSYS; 4139add11daSArnd Bergmann } while (!ret && !(status & (SPU_STATUS_STOPPED_BY_STOP | 41405169237SBenjamin Herrenschmidt SPU_STATUS_STOPPED_BY_HALT | 41505169237SBenjamin Herrenschmidt SPU_STATUS_SINGLE_STEP))); 416ce8ab854SArnd Bergmann 417c25620d7SMasato Noguchi spu_disable_spu(ctx); 4189add11daSArnd Bergmann ret = spu_run_fini(ctx, npc, &status); 419ce8ab854SArnd Bergmann spu_yield(ctx); 420ce8ab854SArnd Bergmann 421e66686b4SLuke Browning if ((status & SPU_STATUS_STOPPED_BY_STOP) && 422e66686b4SLuke Browning (((status >> SPU_STOP_STATUS_SHIFT) & 0x3f00) == 0x2100)) 423e66686b4SLuke Browning ctx->stats.libassist++; 424e66686b4SLuke Browning 4252ebb2477SMasato Noguchi if ((ret == 0) || 4262ebb2477SMasato Noguchi ((ret == -ERESTARTSYS) && 4272ebb2477SMasato Noguchi ((status & SPU_STATUS_STOPPED_BY_HALT) || 42805169237SBenjamin Herrenschmidt (status & SPU_STATUS_SINGLE_STEP) || 4292ebb2477SMasato Noguchi ((status & SPU_STATUS_STOPPED_BY_STOP) && 4302ebb2477SMasato Noguchi (status >> SPU_STOP_STATUS_SHIFT != 0x2104))))) 4312ebb2477SMasato Noguchi ret = status; 4322ebb2477SMasato Noguchi 43305169237SBenjamin Herrenschmidt /* Note: we don't need to force_sig SIGTRAP on single-step 43405169237SBenjamin Herrenschmidt * since we have TIF_SINGLESTEP set, thus the kernel will do 43505169237SBenjamin Herrenschmidt * it upon return from the syscall anyawy 43605169237SBenjamin Herrenschmidt */ 43760cf54dbSJeremy Kerr if (unlikely(status & SPU_STATUS_SINGLE_STEP)) 43860cf54dbSJeremy Kerr ret = -ERESTARTSYS; 43960cf54dbSJeremy Kerr 44060cf54dbSJeremy Kerr else if (unlikely((status & SPU_STATUS_STOPPED_BY_STOP) 44160cf54dbSJeremy Kerr && (status >> SPU_STOP_STATUS_SHIFT) == 0x3fff)) { 4422ebb2477SMasato Noguchi force_sig(SIGTRAP, current); 4432ebb2477SMasato Noguchi ret = -ERESTARTSYS; 4442ebb2477SMasato Noguchi } 4452ebb2477SMasato Noguchi 446ce8ab854SArnd Bergmann out: 4479add11daSArnd Bergmann *event = ctx->event_return; 448c9101bdbSChristoph Hellwig out_unlock: 449e45d48a3SChristoph Hellwig mutex_unlock(&ctx->run_mutex); 450ce8ab854SArnd Bergmann return ret; 451ce8ab854SArnd Bergmann } 452