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", 101e48b1b45SHarvey Harrison __func__); 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", 127e48b1b45SHarvey Harrison __func__); 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. */ 137e48b1b45SHarvey Harrison pr_debug("%s: isolated LOAD failed\n", __func__); 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 */ 145e48b1b45SHarvey Harrison pr_debug("%s: SPU fell out of isolated mode?\n", __func__); 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 223ce7c191bSJeremy Kerr set_bit(SPU_SCHED_SPU_RUN, &ctx->sched_flags); 224aa45e256SChristoph Hellwig return 0; 225ce8ab854SArnd Bergmann } 226ce8ab854SArnd Bergmann 227aa45e256SChristoph Hellwig static int spu_run_fini(struct spu_context *ctx, u32 *npc, 228ce8ab854SArnd Bergmann u32 *status) 229ce8ab854SArnd Bergmann { 230ce8ab854SArnd Bergmann int ret = 0; 231ce8ab854SArnd Bergmann 232e65c2f6fSLuke Browning spu_del_from_rq(ctx); 233e65c2f6fSLuke Browning 234ce8ab854SArnd Bergmann *status = ctx->ops->status_read(ctx); 235ce8ab854SArnd Bergmann *npc = ctx->ops->npc_read(ctx); 23627ec41d3SAndre Detsch 23727ec41d3SAndre Detsch spuctx_switch_state(ctx, SPU_UTIL_IDLE_LOADED); 238ce7c191bSJeremy Kerr clear_bit(SPU_SCHED_SPU_RUN, &ctx->sched_flags); 239ce8ab854SArnd Bergmann spu_release(ctx); 240ce8ab854SArnd Bergmann 241ce8ab854SArnd Bergmann if (signal_pending(current)) 242ce8ab854SArnd Bergmann ret = -ERESTARTSYS; 2432ebb2477SMasato Noguchi 244ce8ab854SArnd Bergmann return ret; 245ce8ab854SArnd Bergmann } 246ce8ab854SArnd Bergmann 2472dd14934SArnd Bergmann /* 2482dd14934SArnd Bergmann * SPU syscall restarting is tricky because we violate the basic 2492dd14934SArnd Bergmann * assumption that the signal handler is running on the interrupted 2502dd14934SArnd Bergmann * thread. Here instead, the handler runs on PowerPC user space code, 2512dd14934SArnd Bergmann * while the syscall was called from the SPU. 2522dd14934SArnd Bergmann * This means we can only do a very rough approximation of POSIX 2532dd14934SArnd Bergmann * signal semantics. 2542dd14934SArnd Bergmann */ 2551238819aSSebastian Siewior static int spu_handle_restartsys(struct spu_context *ctx, long *spu_ret, 2562dd14934SArnd Bergmann unsigned int *npc) 2572dd14934SArnd Bergmann { 2582dd14934SArnd Bergmann int ret; 2592dd14934SArnd Bergmann 2602dd14934SArnd Bergmann switch (*spu_ret) { 2612dd14934SArnd Bergmann case -ERESTARTSYS: 2622dd14934SArnd Bergmann case -ERESTARTNOINTR: 2632dd14934SArnd Bergmann /* 2642dd14934SArnd Bergmann * Enter the regular syscall restarting for 2652dd14934SArnd Bergmann * sys_spu_run, then restart the SPU syscall 2662dd14934SArnd Bergmann * callback. 2672dd14934SArnd Bergmann */ 2682dd14934SArnd Bergmann *npc -= 8; 2692dd14934SArnd Bergmann ret = -ERESTARTSYS; 2702dd14934SArnd Bergmann break; 2712dd14934SArnd Bergmann case -ERESTARTNOHAND: 2722dd14934SArnd Bergmann case -ERESTART_RESTARTBLOCK: 2732dd14934SArnd Bergmann /* 2742dd14934SArnd Bergmann * Restart block is too hard for now, just return -EINTR 2752dd14934SArnd Bergmann * to the SPU. 2762dd14934SArnd Bergmann * ERESTARTNOHAND comes from sys_pause, we also return 2772dd14934SArnd Bergmann * -EINTR from there. 2782dd14934SArnd Bergmann * Assume that we need to be restarted ourselves though. 2792dd14934SArnd Bergmann */ 2802dd14934SArnd Bergmann *spu_ret = -EINTR; 2812dd14934SArnd Bergmann ret = -ERESTARTSYS; 2822dd14934SArnd Bergmann break; 2832dd14934SArnd Bergmann default: 2842dd14934SArnd Bergmann printk(KERN_WARNING "%s: unexpected return code %ld\n", 285e48b1b45SHarvey Harrison __func__, *spu_ret); 2862dd14934SArnd Bergmann ret = 0; 2872dd14934SArnd Bergmann } 2882dd14934SArnd Bergmann return ret; 2892dd14934SArnd Bergmann } 2902dd14934SArnd Bergmann 2911238819aSSebastian Siewior static int spu_process_callback(struct spu_context *ctx) 2922dd14934SArnd Bergmann { 2932dd14934SArnd Bergmann struct spu_syscall_block s; 2942dd14934SArnd Bergmann u32 ls_pointer, npc; 2959e2fe2ceSAkinobu Mita void __iomem *ls; 2962dd14934SArnd Bergmann long spu_ret; 297c9101bdbSChristoph Hellwig int ret, ret2; 2982dd14934SArnd Bergmann 2992dd14934SArnd Bergmann /* get syscall block from local store */ 3009e2fe2ceSAkinobu Mita npc = ctx->ops->npc_read(ctx) & ~3; 3019e2fe2ceSAkinobu Mita ls = (void __iomem *)ctx->ops->get_ls(ctx); 3029e2fe2ceSAkinobu Mita ls_pointer = in_be32(ls + npc); 3032dd14934SArnd Bergmann if (ls_pointer > (LS_SIZE - sizeof(s))) 3042dd14934SArnd Bergmann return -EFAULT; 3059e2fe2ceSAkinobu Mita memcpy_fromio(&s, ls + ls_pointer, sizeof(s)); 3062dd14934SArnd Bergmann 3072dd14934SArnd Bergmann /* do actual syscall without pinning the spu */ 3082dd14934SArnd Bergmann ret = 0; 3092dd14934SArnd Bergmann spu_ret = -ENOSYS; 3102dd14934SArnd Bergmann npc += 4; 3112dd14934SArnd Bergmann 3122dd14934SArnd Bergmann if (s.nr_ret < __NR_syscalls) { 3132dd14934SArnd Bergmann spu_release(ctx); 3142dd14934SArnd Bergmann /* do actual system call from here */ 3152dd14934SArnd Bergmann spu_ret = spu_sys_callback(&s); 3162dd14934SArnd Bergmann if (spu_ret <= -ERESTARTSYS) { 3172dd14934SArnd Bergmann ret = spu_handle_restartsys(ctx, &spu_ret, &npc); 3182dd14934SArnd Bergmann } 319c9101bdbSChristoph Hellwig ret2 = spu_acquire(ctx); 3202dd14934SArnd Bergmann if (ret == -ERESTARTSYS) 3212dd14934SArnd Bergmann return ret; 322c9101bdbSChristoph Hellwig if (ret2) 323c9101bdbSChristoph Hellwig return -EINTR; 3242dd14934SArnd Bergmann } 3252dd14934SArnd Bergmann 3262dd14934SArnd Bergmann /* write result, jump over indirect pointer */ 3279e2fe2ceSAkinobu Mita memcpy_toio(ls + ls_pointer, &spu_ret, sizeof(spu_ret)); 3282dd14934SArnd Bergmann ctx->ops->npc_write(ctx, npc); 3292dd14934SArnd Bergmann ctx->ops->runcntl_write(ctx, SPU_RUNCNTL_RUNNABLE); 3302dd14934SArnd Bergmann return ret; 3312dd14934SArnd Bergmann } 3322dd14934SArnd Bergmann 33350af32a9SJeremy Kerr long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *event) 334ce8ab854SArnd Bergmann { 335ce8ab854SArnd Bergmann int ret; 33636aaccc1SBob Nelson struct spu *spu; 3379add11daSArnd Bergmann u32 status; 338ce8ab854SArnd Bergmann 339e45d48a3SChristoph Hellwig if (mutex_lock_interruptible(&ctx->run_mutex)) 340ce8ab854SArnd Bergmann return -ERESTARTSYS; 341ce8ab854SArnd Bergmann 342c25620d7SMasato Noguchi spu_enable_spu(ctx); 3439add11daSArnd Bergmann ctx->event_return = 0; 344aa45e256SChristoph Hellwig 345c9101bdbSChristoph Hellwig ret = spu_acquire(ctx); 346c9101bdbSChristoph Hellwig if (ret) 347c9101bdbSChristoph Hellwig goto out_unlock; 3482cf2b3b4SChristoph Hellwig 3492cf2b3b4SChristoph Hellwig spu_update_sched_info(ctx); 350aa45e256SChristoph Hellwig 351aa45e256SChristoph Hellwig ret = spu_run_init(ctx, npc); 352aa45e256SChristoph Hellwig if (ret) { 353aa45e256SChristoph Hellwig spu_release(ctx); 354ce8ab854SArnd Bergmann goto out; 355aa45e256SChristoph Hellwig } 356ce8ab854SArnd Bergmann 357ce8ab854SArnd Bergmann do { 3589add11daSArnd Bergmann ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, &status)); 359eebead5bSChristoph Hellwig if (unlikely(ret)) { 360eebead5bSChristoph Hellwig /* 361eebead5bSChristoph Hellwig * This is nasty: we need the state_mutex for all the 362eebead5bSChristoph Hellwig * bookkeeping even if the syscall was interrupted by 363eebead5bSChristoph Hellwig * a signal. ewww. 364eebead5bSChristoph Hellwig */ 365eebead5bSChristoph Hellwig mutex_lock(&ctx->state_mutex); 366ce8ab854SArnd Bergmann break; 367eebead5bSChristoph Hellwig } 36836aaccc1SBob Nelson spu = ctx->spu; 36936aaccc1SBob Nelson if (unlikely(test_and_clear_bit(SPU_SCHED_NOTIFY_ACTIVE, 37036aaccc1SBob Nelson &ctx->sched_flags))) { 37136aaccc1SBob Nelson if (!(status & SPU_STATUS_STOPPED_BY_STOP)) { 37236aaccc1SBob Nelson spu_switch_notify(spu, ctx); 37336aaccc1SBob Nelson continue; 37436aaccc1SBob Nelson } 37536aaccc1SBob Nelson } 37627ec41d3SAndre Detsch 37727ec41d3SAndre Detsch spuctx_switch_state(ctx, SPU_UTIL_SYSTEM); 37827ec41d3SAndre Detsch 3799add11daSArnd Bergmann if ((status & SPU_STATUS_STOPPED_BY_STOP) && 3809add11daSArnd Bergmann (status >> SPU_STOP_STATUS_SHIFT == 0x2104)) { 3812dd14934SArnd Bergmann ret = spu_process_callback(ctx); 3822dd14934SArnd Bergmann if (ret) 3832dd14934SArnd Bergmann break; 3849add11daSArnd Bergmann status &= ~SPU_STATUS_STOPPED_BY_STOP; 3852dd14934SArnd Bergmann } 38657dace23SArnd Bergmann ret = spufs_handle_class1(ctx); 38757dace23SArnd Bergmann if (ret) 38857dace23SArnd Bergmann break; 38957dace23SArnd Bergmann 390d6ad39bcSJeremy Kerr ret = spufs_handle_class0(ctx); 391d6ad39bcSJeremy Kerr if (ret) 392d6ad39bcSJeremy Kerr break; 393d6ad39bcSJeremy Kerr 394d6ad39bcSJeremy Kerr if (signal_pending(current)) 395d6ad39bcSJeremy Kerr ret = -ERESTARTSYS; 3969add11daSArnd Bergmann } while (!ret && !(status & (SPU_STATUS_STOPPED_BY_STOP | 39705169237SBenjamin Herrenschmidt SPU_STATUS_STOPPED_BY_HALT | 39805169237SBenjamin Herrenschmidt SPU_STATUS_SINGLE_STEP))); 399ce8ab854SArnd Bergmann 400c25620d7SMasato Noguchi spu_disable_spu(ctx); 4019add11daSArnd Bergmann ret = spu_run_fini(ctx, npc, &status); 402ce8ab854SArnd Bergmann spu_yield(ctx); 403ce8ab854SArnd Bergmann 404e66686b4SLuke Browning if ((status & SPU_STATUS_STOPPED_BY_STOP) && 405e66686b4SLuke Browning (((status >> SPU_STOP_STATUS_SHIFT) & 0x3f00) == 0x2100)) 406e66686b4SLuke Browning ctx->stats.libassist++; 407e66686b4SLuke Browning 4082ebb2477SMasato Noguchi if ((ret == 0) || 4092ebb2477SMasato Noguchi ((ret == -ERESTARTSYS) && 4102ebb2477SMasato Noguchi ((status & SPU_STATUS_STOPPED_BY_HALT) || 41105169237SBenjamin Herrenschmidt (status & SPU_STATUS_SINGLE_STEP) || 4122ebb2477SMasato Noguchi ((status & SPU_STATUS_STOPPED_BY_STOP) && 4132ebb2477SMasato Noguchi (status >> SPU_STOP_STATUS_SHIFT != 0x2104))))) 4142ebb2477SMasato Noguchi ret = status; 4152ebb2477SMasato Noguchi 41605169237SBenjamin Herrenschmidt /* Note: we don't need to force_sig SIGTRAP on single-step 41705169237SBenjamin Herrenschmidt * since we have TIF_SINGLESTEP set, thus the kernel will do 41805169237SBenjamin Herrenschmidt * it upon return from the syscall anyawy 41905169237SBenjamin Herrenschmidt */ 42060cf54dbSJeremy Kerr if (unlikely(status & SPU_STATUS_SINGLE_STEP)) 42160cf54dbSJeremy Kerr ret = -ERESTARTSYS; 42260cf54dbSJeremy Kerr 42360cf54dbSJeremy Kerr else if (unlikely((status & SPU_STATUS_STOPPED_BY_STOP) 42460cf54dbSJeremy Kerr && (status >> SPU_STOP_STATUS_SHIFT) == 0x3fff)) { 4252ebb2477SMasato Noguchi force_sig(SIGTRAP, current); 4262ebb2477SMasato Noguchi ret = -ERESTARTSYS; 4272ebb2477SMasato Noguchi } 4282ebb2477SMasato Noguchi 429ce8ab854SArnd Bergmann out: 4309add11daSArnd Bergmann *event = ctx->event_return; 431c9101bdbSChristoph Hellwig out_unlock: 432e45d48a3SChristoph Hellwig mutex_unlock(&ctx->run_mutex); 433ce8ab854SArnd Bergmann return ret; 434ce8ab854SArnd Bergmann } 435