]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - arch/powerpc/platforms/cell/spufs/file.c
[CELL] spufs: make sure context are scheduled again after spu_acquire_saved
[mv-sheeva.git] / arch / powerpc / platforms / cell / spufs / file.c
index 2bb51ca51a6c18a5da8d6bf75614e29dacff0f0c..88da996f6d2f1b2d8876e1208e57c52140677c84 100644 (file)
@@ -370,7 +370,7 @@ spufs_regs_read(struct file *file, char __user *buffer,
 
        spu_acquire_saved(ctx);
        ret = __spufs_regs_read(ctx, buffer, size, pos);
-       spu_release(ctx);
+       spu_release_saved(ctx);
        return ret;
 }
 
@@ -392,7 +392,7 @@ spufs_regs_write(struct file *file, const char __user *buffer,
        ret = copy_from_user(lscsa->gprs + *pos - size,
                             buffer, size) ? -EFAULT : size;
 
-       spu_release(ctx);
+       spu_release_saved(ctx);
        return ret;
 }
 
@@ -421,7 +421,7 @@ spufs_fpcr_read(struct file *file, char __user * buffer,
 
        spu_acquire_saved(ctx);
        ret = __spufs_fpcr_read(ctx, buffer, size, pos);
-       spu_release(ctx);
+       spu_release_saved(ctx);
        return ret;
 }
 
@@ -443,7 +443,7 @@ spufs_fpcr_write(struct file *file, const char __user * buffer,
        ret = copy_from_user((char *)&lscsa->fpcr + *pos - size,
                             buffer, size) ? -EFAULT : size;
 
-       spu_release(ctx);
+       spu_release_saved(ctx);
        return ret;
 }
 
@@ -868,7 +868,7 @@ static ssize_t spufs_signal1_read(struct file *file, char __user *buf,
 
        spu_acquire_saved(ctx);
        ret = __spufs_signal1_read(ctx, buf, len, pos);
-       spu_release(ctx);
+       spu_release_saved(ctx);
 
        return ret;
 }
@@ -934,6 +934,13 @@ static const struct file_operations spufs_signal1_fops = {
        .mmap = spufs_signal1_mmap,
 };
 
+static const struct file_operations spufs_signal1_nosched_fops = {
+       .open = spufs_signal1_open,
+       .release = spufs_signal1_release,
+       .write = spufs_signal1_write,
+       .mmap = spufs_signal1_mmap,
+};
+
 static int spufs_signal2_open(struct inode *inode, struct file *file)
 {
        struct spufs_inode_info *i = SPUFS_I(inode);
@@ -992,7 +999,7 @@ static ssize_t spufs_signal2_read(struct file *file, char __user *buf,
 
        spu_acquire_saved(ctx);
        ret = __spufs_signal2_read(ctx, buf, len, pos);
-       spu_release(ctx);
+       spu_release_saved(ctx);
 
        return ret;
 }
@@ -1062,6 +1069,13 @@ static const struct file_operations spufs_signal2_fops = {
        .mmap = spufs_signal2_mmap,
 };
 
+static const struct file_operations spufs_signal2_nosched_fops = {
+       .open = spufs_signal2_open,
+       .release = spufs_signal2_release,
+       .write = spufs_signal2_write,
+       .mmap = spufs_signal2_mmap,
+};
+
 static void spufs_signal1_type_set(void *data, u64 val)
 {
        struct spu_context *ctx = data;
@@ -1499,14 +1513,15 @@ static ssize_t spufs_mfc_write(struct file *file, const char __user *buffer,
                if (status)
                        ret = status;
        }
-       spu_release(ctx);
 
        if (ret)
-               goto out;
+               goto out_unlock;
 
        ctx->tagwait |= 1 << cmd.tag;
        ret = size;
 
+out_unlock:
+       spu_release(ctx);
 out:
        return ret;
 }
@@ -1517,14 +1532,14 @@ static unsigned int spufs_mfc_poll(struct file *file,poll_table *wait)
        u32 free_elements, tagstatus;
        unsigned int mask;
 
+       poll_wait(file, &ctx->mfc_wq, wait);
+
        spu_acquire(ctx);
        ctx->ops->set_mfc_query(ctx, ctx->tagwait, 2);
        free_elements = ctx->ops->get_mfc_free_elements(ctx);
        tagstatus = ctx->ops->read_mfc_tagstatus(ctx);
        spu_release(ctx);
 
-       poll_wait(file, &ctx->mfc_wq, wait);
-
        mask = 0;
        if (free_elements & 0xffff)
                mask |= POLLOUT | POLLWRNORM;
@@ -1611,7 +1626,7 @@ static void spufs_decr_set(void *data, u64 val)
        struct spu_lscsa *lscsa = ctx->csa.lscsa;
        spu_acquire_saved(ctx);
        lscsa->decr.slot[0] = (u32) val;
-       spu_release(ctx);
+       spu_release_saved(ctx);
 }
 
 static u64 __spufs_decr_get(void *data)
