Loading arch/powerpc/platforms/cell/spufs/.gitignore 0 → 100644 +2 −0 Original line number Diff line number Diff line spu_save_dump.h spu_restore_dump.h arch/powerpc/platforms/cell/spufs/context.c +4 −0 Original line number Diff line number Diff line Loading @@ -78,6 +78,7 @@ void destroy_spu_context(struct kref *kref) { struct spu_context *ctx; ctx = container_of(kref, struct spu_context, kref); spu_context_nospu_trace(destroy_spu_context__enter, ctx); mutex_lock(&ctx->state_mutex); spu_deactivate(ctx); mutex_unlock(&ctx->state_mutex); Loading @@ -88,6 +89,7 @@ void destroy_spu_context(struct kref *kref) kref_put(ctx->prof_priv_kref, ctx->prof_priv_release); BUG_ON(!list_empty(&ctx->rq)); atomic_dec(&nr_spu_contexts); kfree(ctx->switch_log); kfree(ctx); } Loading Loading @@ -150,6 +152,8 @@ int spu_acquire_saved(struct spu_context *ctx) { int ret; spu_context_nospu_trace(spu_acquire_saved__enter, ctx); ret = spu_acquire(ctx); if (ret) return ret; Loading arch/powerpc/platforms/cell/spufs/file.c +166 −0 Original line number Diff line number Diff line Loading @@ -2386,6 +2386,171 @@ static const struct file_operations spufs_stat_fops = { .release = single_release, }; static inline int spufs_switch_log_used(struct spu_context *ctx) { return (ctx->switch_log->head - ctx->switch_log->tail) % SWITCH_LOG_BUFSIZE; } static inline int spufs_switch_log_avail(struct spu_context *ctx) { return SWITCH_LOG_BUFSIZE - spufs_switch_log_used(ctx); } static int spufs_switch_log_open(struct inode *inode, struct file *file) { struct spu_context *ctx = SPUFS_I(inode)->i_ctx; /* * We (ab-)use the mapping_lock here because it serves the similar * purpose for synchronizing open/close elsewhere. Maybe it should * be renamed eventually. */ mutex_lock(&ctx->mapping_lock); if (ctx->switch_log) { spin_lock(&ctx->switch_log->lock); ctx->switch_log->head = 0; ctx->switch_log->tail = 0; spin_unlock(&ctx->switch_log->lock); } else { /* * We allocate the switch log data structures on first open. * They will never be free because we assume a context will * be traced until it goes away. */ ctx->switch_log = kzalloc(sizeof(struct switch_log) + SWITCH_LOG_BUFSIZE * sizeof(struct switch_log_entry), GFP_KERNEL); if (!ctx->switch_log) goto out; spin_lock_init(&ctx->switch_log->lock); init_waitqueue_head(&ctx->switch_log->wait); } mutex_unlock(&ctx->mapping_lock); return 0; out: mutex_unlock(&ctx->mapping_lock); return -ENOMEM; } static int switch_log_sprint(struct spu_context *ctx, char *tbuf, int n) { struct switch_log_entry *p; p = ctx->switch_log->log + ctx->switch_log->tail % SWITCH_LOG_BUFSIZE; return snprintf(tbuf, n, "%u.%09u %d %u %u %llu\n", (unsigned int) p->tstamp.tv_sec, (unsigned int) p->tstamp.tv_nsec, p->spu_id, (unsigned int) p->type, (unsigned int) p->val, (unsigned long long) p->timebase); } static ssize_t spufs_switch_log_read(struct file *file, char __user *buf, size_t len, loff_t *ppos) { struct inode *inode = file->f_path.dentry->d_inode; struct spu_context *ctx = SPUFS_I(inode)->i_ctx; int error = 0, cnt = 0; if (!buf || len < 0) return -EINVAL; while (cnt < len) { char tbuf[128]; int width; if (file->f_flags & O_NONBLOCK) { if (spufs_switch_log_used(ctx) <= 0) return cnt ? cnt : -EAGAIN; } else { /* Wait for data in buffer */ error = wait_event_interruptible(ctx->switch_log->wait, spufs_switch_log_used(ctx) > 0); if (error) break; } spin_lock(&ctx->switch_log->lock); if (ctx->switch_log->head == ctx->switch_log->tail) { /* multiple readers race? */ spin_unlock(&ctx->switch_log->lock); continue; } width = switch_log_sprint(ctx, tbuf, sizeof(tbuf)); if (width < len) { ctx->switch_log->tail = (ctx->switch_log->tail + 1) % SWITCH_LOG_BUFSIZE; } spin_unlock(&ctx->switch_log->lock); /* * If the record is greater than space available return * partial buffer (so far) */ if (width >= len) break; error = copy_to_user(buf + cnt, tbuf, width); if (error) break; cnt += width; } return cnt == 0 ? error : cnt; } static unsigned int spufs_switch_log_poll(struct file *file, poll_table *wait) { struct inode *inode = file->f_path.dentry->d_inode; struct spu_context *ctx = SPUFS_I(inode)->i_ctx; unsigned int mask = 0; poll_wait(file, &ctx->switch_log->wait, wait); if (spufs_switch_log_used(ctx) > 0) mask |= POLLIN; return mask; } static const struct file_operations spufs_switch_log_fops = { .owner = THIS_MODULE, .open = spufs_switch_log_open, .read = spufs_switch_log_read, .poll = spufs_switch_log_poll, }; void spu_switch_log_notify(struct spu *spu, struct spu_context *ctx, u32 type, u32 val) { if (!ctx->switch_log) return; spin_lock(&ctx->switch_log->lock); if (spufs_switch_log_avail(ctx) > 1) { struct switch_log_entry *p; p = ctx->switch_log->log + ctx->switch_log->head; ktime_get_ts(&p->tstamp); p->timebase = get_tb(); p->spu_id = spu ? spu->number : -1; p->type = type; p->val = val; ctx->switch_log->head = (ctx->switch_log->head + 1) % SWITCH_LOG_BUFSIZE; } spin_unlock(&ctx->switch_log->lock); wake_up(&ctx->switch_log->wait); } struct tree_descr spufs_dir_contents[] = { { "capabilities", &spufs_caps_fops, 0444, }, Loading Loading @@ -2422,6 +2587,7 @@ struct tree_descr spufs_dir_contents[] = { { "proxydma_info", &spufs_proxydma_info_fops, 0444, }, { "tid", &spufs_tid_fops, 0444, }, { "stat", &spufs_stat_fops, 0444, }, { "switch_log", &spufs_switch_log_fops, 0444 }, {}, }; Loading arch/powerpc/platforms/cell/spufs/run.c +2 −0 Original line number Diff line number Diff line Loading @@ -405,6 +405,8 @@ long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *event) ret = spu_run_fini(ctx, npc, &status); spu_yield(ctx); spu_switch_log_notify(NULL, ctx, SWITCH_LOG_EXIT, status); if ((status & SPU_STATUS_STOPPED_BY_STOP) && (((status >> SPU_STOP_STATUS_SHIFT) & 0x3f00) == 0x2100)) ctx->stats.libassist++; Loading arch/powerpc/platforms/cell/spufs/sched.c +3 −1 Original line number Diff line number Diff line Loading @@ -240,6 +240,7 @@ static void spu_bind_context(struct spu *spu, struct spu_context *ctx) spu->mfc_callback = spufs_mfc_callback; mb(); spu_unmap_mappings(ctx); spu_switch_log_notify(spu, ctx, SWITCH_LOG_START, 0); spu_restore(&ctx->csa, spu); spu->timestamp = jiffies; spu_cpu_affinity_set(spu, raw_smp_processor_id()); Loading Loading @@ -419,6 +420,7 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx) spu_switch_notify(spu, NULL); spu_unmap_mappings(ctx); spu_save(&ctx->csa, spu); spu_switch_log_notify(spu, ctx, SWITCH_LOG_STOP, 0); spu->timestamp = jiffies; ctx->state = SPU_STATE_SAVED; spu->ibox_callback = NULL; Loading Loading @@ -591,7 +593,7 @@ static struct spu *find_victim(struct spu_context *ctx) struct spu *spu; int node, n; spu_context_nospu_trace(spu_find_vitim__enter, ctx); spu_context_nospu_trace(spu_find_victim__enter, ctx); /* * Look for a possible preemption candidate on the local node first. Loading Loading
arch/powerpc/platforms/cell/spufs/.gitignore 0 → 100644 +2 −0 Original line number Diff line number Diff line spu_save_dump.h spu_restore_dump.h
arch/powerpc/platforms/cell/spufs/context.c +4 −0 Original line number Diff line number Diff line Loading @@ -78,6 +78,7 @@ void destroy_spu_context(struct kref *kref) { struct spu_context *ctx; ctx = container_of(kref, struct spu_context, kref); spu_context_nospu_trace(destroy_spu_context__enter, ctx); mutex_lock(&ctx->state_mutex); spu_deactivate(ctx); mutex_unlock(&ctx->state_mutex); Loading @@ -88,6 +89,7 @@ void destroy_spu_context(struct kref *kref) kref_put(ctx->prof_priv_kref, ctx->prof_priv_release); BUG_ON(!list_empty(&ctx->rq)); atomic_dec(&nr_spu_contexts); kfree(ctx->switch_log); kfree(ctx); } Loading Loading @@ -150,6 +152,8 @@ int spu_acquire_saved(struct spu_context *ctx) { int ret; spu_context_nospu_trace(spu_acquire_saved__enter, ctx); ret = spu_acquire(ctx); if (ret) return ret; Loading
arch/powerpc/platforms/cell/spufs/file.c +166 −0 Original line number Diff line number Diff line Loading @@ -2386,6 +2386,171 @@ static const struct file_operations spufs_stat_fops = { .release = single_release, }; static inline int spufs_switch_log_used(struct spu_context *ctx) { return (ctx->switch_log->head - ctx->switch_log->tail) % SWITCH_LOG_BUFSIZE; } static inline int spufs_switch_log_avail(struct spu_context *ctx) { return SWITCH_LOG_BUFSIZE - spufs_switch_log_used(ctx); } static int spufs_switch_log_open(struct inode *inode, struct file *file) { struct spu_context *ctx = SPUFS_I(inode)->i_ctx; /* * We (ab-)use the mapping_lock here because it serves the similar * purpose for synchronizing open/close elsewhere. Maybe it should * be renamed eventually. */ mutex_lock(&ctx->mapping_lock); if (ctx->switch_log) { spin_lock(&ctx->switch_log->lock); ctx->switch_log->head = 0; ctx->switch_log->tail = 0; spin_unlock(&ctx->switch_log->lock); } else { /* * We allocate the switch log data structures on first open. * They will never be free because we assume a context will * be traced until it goes away. */ ctx->switch_log = kzalloc(sizeof(struct switch_log) + SWITCH_LOG_BUFSIZE * sizeof(struct switch_log_entry), GFP_KERNEL); if (!ctx->switch_log) goto out; spin_lock_init(&ctx->switch_log->lock); init_waitqueue_head(&ctx->switch_log->wait); } mutex_unlock(&ctx->mapping_lock); return 0; out: mutex_unlock(&ctx->mapping_lock); return -ENOMEM; } static int switch_log_sprint(struct spu_context *ctx, char *tbuf, int n) { struct switch_log_entry *p; p = ctx->switch_log->log + ctx->switch_log->tail % SWITCH_LOG_BUFSIZE; return snprintf(tbuf, n, "%u.%09u %d %u %u %llu\n", (unsigned int) p->tstamp.tv_sec, (unsigned int) p->tstamp.tv_nsec, p->spu_id, (unsigned int) p->type, (unsigned int) p->val, (unsigned long long) p->timebase); } static ssize_t spufs_switch_log_read(struct file *file, char __user *buf, size_t len, loff_t *ppos) { struct inode *inode = file->f_path.dentry->d_inode; struct spu_context *ctx = SPUFS_I(inode)->i_ctx; int error = 0, cnt = 0; if (!buf || len < 0) return -EINVAL; while (cnt < len) { char tbuf[128]; int width; if (file->f_flags & O_NONBLOCK) { if (spufs_switch_log_used(ctx) <= 0) return cnt ? cnt : -EAGAIN; } else { /* Wait for data in buffer */ error = wait_event_interruptible(ctx->switch_log->wait, spufs_switch_log_used(ctx) > 0); if (error) break; } spin_lock(&ctx->switch_log->lock); if (ctx->switch_log->head == ctx->switch_log->tail) { /* multiple readers race? */ spin_unlock(&ctx->switch_log->lock); continue; } width = switch_log_sprint(ctx, tbuf, sizeof(tbuf)); if (width < len) { ctx->switch_log->tail = (ctx->switch_log->tail + 1) % SWITCH_LOG_BUFSIZE; } spin_unlock(&ctx->switch_log->lock); /* * If the record is greater than space available return * partial buffer (so far) */ if (width >= len) break; error = copy_to_user(buf + cnt, tbuf, width); if (error) break; cnt += width; } return cnt == 0 ? error : cnt; } static unsigned int spufs_switch_log_poll(struct file *file, poll_table *wait) { struct inode *inode = file->f_path.dentry->d_inode; struct spu_context *ctx = SPUFS_I(inode)->i_ctx; unsigned int mask = 0; poll_wait(file, &ctx->switch_log->wait, wait); if (spufs_switch_log_used(ctx) > 0) mask |= POLLIN; return mask; } static const struct file_operations spufs_switch_log_fops = { .owner = THIS_MODULE, .open = spufs_switch_log_open, .read = spufs_switch_log_read, .poll = spufs_switch_log_poll, }; void spu_switch_log_notify(struct spu *spu, struct spu_context *ctx, u32 type, u32 val) { if (!ctx->switch_log) return; spin_lock(&ctx->switch_log->lock); if (spufs_switch_log_avail(ctx) > 1) { struct switch_log_entry *p; p = ctx->switch_log->log + ctx->switch_log->head; ktime_get_ts(&p->tstamp); p->timebase = get_tb(); p->spu_id = spu ? spu->number : -1; p->type = type; p->val = val; ctx->switch_log->head = (ctx->switch_log->head + 1) % SWITCH_LOG_BUFSIZE; } spin_unlock(&ctx->switch_log->lock); wake_up(&ctx->switch_log->wait); } struct tree_descr spufs_dir_contents[] = { { "capabilities", &spufs_caps_fops, 0444, }, Loading Loading @@ -2422,6 +2587,7 @@ struct tree_descr spufs_dir_contents[] = { { "proxydma_info", &spufs_proxydma_info_fops, 0444, }, { "tid", &spufs_tid_fops, 0444, }, { "stat", &spufs_stat_fops, 0444, }, { "switch_log", &spufs_switch_log_fops, 0444 }, {}, }; Loading
arch/powerpc/platforms/cell/spufs/run.c +2 −0 Original line number Diff line number Diff line Loading @@ -405,6 +405,8 @@ long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *event) ret = spu_run_fini(ctx, npc, &status); spu_yield(ctx); spu_switch_log_notify(NULL, ctx, SWITCH_LOG_EXIT, status); if ((status & SPU_STATUS_STOPPED_BY_STOP) && (((status >> SPU_STOP_STATUS_SHIFT) & 0x3f00) == 0x2100)) ctx->stats.libassist++; Loading
arch/powerpc/platforms/cell/spufs/sched.c +3 −1 Original line number Diff line number Diff line Loading @@ -240,6 +240,7 @@ static void spu_bind_context(struct spu *spu, struct spu_context *ctx) spu->mfc_callback = spufs_mfc_callback; mb(); spu_unmap_mappings(ctx); spu_switch_log_notify(spu, ctx, SWITCH_LOG_START, 0); spu_restore(&ctx->csa, spu); spu->timestamp = jiffies; spu_cpu_affinity_set(spu, raw_smp_processor_id()); Loading Loading @@ -419,6 +420,7 @@ static void spu_unbind_context(struct spu *spu, struct spu_context *ctx) spu_switch_notify(spu, NULL); spu_unmap_mappings(ctx); spu_save(&ctx->csa, spu); spu_switch_log_notify(spu, ctx, SWITCH_LOG_STOP, 0); spu->timestamp = jiffies; ctx->state = SPU_STATE_SAVED; spu->ibox_callback = NULL; Loading Loading @@ -591,7 +593,7 @@ static struct spu *find_victim(struct spu_context *ctx) struct spu *spu; int node, n; spu_context_nospu_trace(spu_find_vitim__enter, ctx); spu_context_nospu_trace(spu_find_victim__enter, ctx); /* * Look for a possible preemption candidate on the local node first. Loading