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 44e65c2f6fSLuke Browning int spu_stopped(struct spu_context *ctx, u32 *stat) 45ce8ab854SArnd Bergmann { 46e65c2f6fSLuke Browning u64 dsisr; 47e65c2f6fSLuke Browning u32 stopped; 48ce8ab854SArnd Bergmann 49ce8ab854SArnd Bergmann *stat = ctx->ops->status_read(ctx); 5036aaccc1SBob Nelson 51e65c2f6fSLuke Browning if (test_bit(SPU_SCHED_NOTIFY_ACTIVE, &ctx->sched_flags)) 5236aaccc1SBob Nelson return 1; 53e65c2f6fSLuke Browning 54e65c2f6fSLuke Browning stopped = SPU_STATUS_INVALID_INSTR | SPU_STATUS_SINGLE_STEP | 55e65c2f6fSLuke Browning SPU_STATUS_STOPPED_BY_HALT | SPU_STATUS_STOPPED_BY_STOP; 5685687ff2SLuke Browning if (!(*stat & SPU_STATUS_RUNNING) && (*stat & stopped)) 57e65c2f6fSLuke Browning return 1; 58e65c2f6fSLuke Browning 59e65c2f6fSLuke Browning dsisr = ctx->csa.dsisr; 60e65c2f6fSLuke Browning if (dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED)) 61e65c2f6fSLuke Browning return 1; 62e65c2f6fSLuke Browning 63e65c2f6fSLuke Browning if (ctx->csa.class_0_pending) 64e65c2f6fSLuke Browning return 1; 65e65c2f6fSLuke Browning 66e65c2f6fSLuke Browning return 0; 67ce8ab854SArnd Bergmann } 68ce8ab854SArnd Bergmann 69c6730ed4SJeremy Kerr static int spu_setup_isolated(struct spu_context *ctx) 70c6730ed4SJeremy Kerr { 71c6730ed4SJeremy Kerr int ret; 72c6730ed4SJeremy Kerr u64 __iomem *mfc_cntl; 73c6730ed4SJeremy Kerr u64 sr1; 74c6730ed4SJeremy Kerr u32 status; 75c6730ed4SJeremy Kerr unsigned long timeout; 76c6730ed4SJeremy Kerr const u32 status_loading = SPU_STATUS_RUNNING 77c6730ed4SJeremy Kerr | SPU_STATUS_ISOLATED_STATE | SPU_STATUS_ISOLATED_LOAD_STATUS; 78c6730ed4SJeremy Kerr 797ec18ab9SChristoph Hellwig ret = -ENODEV; 80c6730ed4SJeremy Kerr if (!isolated_loader) 81c6730ed4SJeremy Kerr goto out; 82c6730ed4SJeremy Kerr 837ec18ab9SChristoph Hellwig /* 847ec18ab9SChristoph Hellwig * We need to exclude userspace access to the context. 857ec18ab9SChristoph Hellwig * 867ec18ab9SChristoph Hellwig * To protect against memory access we invalidate all ptes 877ec18ab9SChristoph Hellwig * and make sure the pagefault handlers block on the mutex. 887ec18ab9SChristoph Hellwig */ 897ec18ab9SChristoph Hellwig spu_unmap_mappings(ctx); 907ec18ab9SChristoph Hellwig 91c6730ed4SJeremy Kerr mfc_cntl = &ctx->spu->priv2->mfc_control_RW; 92c6730ed4SJeremy Kerr 93c6730ed4SJeremy Kerr /* purge the MFC DMA queue to ensure no spurious accesses before we 94c6730ed4SJeremy Kerr * enter kernel mode */ 95c6730ed4SJeremy Kerr timeout = jiffies + HZ; 96c6730ed4SJeremy Kerr out_be64(mfc_cntl, MFC_CNTL_PURGE_DMA_REQUEST); 97c6730ed4SJeremy Kerr while ((in_be64(mfc_cntl) & MFC_CNTL_PURGE_DMA_STATUS_MASK) 98c6730ed4SJeremy Kerr != MFC_CNTL_PURGE_DMA_COMPLETE) { 99c6730ed4SJeremy Kerr if (time_after(jiffies, timeout)) { 100c6730ed4SJeremy Kerr printk(KERN_ERR "%s: timeout flushing MFC DMA queue\n", 101c6730ed4SJeremy Kerr __FUNCTION__); 102c6730ed4SJeremy Kerr ret = -EIO; 1037ec18ab9SChristoph Hellwig goto out; 104c6730ed4SJeremy Kerr } 105c6730ed4SJeremy Kerr cond_resched(); 106c6730ed4SJeremy Kerr } 107c6730ed4SJeremy Kerr 108c6730ed4SJeremy Kerr /* put the SPE in kernel mode to allow access to the loader */ 109c6730ed4SJeremy Kerr sr1 = spu_mfc_sr1_get(ctx->spu); 110c6730ed4SJeremy Kerr sr1 &= ~MFC_STATE1_PROBLEM_STATE_MASK; 111c6730ed4SJeremy Kerr spu_mfc_sr1_set(ctx->spu, sr1); 112c6730ed4SJeremy Kerr 113c6730ed4SJeremy Kerr /* start the loader */ 114c6730ed4SJeremy Kerr ctx->ops->signal1_write(ctx, (unsigned long)isolated_loader >> 32); 115c6730ed4SJeremy Kerr ctx->ops->signal2_write(ctx, 116c6730ed4SJeremy Kerr (unsigned long)isolated_loader & 0xffffffff); 117c6730ed4SJeremy Kerr 118c6730ed4SJeremy Kerr ctx->ops->runcntl_write(ctx, 119c6730ed4SJeremy Kerr SPU_RUNCNTL_RUNNABLE | SPU_RUNCNTL_ISOLATE); 120c6730ed4SJeremy Kerr 121c6730ed4SJeremy Kerr ret = 0; 122c6730ed4SJeremy Kerr timeout = jiffies + HZ; 123c6730ed4SJeremy Kerr while (((status = ctx->ops->status_read(ctx)) & status_loading) == 124c6730ed4SJeremy Kerr status_loading) { 125c6730ed4SJeremy Kerr if (time_after(jiffies, timeout)) { 126c6730ed4SJeremy Kerr printk(KERN_ERR "%s: timeout waiting for loader\n", 127c6730ed4SJeremy Kerr __FUNCTION__); 128c6730ed4SJeremy Kerr ret = -EIO; 129c6730ed4SJeremy Kerr goto out_drop_priv; 130c6730ed4SJeremy Kerr } 131c6730ed4SJeremy Kerr cond_resched(); 132c6730ed4SJeremy Kerr } 133c6730ed4SJeremy Kerr 134c6730ed4SJeremy Kerr if (!(status & SPU_STATUS_RUNNING)) { 135c6730ed4SJeremy Kerr /* If isolated LOAD has failed: run SPU, we will get a stop-and 136c6730ed4SJeremy Kerr * signal later. */ 137c6730ed4SJeremy Kerr pr_debug("%s: isolated LOAD failed\n", __FUNCTION__); 138c6730ed4SJeremy Kerr ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE); 139c6730ed4SJeremy Kerr ret = -EACCES; 1407ec18ab9SChristoph Hellwig goto out_drop_priv; 1417ec18ab9SChristoph Hellwig } 142c6730ed4SJeremy Kerr 1437ec18ab9SChristoph Hellwig if (!(status & SPU_STATUS_ISOLATED_STATE)) { 144c6730ed4SJeremy Kerr /* This isn't allowed by the CBEA, but check anyway */ 145c6730ed4SJeremy Kerr pr_debug("%s: SPU fell out of isolated mode?\n", __FUNCTION__); 146c6730ed4SJeremy Kerr ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_STOP); 147c6730ed4SJeremy Kerr ret = -EINVAL; 1487ec18ab9SChristoph Hellwig goto out_drop_priv; 149c6730ed4SJeremy Kerr } 150c6730ed4SJeremy Kerr 151c6730ed4SJeremy Kerr out_drop_priv: 152c6730ed4SJeremy Kerr /* Finished accessing the loader. Drop kernel mode */ 153c6730ed4SJeremy Kerr sr1 |= MFC_STATE1_PROBLEM_STATE_MASK; 154c6730ed4SJeremy Kerr spu_mfc_sr1_set(ctx->spu, sr1); 155c6730ed4SJeremy Kerr 156c6730ed4SJeremy Kerr out: 157c6730ed4SJeremy Kerr return ret; 158c6730ed4SJeremy Kerr } 159c6730ed4SJeremy Kerr 160aa45e256SChristoph Hellwig static int spu_run_init(struct spu_context *ctx, u32 *npc) 161ce8ab854SArnd Bergmann { 162e65c2f6fSLuke Browning unsigned long runcntl = SPU_RUNCNTL_RUNNABLE; 16391569531SLuke Browning int ret; 164cc210b3eSLuke Browning 16527ec41d3SAndre Detsch spuctx_switch_state(ctx, SPU_UTIL_SYSTEM); 16627ec41d3SAndre Detsch 16791569531SLuke Browning /* 168e65c2f6fSLuke Browning * NOSCHED is synchronous scheduling with respect to the caller. 169e65c2f6fSLuke Browning * The caller waits for the context to be loaded. 17091569531SLuke Browning */ 171e65c2f6fSLuke Browning if (ctx->flags & SPU_CREATE_NOSCHED) { 17291569531SLuke Browning if (ctx->state == SPU_STATE_SAVED) { 17391569531SLuke Browning ret = spu_activate(ctx, 0); 174c6730ed4SJeremy Kerr if (ret) 175ce8ab854SArnd Bergmann return ret; 1760afacde3Sarnd@arndb.de } 177e65c2f6fSLuke Browning } 178c6730ed4SJeremy Kerr 179e65c2f6fSLuke Browning /* 180e65c2f6fSLuke Browning * Apply special setup as required. 181e65c2f6fSLuke Browning */ 182e65c2f6fSLuke Browning if (ctx->flags & SPU_CREATE_ISOLATE) { 18391569531SLuke Browning if (!(ctx->ops->status_read(ctx) & SPU_STATUS_ISOLATED_STATE)) { 18491569531SLuke Browning ret = spu_setup_isolated(ctx); 18591569531SLuke Browning if (ret) 18691569531SLuke Browning return ret; 18791569531SLuke Browning } 18891569531SLuke Browning 18991569531SLuke Browning /* 19091569531SLuke Browning * If userspace has set the runcntrl register (eg, to 19191569531SLuke Browning * issue an isolated exit), we need to re-set it here 19291569531SLuke Browning */ 193c6730ed4SJeremy Kerr runcntl = ctx->ops->runcntl_read(ctx) & 194c6730ed4SJeremy Kerr (SPU_RUNCNTL_RUNNABLE | SPU_RUNCNTL_ISOLATE); 195c6730ed4SJeremy Kerr if (runcntl == 0) 196c6730ed4SJeremy Kerr runcntl = SPU_RUNCNTL_RUNNABLE; 197e65c2f6fSLuke Browning } 19891569531SLuke Browning 199e65c2f6fSLuke Browning if (ctx->flags & SPU_CREATE_NOSCHED) { 20091569531SLuke Browning spuctx_switch_state(ctx, SPU_UTIL_USER); 20191569531SLuke Browning ctx->ops->runcntl_write(ctx, runcntl); 2022eb1b120SChristoph Hellwig } else { 203cc210b3eSLuke Browning unsigned long privcntl; 204cc210b3eSLuke Browning 20505169237SBenjamin Herrenschmidt if (test_thread_flag(TIF_SINGLESTEP)) 206cc210b3eSLuke Browning privcntl = SPU_PRIVCNTL_MODE_SINGLE_STEP; 207cc210b3eSLuke Browning else 208cc210b3eSLuke Browning privcntl = SPU_PRIVCNTL_MODE_NORMAL; 209cc210b3eSLuke Browning 210cc210b3eSLuke Browning ctx->ops->npc_write(ctx, *npc); 211cc210b3eSLuke Browning ctx->ops->privcntl_write(ctx, privcntl); 212e65c2f6fSLuke Browning ctx->ops->runcntl_write(ctx, runcntl); 21391569531SLuke Browning 21491569531SLuke Browning if (ctx->state == SPU_STATE_SAVED) { 21591569531SLuke Browning ret = spu_activate(ctx, 0); 21691569531SLuke Browning if (ret) 21791569531SLuke Browning return ret; 218e65c2f6fSLuke Browning } else { 21927ec41d3SAndre Detsch spuctx_switch_state(ctx, SPU_UTIL_USER); 220e65c2f6fSLuke Browning } 22191569531SLuke Browning } 22227ec41d3SAndre Detsch 223aa45e256SChristoph Hellwig return 0; 224ce8ab854SArnd Bergmann } 225ce8ab854SArnd Bergmann 226aa45e256SChristoph Hellwig static int spu_run_fini(struct spu_context *ctx, u32 *npc, 227ce8ab854SArnd Bergmann u32 *status) 228ce8ab854SArnd Bergmann { 229ce8ab854SArnd Bergmann int ret = 0; 230ce8ab854SArnd Bergmann 231e65c2f6fSLuke Browning spu_del_from_rq(ctx); 232e65c2f6fSLuke Browning 233ce8ab854SArnd Bergmann *status = ctx->ops->status_read(ctx); 234ce8ab854SArnd Bergmann *npc = ctx->ops->npc_read(ctx); 23527ec41d3SAndre Detsch 23627ec41d3SAndre Detsch spuctx_switch_state(ctx, SPU_UTIL_IDLE_LOADED); 237ce8ab854SArnd Bergmann spu_release(ctx); 238ce8ab854SArnd Bergmann 239ce8ab854SArnd Bergmann if (signal_pending(current)) 240ce8ab854SArnd Bergmann ret = -ERESTARTSYS; 2412ebb2477SMasato Noguchi 242ce8ab854SArnd Bergmann return ret; 243ce8ab854SArnd Bergmann } 244ce8ab854SArnd Bergmann 2452dd14934SArnd Bergmann /* 2462dd14934SArnd Bergmann * SPU syscall restarting is tricky because we violate the basic 2472dd14934SArnd Bergmann * assumption that the signal handler is running on the interrupted 2482dd14934SArnd Bergmann * thread. Here instead, the handler runs on PowerPC user space code, 2492dd14934SArnd Bergmann * while the syscall was called from the SPU. 2502dd14934SArnd Bergmann * This means we can only do a very rough approximation of POSIX 2512dd14934SArnd Bergmann * signal semantics. 2522dd14934SArnd Bergmann */ 2531238819aSSebastian Siewior static int spu_handle_restartsys(struct spu_context *ctx, long *spu_ret, 2542dd14934SArnd Bergmann unsigned int *npc) 2552dd14934SArnd Bergmann { 2562dd14934SArnd Bergmann int ret; 2572dd14934SArnd Bergmann 2582dd14934SArnd Bergmann switch (*spu_ret) { 2592dd14934SArnd Bergmann case -ERESTARTSYS: 2602dd14934SArnd Bergmann case -ERESTARTNOINTR: 2612dd14934SArnd Bergmann /* 2622dd14934SArnd Bergmann * Enter the regular syscall restarting for 2632dd14934SArnd Bergmann * sys_spu_run, then restart the SPU syscall 2642dd14934SArnd Bergmann * callback. 2652dd14934SArnd Bergmann */ 2662dd14934SArnd Bergmann *npc -= 8; 2672dd14934SArnd Bergmann ret = -ERESTARTSYS; 2682dd14934SArnd Bergmann break; 2692dd14934SArnd Bergmann case -ERESTARTNOHAND: 2702dd14934SArnd Bergmann case -ERESTART_RESTARTBLOCK: 2712dd14934SArnd Bergmann /* 2722dd14934SArnd Bergmann * Restart block is too hard for now, just return -EINTR 2732dd14934SArnd Bergmann * to the SPU. 2742dd14934SArnd Bergmann * ERESTARTNOHAND comes from sys_pause, we also return 2752dd14934SArnd Bergmann * -EINTR from there. 2762dd14934SArnd Bergmann * Assume that we need to be restarted ourselves though. 2772dd14934SArnd Bergmann */ 2782dd14934SArnd Bergmann *spu_ret = -EINTR; 2792dd14934SArnd Bergmann ret = -ERESTARTSYS; 2802dd14934SArnd Bergmann break; 2812dd14934SArnd Bergmann default: 2822dd14934SArnd Bergmann printk(KERN_WARNING "%s: unexpected return code %ld\n", 2832dd14934SArnd Bergmann __FUNCTION__, *spu_ret); 2842dd14934SArnd Bergmann ret = 0; 2852dd14934SArnd Bergmann } 2862dd14934SArnd Bergmann return ret; 2872dd14934SArnd Bergmann } 2882dd14934SArnd Bergmann 2891238819aSSebastian Siewior static int spu_process_callback(struct spu_context *ctx) 2902dd14934SArnd Bergmann { 2912dd14934SArnd Bergmann struct spu_syscall_block s; 2922dd14934SArnd Bergmann u32 ls_pointer, npc; 2939e2fe2ceSAkinobu Mita void __iomem *ls; 2942dd14934SArnd Bergmann long spu_ret; 295c9101bdbSChristoph Hellwig int ret, ret2; 2962dd14934SArnd Bergmann 2972dd14934SArnd Bergmann /* get syscall block from local store */ 2989e2fe2ceSAkinobu Mita npc = ctx->ops->npc_read(ctx) & ~3; 2999e2fe2ceSAkinobu Mita ls = (void __iomem *)ctx->ops->get_ls(ctx); 3009e2fe2ceSAkinobu Mita ls_pointer = in_be32(ls + npc); 3012dd14934SArnd Bergmann if (ls_pointer > (LS_SIZE - sizeof(s))) 3022dd14934SArnd Bergmann return -EFAULT; 3039e2fe2ceSAkinobu Mita memcpy_fromio(&s, ls + ls_pointer, sizeof(s)); 3042dd14934SArnd Bergmann 3052dd14934SArnd Bergmann /* do actual syscall without pinning the spu */ 3062dd14934SArnd Bergmann ret = 0; 3072dd14934SArnd Bergmann spu_ret = -ENOSYS; 3082dd14934SArnd Bergmann npc += 4; 3092dd14934SArnd Bergmann 3102dd14934SArnd Bergmann if (s.nr_ret < __NR_syscalls) { 3112dd14934SArnd Bergmann spu_release(ctx); 3122dd14934SArnd Bergmann /* do actual system call from here */ 3132dd14934SArnd Bergmann spu_ret = spu_sys_callback(&s); 3142dd14934SArnd Bergmann if (spu_ret <= -ERESTARTSYS) { 3152dd14934SArnd Bergmann ret = spu_handle_restartsys(ctx, &spu_ret, &npc); 3162dd14934SArnd Bergmann } 317c9101bdbSChristoph Hellwig ret2 = spu_acquire(ctx); 3182dd14934SArnd Bergmann if (ret == -ERESTARTSYS) 3192dd14934SArnd Bergmann return ret; 320c9101bdbSChristoph Hellwig if (ret2) 321c9101bdbSChristoph Hellwig return -EINTR; 3222dd14934SArnd Bergmann } 3232dd14934SArnd Bergmann 3242dd14934SArnd Bergmann /* write result, jump over indirect pointer */ 3259e2fe2ceSAkinobu Mita memcpy_toio(ls + ls_pointer, &spu_ret, sizeof(spu_ret)); 3262dd14934SArnd Bergmann ctx->ops->npc_write(ctx, npc); 3272dd14934SArnd Bergmann ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE); 3282dd14934SArnd Bergmann return ret; 3292dd14934SArnd Bergmann } 3302dd14934SArnd Bergmann 33150af32a9SJeremy Kerr long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *event) 332ce8ab854SArnd Bergmann { 333ce8ab854SArnd Bergmann int ret; 33436aaccc1SBob Nelson struct spu *spu; 3359add11daSArnd Bergmann u32 status; 336ce8ab854SArnd Bergmann 337e45d48a3SChristoph Hellwig if (mutex_lock_interruptible(&ctx->run_mutex)) 338ce8ab854SArnd Bergmann return -ERESTARTSYS; 339ce8ab854SArnd Bergmann 340c25620d7SMasato Noguchi spu_enable_spu(ctx); 3419add11daSArnd Bergmann ctx->event_return = 0; 342aa45e256SChristoph Hellwig 343c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 344c9101bdbSChristoph Hellwig if (ret) 345c9101bdbSChristoph Hellwig goto out_unlock; 3462cf2b3b4SChristoph Hellwig 3472cf2b3b4SChristoph Hellwig spu_update_sched_info(ctx); 348aa45e256SChristoph Hellwig 349aa45e256SChristoph Hellwig ret = spu_run_init(ctx, npc); 350aa45e256SChristoph Hellwig if (ret) { 351aa45e256SChristoph Hellwig spu_release(ctx); 352ce8ab854SArnd Bergmann goto out; 353aa45e256SChristoph Hellwig } 354ce8ab854SArnd Bergmann 355ce8ab854SArnd Bergmann do { 3569add11daSArnd Bergmann ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, &status)); 357eebead5bSChristoph Hellwig if (unlikely(ret)) { 358eebead5bSChristoph Hellwig /* 359eebead5bSChristoph Hellwig * This is nasty: we need the state_mutex for all the 360eebead5bSChristoph Hellwig * bookkeeping even if the syscall was interrupted by 361eebead5bSChristoph Hellwig * a signal. ewww. 362eebead5bSChristoph Hellwig */ 363eebead5bSChristoph Hellwig mutex_lock(&ctx->state_mutex); 364ce8ab854SArnd Bergmann break; 365eebead5bSChristoph Hellwig } 36636aaccc1SBob Nelson spu = ctx->spu; 36736aaccc1SBob Nelson if (unlikely(test_and_clear_bit(SPU_SCHED_NOTIFY_ACTIVE, 36836aaccc1SBob Nelson &ctx->sched_flags))) { 36936aaccc1SBob Nelson if (!(status & SPU_STATUS_STOPPED_BY_STOP)) { 37036aaccc1SBob Nelson spu_switch_notify(spu, ctx); 37136aaccc1SBob Nelson continue; 37236aaccc1SBob Nelson } 37336aaccc1SBob Nelson } 37427ec41d3SAndre Detsch 37527ec41d3SAndre Detsch spuctx_switch_state(ctx, SPU_UTIL_SYSTEM); 37627ec41d3SAndre Detsch 3779add11daSArnd Bergmann if ((status & SPU_STATUS_STOPPED_BY_STOP) && 3789add11daSArnd Bergmann (status >> SPU_STOP_STATUS_SHIFT == 0x2104)) { 3792dd14934SArnd Bergmann ret = spu_process_callback(ctx); 3802dd14934SArnd Bergmann if (ret) 3812dd14934SArnd Bergmann break; 3829add11daSArnd Bergmann status &= ~SPU_STATUS_STOPPED_BY_STOP; 3832dd14934SArnd Bergmann } 38457dace23SArnd Bergmann ret = spufs_handle_class1(ctx); 38557dace23SArnd Bergmann if (ret) 38657dace23SArnd Bergmann break; 38757dace23SArnd Bergmann 388d6ad39bcSJeremy Kerr ret = spufs_handle_class0(ctx); 389d6ad39bcSJeremy Kerr if (ret) 390d6ad39bcSJeremy Kerr break; 391d6ad39bcSJeremy Kerr 392d6ad39bcSJeremy Kerr if (signal_pending(current)) 393d6ad39bcSJeremy Kerr ret = -ERESTARTSYS; 3949add11daSArnd Bergmann } while (!ret && !(status & (SPU_STATUS_STOPPED_BY_STOP | 39505169237SBenjamin Herrenschmidt SPU_STATUS_STOPPED_BY_HALT | 39605169237SBenjamin Herrenschmidt SPU_STATUS_SINGLE_STEP))); 397ce8ab854SArnd Bergmann 398c25620d7SMasato Noguchi spu_disable_spu(ctx); 3999add11daSArnd Bergmann ret = spu_run_fini(ctx, npc, &status); 400ce8ab854SArnd Bergmann spu_yield(ctx); 401ce8ab854SArnd Bergmann 402e66686b4SLuke Browning if ((status & SPU_STATUS_STOPPED_BY_STOP) && 403e66686b4SLuke Browning (((status >> SPU_STOP_STATUS_SHIFT) & 0x3f00) == 0x2100)) 404e66686b4SLuke Browning ctx->stats.libassist++; 405e66686b4SLuke Browning 4062ebb2477SMasato Noguchi if ((ret == 0) || 4072ebb2477SMasato Noguchi ((ret == -ERESTARTSYS) && 4082ebb2477SMasato Noguchi ((status & SPU_STATUS_STOPPED_BY_HALT) || 40905169237SBenjamin Herrenschmidt (status & SPU_STATUS_SINGLE_STEP) || 4102ebb2477SMasato Noguchi ((status & SPU_STATUS_STOPPED_BY_STOP) && 4112ebb2477SMasato Noguchi (status >> SPU_STOP_STATUS_SHIFT != 0x2104))))) 4122ebb2477SMasato Noguchi ret = status; 4132ebb2477SMasato Noguchi 41405169237SBenjamin Herrenschmidt /* Note: we don't need to force_sig SIGTRAP on single-step 41505169237SBenjamin Herrenschmidt * since we have TIF_SINGLESTEP set, thus the kernel will do 41605169237SBenjamin Herrenschmidt * it upon return from the syscall anyawy 41705169237SBenjamin Herrenschmidt */ 41860cf54dbSJeremy Kerr if (unlikely(status & SPU_STATUS_SINGLE_STEP)) 41960cf54dbSJeremy Kerr ret = -ERESTARTSYS; 42060cf54dbSJeremy Kerr 42160cf54dbSJeremy Kerr else if (unlikely((status & SPU_STATUS_STOPPED_BY_STOP) 42260cf54dbSJeremy Kerr && (status >> SPU_STOP_STATUS_SHIFT) == 0x3fff)) { 4232ebb2477SMasato Noguchi force_sig(SIGTRAP, current); 4242ebb2477SMasato Noguchi ret = -ERESTARTSYS; 4252ebb2477SMasato Noguchi } 4262ebb2477SMasato Noguchi 427ce8ab854SArnd Bergmann out: 4289add11daSArnd Bergmann *event = ctx->event_return; 429c9101bdbSChristoph Hellwig out_unlock: 430e45d48a3SChristoph Hellwig mutex_unlock(&ctx->run_mutex); 431ce8ab854SArnd Bergmann return ret; 432ce8ab854SArnd Bergmann } 433