@@ -1627,7 +1642,7 @@ static u64 spufs_decr_get(void *data)
        u64 ret;
        spu_acquire_saved(ctx);
        ret = __spufs_decr_get(data);
-       spu_release(ctx);
+       spu_release_saved(ctx);
        return ret;
 }
 DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_ops, spufs_decr_get, spufs_decr_set,
@@ -1639,7 +1654,7 @@ static void spufs_decr_status_set(void *data, u64 val)
        struct spu_lscsa *lscsa = ctx->csa.lscsa;
        spu_acquire_saved(ctx);
        lscsa->decr_status.slot[0] = (u32) val;
-       spu_release(ctx);
+       spu_release_saved(ctx);
 }
 
 static u64 __spufs_decr_status_get(void *data)
@@ -1655,7 +1670,7 @@ static u64 spufs_decr_status_get(void *data)
        u64 ret;
        spu_acquire_saved(ctx);
        ret = __spufs_decr_status_get(data);
-       spu_release(ctx);
+       spu_release_saved(ctx);
        return ret;
 }
 DEFINE_SIMPLE_ATTRIBUTE(spufs_decr_status_ops, spufs_decr_status_get,
@@ -1667,7 +1682,7 @@ static void spufs_event_mask_set(void *data, u64 val)
        struct spu_lscsa *lscsa = ctx->csa.lscsa;
        spu_acquire_saved(ctx);
        lscsa->event_mask.slot[0] = (u32) val;
-       spu_release(ctx);
+       spu_release_saved(ctx);
 }
 
 static u64 __spufs_event_mask_get(void *data)
@@ -1683,7 +1698,7 @@ static u64 spufs_event_mask_get(void *data)
        u64 ret;
        spu_acquire_saved(ctx);
        ret = __spufs_event_mask_get(data);
-       spu_release(ctx);
+       spu_release_saved(ctx);
        return ret;
 }
 DEFINE_SIMPLE_ATTRIBUTE(spufs_event_mask_ops, spufs_event_mask_get,
@@ -1707,7 +1722,7 @@ static u64 spufs_event_status_get(void *data)
 
        spu_acquire_saved(ctx);
        ret = __spufs_event_status_get(data);
-       spu_release(ctx);
+       spu_release_saved(ctx);
        return ret;
 }
 DEFINE_SIMPLE_ATTRIBUTE(spufs_event_status_ops, spufs_event_status_get,
@@ -1719,7 +1734,7 @@ static void spufs_srr0_set(void *data, u64 val)
        struct spu_lscsa *lscsa = ctx->csa.lscsa;
        spu_acquire_saved(ctx);
        lscsa->srr0.slot[0] = (u32) val;
-       spu_release(ctx);
+       spu_release_saved(ctx);
 }
 
 static u64 spufs_srr0_get(void *data)
@@ -1729,7 +1744,7 @@ static u64 spufs_srr0_get(void *data)
        u64 ret;
        spu_acquire_saved(ctx);
        ret = lscsa->srr0.slot[0];
-       spu_release(ctx);
+       spu_release_saved(ctx);
        return ret;
 }
 DEFINE_SIMPLE_ATTRIBUTE(spufs_srr0_ops, spufs_srr0_get, spufs_srr0_set,
@@ -1785,7 +1800,7 @@ static u64 spufs_lslr_get(void *data)
 
        spu_acquire_saved(ctx);
        ret = __spufs_lslr_get(data);
-       spu_release(ctx);
+       spu_release_saved(ctx);
 
        return ret;
 }
@@ -1849,7 +1864,7 @@ static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf,
        spin_lock(&ctx->csa.register_lock);
        ret = __spufs_mbox_info_read(ctx, buf, len, pos);
        spin_unlock(&ctx->csa.register_lock);
-       spu_release(ctx);
+       spu_release_saved(ctx);
 
        return ret;
 }
@@ -1887,7 +1902,7 @@ static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf,
        spin_lock(&ctx->csa.register_lock);
        ret = __spufs_ibox_info_read(ctx, buf, len, pos);
        spin_unlock(&ctx->csa.register_lock);
-       spu_release(ctx);
+       spu_release_saved(ctx);
 
        return ret;
 }
@@ -1928,7 +1943,7 @@ static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf,
        spin_lock(&ctx->csa.register_lock);
        ret = __spufs_wbox_info_read(ctx, buf, len, pos);
        spin_unlock(&ctx->csa.register_lock);
-       spu_release(ctx);
+       spu_release_saved(ctx);
 
        return ret;
 }
@@ -1978,7 +1993,7 @@ static ssize_t spufs_dma_info_read(struct file *file, char __user *buf,
        spin_lock(&ctx->csa.register_lock);
        ret = __spufs_dma_info_read(ctx, buf, len, pos);
        spin_unlock(&ctx->csa.register_lock);
-       spu_release(ctx);
+       spu_release_saved(ctx);
 
        return ret;
 }
@@ -2029,7 +2044,7 @@ static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf,
        spin_lock(&ctx->csa.register_lock);
        ret = __spufs_proxydma_info_read(ctx, buf, len, pos);
        spin_unlock(&ctx->csa.register_lock);
