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. */ 14ce8ab854SArnd Bergmann void spufs_stop_callback(struct spu *spu) 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 */ 27d6ad39bcSJeremy Kerr ctx->csa.class_0_pending = spu->class_0_pending; 28d6ad39bcSJeremy Kerr ctx->csa.dsisr = spu->dsisr; 29d6ad39bcSJeremy Kerr ctx->csa.dar = spu->dar; 30d6ad39bcSJeremy Kerr 31d6ad39bcSJeremy Kerr /* ensure that the exception status has hit memory before a 32d6ad39bcSJeremy Kerr * thread waiting on the context's stop queue is woken */ 33d6ad39bcSJeremy Kerr smp_wmb(); 34d6ad39bcSJeremy Kerr 35ce8ab854SArnd Bergmann wake_up_all(&ctx->stop_wq); 36ce8ab854SArnd Bergmann } 37ce8ab854SArnd Bergmann 38d6ad39bcSJeremy Kerr /* Clear callback arguments from spu structure */ 39d6ad39bcSJeremy Kerr spu->class_0_pending = 0; 40d6ad39bcSJeremy Kerr spu->dsisr = 0; 41d6ad39bcSJeremy Kerr spu->dar = 0; 42d6ad39bcSJeremy Kerr } 43d6ad39bcSJeremy Kerr 44ce8ab854SArnd Bergmann static inline int spu_stopped(struct spu_context *ctx, u32 *stat) 45ce8ab854SArnd Bergmann { 46ce8ab854SArnd Bergmann struct spu *spu; 47ce8ab854SArnd Bergmann u64 pte_fault; 48ce8ab854SArnd Bergmann 49ce8ab854SArnd Bergmann *stat = ctx->ops->status_read(ctx); 5036aaccc1SBob Nelson 51ce8ab854SArnd Bergmann spu = ctx->spu; 5236aaccc1SBob Nelson if (ctx->state != SPU_STATE_RUNNABLE || 5336aaccc1SBob Nelson test_bit(SPU_SCHED_NOTIFY_ACTIVE, &ctx->sched_flags)) 5436aaccc1SBob Nelson return 1; 55d6ad39bcSJeremy Kerr pte_fault = ctx->csa.dsisr & 56ce8ab854SArnd Bergmann (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED); 57d6ad39bcSJeremy Kerr return (!(*stat & SPU_STATUS_RUNNING) || pte_fault || ctx->csa.class_0_pending) ? 58be703177SSebastian Siewior 1 : 0; 59ce8ab854SArnd Bergmann } 60ce8ab854SArnd Bergmann 61c6730ed4SJeremy Kerr static int spu_setup_isolated(struct spu_context *ctx) 62c6730ed4SJeremy Kerr { 63c6730ed4SJeremy Kerr int ret; 64c6730ed4SJeremy Kerr u64 __iomem *mfc_cntl; 65c6730ed4SJeremy Kerr u64 sr1; 66c6730ed4SJeremy Kerr u32 status; 67c6730ed4SJeremy Kerr unsigned long timeout; 68c6730ed4SJeremy Kerr const u32 status_loading = SPU_STATUS_RUNNING 69c6730ed4SJeremy Kerr | SPU_STATUS_ISOLATED_STATE | SPU_STATUS_ISOLATED_LOAD_STATUS; 70c6730ed4SJeremy Kerr 717ec18ab9SChristoph Hellwig ret = -ENODEV; 72c6730ed4SJeremy Kerr if (!isolated_loader) 73c6730ed4SJeremy Kerr goto out; 74c6730ed4SJeremy Kerr 757ec18ab9SChristoph Hellwig /* 767ec18ab9SChristoph Hellwig * We need to exclude userspace access to the context. 777ec18ab9SChristoph Hellwig * 787ec18ab9SChristoph Hellwig * To protect against memory access we invalidate all ptes 797ec18ab9SChristoph Hellwig * and make sure the pagefault handlers block on the mutex. 807ec18ab9SChristoph Hellwig */ 817ec18ab9SChristoph Hellwig spu_unmap_mappings(ctx); 827ec18ab9SChristoph Hellwig 83c6730ed4SJeremy Kerr mfc_cntl = &ctx->spu->priv2->mfc_control_RW; 84c6730ed4SJeremy Kerr 85c6730ed4SJeremy Kerr /* purge the MFC DMA queue to ensure no spurious accesses before we 86c6730ed4SJeremy Kerr * enter kernel mode */ 87c6730ed4SJeremy Kerr timeout = jiffies + HZ; 88c6730ed4SJeremy Kerr out_be64(mfc_cntl, MFC_CNTL_PURGE_DMA_REQUEST); 89c6730ed4SJeremy Kerr while ((in_be64(mfc_cntl) & MFC_CNTL_PURGE_DMA_STATUS_MASK) 90c6730ed4SJeremy Kerr != MFC_CNTL_PURGE_DMA_COMPLETE) { 91c6730ed4SJeremy Kerr if (time_after(jiffies, timeout)) { 92c6730ed4SJeremy Kerr printk(KERN_ERR "%s: timeout flushing MFC DMA queue\n", 93c6730ed4SJeremy Kerr __FUNCTION__); 94c6730ed4SJeremy Kerr ret = -EIO; 957ec18ab9SChristoph Hellwig goto out; 96c6730ed4SJeremy Kerr } 97c6730ed4SJeremy Kerr cond_resched(); 98c6730ed4SJeremy Kerr } 99c6730ed4SJeremy Kerr 100c6730ed4SJeremy Kerr /* put the SPE in kernel mode to allow access to the loader */ 101c6730ed4SJeremy Kerr sr1 = spu_mfc_sr1_get(ctx->spu); 102c6730ed4SJeremy Kerr sr1 &= ~MFC_STATE1_PROBLEM_STATE_MASK; 103c6730ed4SJeremy Kerr spu_mfc_sr1_set(ctx->spu, sr1); 104c6730ed4SJeremy Kerr 105c6730ed4SJeremy Kerr /* start the loader */ 106c6730ed4SJeremy Kerr ctx->ops->signal1_write(ctx, (unsigned long)isolated_loader >> 32); 107c6730ed4SJeremy Kerr ctx->ops->signal2_write(ctx, 108c6730ed4SJeremy Kerr (unsigned long)isolated_loader & 0xffffffff); 109c6730ed4SJeremy Kerr 110c6730ed4SJeremy Kerr ctx->ops->runcntl_write(ctx, 111c6730ed4SJeremy Kerr SPU_RUNCNTL_RUNNABLE | SPU_RUNCNTL_ISOLATE); 112c6730ed4SJeremy Kerr 113c6730ed4SJeremy Kerr ret = 0; 114c6730ed4SJeremy Kerr timeout = jiffies + HZ; 115c6730ed4SJeremy Kerr while (((status = ctx->ops->status_read(ctx)) & status_loading) == 116c6730ed4SJeremy Kerr status_loading) { 117c6730ed4SJeremy Kerr if (time_after(jiffies, timeout)) { 118c6730ed4SJeremy Kerr printk(KERN_ERR "%s: timeout waiting for loader\n", 119c6730ed4SJeremy Kerr __FUNCTION__); 120c6730ed4SJeremy Kerr ret = -EIO; 121c6730ed4SJeremy Kerr goto out_drop_priv; 122c6730ed4SJeremy Kerr } 123c6730ed4SJeremy Kerr cond_resched(); 124c6730ed4SJeremy Kerr } 125c6730ed4SJeremy Kerr 126c6730ed4SJeremy Kerr if (!(status & SPU_STATUS_RUNNING)) { 127c6730ed4SJeremy Kerr /* If isolated LOAD has failed: run SPU, we will get a stop-and 128c6730ed4SJeremy Kerr * signal later. */ 129c6730ed4SJeremy Kerr pr_debug("%s: isolated LOAD failed\n", __FUNCTION__); 130c6730ed4SJeremy Kerr ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE); 131c6730ed4SJeremy Kerr ret = -EACCES; 1327ec18ab9SChristoph Hellwig goto out_drop_priv; 1337ec18ab9SChristoph Hellwig } 134c6730ed4SJeremy Kerr 1357ec18ab9SChristoph Hellwig if (!(status & SPU_STATUS_ISOLATED_STATE)) { 136c6730ed4SJeremy Kerr /* This isn't allowed by the CBEA, but check anyway */ 137c6730ed4SJeremy Kerr pr_debug("%s: SPU fell out of isolated mode?\n", __FUNCTION__); 138c6730ed4SJeremy Kerr ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_STOP); 139c6730ed4SJeremy Kerr ret = -EINVAL; 1407ec18ab9SChristoph Hellwig goto out_drop_priv; 141c6730ed4SJeremy Kerr } 142c6730ed4SJeremy Kerr 143c6730ed4SJeremy Kerr out_drop_priv: 144c6730ed4SJeremy Kerr /* Finished accessing the loader. Drop kernel mode */ 145c6730ed4SJeremy Kerr sr1 |= MFC_STATE1_PROBLEM_STATE_MASK; 146c6730ed4SJeremy Kerr spu_mfc_sr1_set(ctx->spu, sr1); 147c6730ed4SJeremy Kerr 148c6730ed4SJeremy Kerr out: 149c6730ed4SJeremy Kerr return ret; 150c6730ed4SJeremy Kerr } 151c6730ed4SJeremy Kerr 152aa45e256SChristoph Hellwig static int spu_run_init(struct spu_context *ctx, u32 *npc) 153ce8ab854SArnd Bergmann { 154cc210b3eSLuke Browning unsigned long runcntl; 15591569531SLuke Browning int ret; 156cc210b3eSLuke Browning 15727ec41d3SAndre Detsch spuctx_switch_state(ctx, SPU_UTIL_SYSTEM); 15827ec41d3SAndre Detsch 159aa45e256SChristoph Hellwig if (ctx->flags & SPU_CREATE_ISOLATE) { 16091569531SLuke Browning /* 16191569531SLuke Browning * Force activation of spu. Isolated state assumes that 16291569531SLuke Browning * special loader context is loaded and running on spu. 16391569531SLuke Browning */ 16491569531SLuke Browning if (ctx->state == SPU_STATE_SAVED) { 16591569531SLuke Browning spu_set_timeslice(ctx); 166ce8ab854SArnd Bergmann 16791569531SLuke Browning ret = spu_activate(ctx, 0); 168c6730ed4SJeremy Kerr if (ret) 169ce8ab854SArnd Bergmann return ret; 1700afacde3Sarnd@arndb.de } 171c6730ed4SJeremy Kerr 17291569531SLuke Browning if (!(ctx->ops->status_read(ctx) & SPU_STATUS_ISOLATED_STATE)) { 17391569531SLuke Browning ret = spu_setup_isolated(ctx); 17491569531SLuke Browning if (ret) 17591569531SLuke Browning return ret; 17691569531SLuke Browning } 17791569531SLuke Browning 17891569531SLuke Browning /* 17991569531SLuke Browning * If userspace has set the runcntrl register (eg, to 18091569531SLuke Browning * issue an isolated exit), we need to re-set it here 18191569531SLuke Browning */ 182c6730ed4SJeremy Kerr runcntl = ctx->ops->runcntl_read(ctx) & 183c6730ed4SJeremy Kerr (SPU_RUNCNTL_RUNNABLE | SPU_RUNCNTL_ISOLATE); 184c6730ed4SJeremy Kerr if (runcntl == 0) 185c6730ed4SJeremy Kerr runcntl = SPU_RUNCNTL_RUNNABLE; 18691569531SLuke Browning 18791569531SLuke Browning spuctx_switch_state(ctx, SPU_UTIL_USER); 18891569531SLuke Browning ctx->ops->runcntl_write(ctx, runcntl); 18991569531SLuke Browning 1902eb1b120SChristoph Hellwig } else { 191cc210b3eSLuke Browning unsigned long privcntl; 192cc210b3eSLuke Browning 19305169237SBenjamin Herrenschmidt if (test_thread_flag(TIF_SINGLESTEP)) 194cc210b3eSLuke Browning privcntl = SPU_PRIVCNTL_MODE_SINGLE_STEP; 195cc210b3eSLuke Browning else 196cc210b3eSLuke Browning privcntl = SPU_PRIVCNTL_MODE_NORMAL; 197cc210b3eSLuke Browning runcntl = SPU_RUNCNTL_RUNNABLE; 198cc210b3eSLuke Browning 199cc210b3eSLuke Browning ctx->ops->npc_write(ctx, *npc); 200cc210b3eSLuke Browning ctx->ops->privcntl_write(ctx, privcntl); 20191569531SLuke Browning 20291569531SLuke Browning if (ctx->state == SPU_STATE_SAVED) { 20391569531SLuke Browning spu_set_timeslice(ctx); 20491569531SLuke Browning ret = spu_activate(ctx, 0); 20591569531SLuke Browning if (ret) 20691569531SLuke Browning return ret; 2072eb1b120SChristoph Hellwig } 208c6730ed4SJeremy Kerr 20927ec41d3SAndre Detsch spuctx_switch_state(ctx, SPU_UTIL_USER); 21091569531SLuke Browning ctx->ops->runcntl_write(ctx, runcntl); 21191569531SLuke Browning } 21227ec41d3SAndre Detsch 213aa45e256SChristoph Hellwig return 0; 214ce8ab854SArnd Bergmann } 215ce8ab854SArnd Bergmann 216aa45e256SChristoph Hellwig static int spu_run_fini(struct spu_context *ctx, u32 *npc, 217ce8ab854SArnd Bergmann u32 *status) 218ce8ab854SArnd Bergmann { 219ce8ab854SArnd Bergmann int ret = 0; 220ce8ab854SArnd Bergmann 221ce8ab854SArnd Bergmann *status = ctx->ops->status_read(ctx); 222ce8ab854SArnd Bergmann *npc = ctx->ops->npc_read(ctx); 22327ec41d3SAndre Detsch 22427ec41d3SAndre Detsch spuctx_switch_state(ctx, SPU_UTIL_IDLE_LOADED); 225ce8ab854SArnd Bergmann spu_release(ctx); 226ce8ab854SArnd Bergmann 227ce8ab854SArnd Bergmann if (signal_pending(current)) 228ce8ab854SArnd Bergmann ret = -ERESTARTSYS; 2292ebb2477SMasato Noguchi 230ce8ab854SArnd Bergmann return ret; 231ce8ab854SArnd Bergmann } 232ce8ab854SArnd Bergmann 233aa45e256SChristoph Hellwig static int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc, 234ce8ab854SArnd Bergmann u32 *status) 235ce8ab854SArnd Bergmann { 236ce8ab854SArnd Bergmann int ret; 237ce8ab854SArnd Bergmann 238aa45e256SChristoph Hellwig ret = spu_run_fini(ctx, npc, status); 239aa45e256SChristoph Hellwig if (ret) 240ce8ab854SArnd Bergmann return ret; 241aa45e256SChristoph Hellwig 242aa45e256SChristoph Hellwig if (*status & (SPU_STATUS_STOPPED_BY_STOP | SPU_STATUS_STOPPED_BY_HALT)) 243ce8ab854SArnd Bergmann return *status; 244aa45e256SChristoph Hellwig 245aa45e256SChristoph Hellwig ret = spu_acquire_runnable(ctx, 0); 246aa45e256SChristoph Hellwig if (ret) 247ce8ab854SArnd Bergmann return ret; 248aa45e256SChristoph Hellwig 249ada83daaSAndre Detsch spuctx_switch_state(ctx, SPU_UTIL_USER); 250ce8ab854SArnd Bergmann return 0; 251ce8ab854SArnd Bergmann } 252ce8ab854SArnd Bergmann 2532dd14934SArnd Bergmann /* 2542dd14934SArnd Bergmann * SPU syscall restarting is tricky because we violate the basic 2552dd14934SArnd Bergmann * assumption that the signal handler is running on the interrupted 2562dd14934SArnd Bergmann * thread. Here instead, the handler runs on PowerPC user space code, 2572dd14934SArnd Bergmann * while the syscall was called from the SPU. 2582dd14934SArnd Bergmann * This means we can only do a very rough approximation of POSIX 2592dd14934SArnd Bergmann * signal semantics. 2602dd14934SArnd Bergmann */ 2611238819aSSebastian Siewior static int spu_handle_restartsys(struct spu_context *ctx, long *spu_ret, 2622dd14934SArnd Bergmann unsigned int *npc) 2632dd14934SArnd Bergmann { 2642dd14934SArnd Bergmann int ret; 2652dd14934SArnd Bergmann 2662dd14934SArnd Bergmann switch (*spu_ret) { 2672dd14934SArnd Bergmann case -ERESTARTSYS: 2682dd14934SArnd Bergmann case -ERESTARTNOINTR: 2692dd14934SArnd Bergmann /* 2702dd14934SArnd Bergmann * Enter the regular syscall restarting for 2712dd14934SArnd Bergmann * sys_spu_run, then restart the SPU syscall 2722dd14934SArnd Bergmann * callback. 2732dd14934SArnd Bergmann */ 2742dd14934SArnd Bergmann *npc -= 8; 2752dd14934SArnd Bergmann ret = -ERESTARTSYS; 2762dd14934SArnd Bergmann break; 2772dd14934SArnd Bergmann case -ERESTARTNOHAND: 2782dd14934SArnd Bergmann case -ERESTART_RESTARTBLOCK: 2792dd14934SArnd Bergmann /* 2802dd14934SArnd Bergmann * Restart block is too hard for now, just return -EINTR 2812dd14934SArnd Bergmann * to the SPU. 2822dd14934SArnd Bergmann * ERESTARTNOHAND comes from sys_pause, we also return 2832dd14934SArnd Bergmann * -EINTR from there. 2842dd14934SArnd Bergmann * Assume that we need to be restarted ourselves though. 2852dd14934SArnd Bergmann */ 2862dd14934SArnd Bergmann *spu_ret = -EINTR; 2872dd14934SArnd Bergmann ret = -ERESTARTSYS; 2882dd14934SArnd Bergmann break; 2892dd14934SArnd Bergmann default: 2902dd14934SArnd Bergmann printk(KERN_WARNING "%s: unexpected return code %ld\n", 2912dd14934SArnd Bergmann __FUNCTION__, *spu_ret); 2922dd14934SArnd Bergmann ret = 0; 2932dd14934SArnd Bergmann } 2942dd14934SArnd Bergmann return ret; 2952dd14934SArnd Bergmann } 2962dd14934SArnd Bergmann 2971238819aSSebastian Siewior static int spu_process_callback(struct spu_context *ctx) 2982dd14934SArnd Bergmann { 2992dd14934SArnd Bergmann struct spu_syscall_block s; 3002dd14934SArnd Bergmann u32 ls_pointer, npc; 3019e2fe2ceSAkinobu Mita void __iomem *ls; 3022dd14934SArnd Bergmann long spu_ret; 3032dd14934SArnd Bergmann int ret; 3042dd14934SArnd Bergmann 3052dd14934SArnd Bergmann /* get syscall block from local store */ 3069e2fe2ceSAkinobu Mita npc = ctx->ops->npc_read(ctx) & ~3; 3079e2fe2ceSAkinobu Mita ls = (void __iomem *)ctx->ops->get_ls(ctx); 3089e2fe2ceSAkinobu Mita ls_pointer = in_be32(ls + npc); 3092dd14934SArnd Bergmann if (ls_pointer > (LS_SIZE - sizeof(s))) 3102dd14934SArnd Bergmann return -EFAULT; 3119e2fe2ceSAkinobu Mita memcpy_fromio(&s, ls + ls_pointer, sizeof(s)); 3122dd14934SArnd Bergmann 3132dd14934SArnd Bergmann /* do actual syscall without pinning the spu */ 3142dd14934SArnd Bergmann ret = 0; 3152dd14934SArnd Bergmann spu_ret = -ENOSYS; 3162dd14934SArnd Bergmann npc += 4; 3172dd14934SArnd Bergmann 3182dd14934SArnd Bergmann if (s.nr_ret < __NR_syscalls) { 3192dd14934SArnd Bergmann spu_release(ctx); 3202dd14934SArnd Bergmann /* do actual system call from here */ 3212dd14934SArnd Bergmann spu_ret = spu_sys_callback(&s); 3222dd14934SArnd Bergmann if (spu_ret <= -ERESTARTSYS) { 3232dd14934SArnd Bergmann ret = spu_handle_restartsys(ctx, &spu_ret, &npc); 3242dd14934SArnd Bergmann } 3252dd14934SArnd Bergmann spu_acquire(ctx); 3262dd14934SArnd Bergmann if (ret == -ERESTARTSYS) 3272dd14934SArnd Bergmann return ret; 3282dd14934SArnd Bergmann } 3292dd14934SArnd Bergmann 3302dd14934SArnd Bergmann /* write result, jump over indirect pointer */ 3319e2fe2ceSAkinobu Mita memcpy_toio(ls + ls_pointer, &spu_ret, sizeof(spu_ret)); 3322dd14934SArnd Bergmann ctx->ops->npc_write(ctx, npc); 3332dd14934SArnd Bergmann ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE); 3342dd14934SArnd Bergmann return ret; 3352dd14934SArnd Bergmann } 3362dd14934SArnd Bergmann 33750af32a9SJeremy Kerr long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *event) 338ce8ab854SArnd Bergmann { 339ce8ab854SArnd Bergmann int ret; 34036aaccc1SBob Nelson struct spu *spu; 3419add11daSArnd Bergmann u32 status; 342ce8ab854SArnd Bergmann 343e45d48a3SChristoph Hellwig if (mutex_lock_interruptible(&ctx->run_mutex)) 344ce8ab854SArnd Bergmann return -ERESTARTSYS; 345ce8ab854SArnd Bergmann 346c25620d7SMasato Noguchi spu_enable_spu(ctx); 3479add11daSArnd Bergmann ctx->event_return = 0; 348aa45e256SChristoph Hellwig 3492cf2b3b4SChristoph Hellwig spu_acquire(ctx); 3502cf2b3b4SChristoph Hellwig 3512cf2b3b4SChristoph Hellwig spu_update_sched_info(ctx); 352aa45e256SChristoph Hellwig 353aa45e256SChristoph Hellwig ret = spu_run_init(ctx, npc); 354aa45e256SChristoph Hellwig if (ret) { 355aa45e256SChristoph Hellwig spu_release(ctx); 356ce8ab854SArnd Bergmann goto out; 357aa45e256SChristoph Hellwig } 358ce8ab854SArnd Bergmann 359ce8ab854SArnd Bergmann do { 3609add11daSArnd Bergmann ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, &status)); 361ce8ab854SArnd Bergmann if (unlikely(ret)) 362ce8ab854SArnd Bergmann break; 36336aaccc1SBob Nelson spu = ctx->spu; 36436aaccc1SBob Nelson if (unlikely(test_and_clear_bit(SPU_SCHED_NOTIFY_ACTIVE, 36536aaccc1SBob Nelson &ctx->sched_flags))) { 36636aaccc1SBob Nelson if (!(status & SPU_STATUS_STOPPED_BY_STOP)) { 36736aaccc1SBob Nelson spu_switch_notify(spu, ctx); 36836aaccc1SBob Nelson continue; 36936aaccc1SBob Nelson } 37036aaccc1SBob Nelson } 37127ec41d3SAndre Detsch 37227ec41d3SAndre Detsch spuctx_switch_state(ctx, SPU_UTIL_SYSTEM); 37327ec41d3SAndre Detsch 3749add11daSArnd Bergmann if ((status & SPU_STATUS_STOPPED_BY_STOP) && 3759add11daSArnd Bergmann (status >> SPU_STOP_STATUS_SHIFT == 0x2104)) { 3762dd14934SArnd Bergmann ret = spu_process_callback(ctx); 3772dd14934SArnd Bergmann if (ret) 3782dd14934SArnd Bergmann break; 3799add11daSArnd Bergmann status &= ~SPU_STATUS_STOPPED_BY_STOP; 3802dd14934SArnd Bergmann } 38157dace23SArnd Bergmann ret = spufs_handle_class1(ctx); 38257dace23SArnd Bergmann if (ret) 38357dace23SArnd Bergmann break; 38457dace23SArnd Bergmann 385d6ad39bcSJeremy Kerr ret = spufs_handle_class0(ctx); 386d6ad39bcSJeremy Kerr if (ret) 387d6ad39bcSJeremy Kerr break; 388d6ad39bcSJeremy Kerr 389ce8ab854SArnd Bergmann if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) { 3909add11daSArnd Bergmann ret = spu_reacquire_runnable(ctx, npc, &status); 39137901802SChristoph Hellwig if (ret) 3922ebb2477SMasato Noguchi goto out2; 393ce8ab854SArnd Bergmann continue; 394ce8ab854SArnd Bergmann } 395d6ad39bcSJeremy Kerr 396d6ad39bcSJeremy Kerr if (signal_pending(current)) 397d6ad39bcSJeremy Kerr ret = -ERESTARTSYS; 398d6ad39bcSJeremy Kerr 399ce8ab854SArnd Bergmann 4009add11daSArnd Bergmann } while (!ret && !(status & (SPU_STATUS_STOPPED_BY_STOP | 40105169237SBenjamin Herrenschmidt SPU_STATUS_STOPPED_BY_HALT | 40205169237SBenjamin Herrenschmidt SPU_STATUS_SINGLE_STEP))); 403ce8ab854SArnd Bergmann 404e9f8a0b6SChristoph Hellwig if ((status & SPU_STATUS_STOPPED_BY_STOP) && 405fe2f896dSChristoph Hellwig (((status >> SPU_STOP_STATUS_SHIFT) & 0x3f00) == 0x2100) && 406fe2f896dSChristoph Hellwig (ctx->state == SPU_STATE_RUNNABLE)) 407e9f8a0b6SChristoph Hellwig ctx->stats.libassist++; 408e9f8a0b6SChristoph Hellwig 40927ec41d3SAndre Detsch 410c25620d7SMasato Noguchi spu_disable_spu(ctx); 4119add11daSArnd Bergmann ret = spu_run_fini(ctx, npc, &status); 412ce8ab854SArnd Bergmann spu_yield(ctx); 413ce8ab854SArnd Bergmann 4142ebb2477SMasato Noguchi out2: 4152ebb2477SMasato Noguchi if ((ret == 0) || 4162ebb2477SMasato Noguchi ((ret == -ERESTARTSYS) && 4172ebb2477SMasato Noguchi ((status & SPU_STATUS_STOPPED_BY_HALT) || 41805169237SBenjamin Herrenschmidt (status & SPU_STATUS_SINGLE_STEP) || 4192ebb2477SMasato Noguchi ((status & SPU_STATUS_STOPPED_BY_STOP) && 4202ebb2477SMasato Noguchi (status >> SPU_STOP_STATUS_SHIFT != 0x2104))))) 4212ebb2477SMasato Noguchi ret = status; 4222ebb2477SMasato Noguchi 42305169237SBenjamin Herrenschmidt /* Note: we don't need to force_sig SIGTRAP on single-step 42405169237SBenjamin Herrenschmidt * since we have TIF_SINGLESTEP set, thus the kernel will do 42505169237SBenjamin Herrenschmidt * it upon return from the syscall anyawy 42605169237SBenjamin Herrenschmidt */ 4272ebb2477SMasato Noguchi if ((status & SPU_STATUS_STOPPED_BY_STOP) 4282ebb2477SMasato Noguchi && (status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) { 4292ebb2477SMasato Noguchi force_sig(SIGTRAP, current); 4302ebb2477SMasato Noguchi ret = -ERESTARTSYS; 4312ebb2477SMasato Noguchi } 4322ebb2477SMasato Noguchi 433ce8ab854SArnd Bergmann out: 4349add11daSArnd Bergmann *event = ctx->event_return; 435e45d48a3SChristoph Hellwig mutex_unlock(&ctx->run_mutex); 436ce8ab854SArnd Bergmann return ret; 437ce8ab854SArnd Bergmann } 438