-       spu_release(ctx);
+       spu_release_saved(ctx);
 
        return ret;
 }
@@ -2059,6 +2074,95 @@ static const struct file_operations spufs_tid_fops = {
        .release        = single_release,
 };
 
+static const char *ctx_state_names[] = {
+       "user", "system", "iowait", "loaded"
+};
+
+static unsigned long long spufs_acct_time(struct spu_context *ctx,
+               enum spu_utilization_state state)
+{
+       struct timespec ts;
+       unsigned long long time = ctx->stats.times[state];
+
+       /*
+        * In general, utilization statistics are updated by the controlling
+        * thread as the spu context moves through various well defined
+        * state transitions, but if the context is lazily loaded its
+        * utilization statistics are not updated as the controlling thread
+        * is not tightly coupled with the execution of the spu context.  We
+        * calculate and apply the time delta from the last recorded state
+        * of the spu context.
+        */
+       if (ctx->spu && ctx->stats.util_state == state) {
+               ktime_get_ts(&ts);
+               time += timespec_to_ns(&ts) - ctx->stats.tstamp;
+       }
+
+       return time / NSEC_PER_MSEC;
+}
+
+static unsigned long long spufs_slb_flts(struct spu_context *ctx)
+{
+       unsigned long long slb_flts = ctx->stats.slb_flt;
+
+       if (ctx->state == SPU_STATE_RUNNABLE) {
+               slb_flts += (ctx->spu->stats.slb_flt -
+                            ctx->stats.slb_flt_base);
+       }
+
+       return slb_flts;
+}
+
+static unsigned long long spufs_class2_intrs(struct spu_context *ctx)
+{
+       unsigned long long class2_intrs = ctx->stats.class2_intr;
+
+       if (ctx->state == SPU_STATE_RUNNABLE) {
+               class2_intrs += (ctx->spu->stats.class2_intr -
+                                ctx->stats.class2_intr_base);
+       }
+
+       return class2_intrs;
+}
+
+
+static int spufs_show_stat(struct seq_file *s, void *private)
+{
+       struct spu_context *ctx = s->private;
+
+       spu_acquire(ctx);
+       seq_printf(s, "%s %llu %llu %llu %llu "
+                     "%llu %llu %llu %llu %llu %llu %llu %llu\n",
+               ctx_state_names[ctx->stats.util_state],
+               spufs_acct_time(ctx, SPU_UTIL_USER),
+               spufs_acct_time(ctx, SPU_UTIL_SYSTEM),
+               spufs_acct_time(ctx, SPU_UTIL_IOWAIT),
+               spufs_acct_time(ctx, SPU_UTIL_IDLE_LOADED),
+               ctx->stats.vol_ctx_switch,
+               ctx->stats.invol_ctx_switch,
+               spufs_slb_flts(ctx),
+               ctx->stats.hash_flt,
+               ctx->stats.min_flt,
+               ctx->stats.maj_flt,
+               spufs_class2_intrs(ctx),
+               ctx->stats.libassist);
+       spu_release(ctx);
+       return 0;
+}
+
+static int spufs_stat_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, spufs_show_stat, SPUFS_I(inode)->i_ctx);
+}
+
+static const struct file_operations spufs_stat_fops = {
+       .open           = spufs_stat_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+
 struct tree_descr spufs_dir_contents[] = {
        { "capabilities", &spufs_caps_fops, 0444, },
        { "mem",  &spufs_mem_fops,  0666, },
@@ -2093,6 +2197,7 @@ struct tree_descr spufs_dir_contents[] = {
        { "dma_info", &spufs_dma_info_fops, 0444, },
        { "proxydma_info", &spufs_proxydma_info_fops, 0444, },
        { "tid", &spufs_tid_fops, 0444, },
+       { "stat", &spufs_stat_fops, 0444, },
        {},
 };
 
@@ -2105,8 +2210,8 @@ struct tree_descr spufs_dir_nosched_contents[] = {
        { "mbox_stat", &spufs_mbox_stat_fops, 0444, },
        { "ibox_stat", &spufs_ibox_stat_fops, 0444, },
        { "wbox_stat", &spufs_wbox_stat_fops, 0444, },
-       { "signal1", &spufs_signal1_fops, 0666, },
-       { "signal2", &spufs_signal2_fops, 0666, },
+       { "signal1", &spufs_signal1_nosched_fops, 0222, },
+       { "signal2", &spufs_signal2_nosched_fops, 0222, },
        { "signal1_type", &spufs_signal1_type, 0666, },
        { "signal2_type", &spufs_signal2_type, 0666, },
        { "mss", &spufs_mss_fops, 0666, },
@@ -2117,6 +2222,7 @@ struct tree_descr spufs_dir_nosched_contents[] = {
        { "phys-id", &spufs_id_ops, 0666, },
        { "object-id", &spufs_object_id_ops, 0666, },
        { "tid", &spufs_tid_fops, 0444, },
+       { "stat", &spufs_stat_fops, 0444, },
        {},
 };