fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / arch / powerpc / platforms / cell / spufs / context.c
index 336f238..0870009 100644 (file)
 #include <asm/spu_csa.h>
 #include "spufs.h"
 
-struct spu_context *alloc_spu_context(struct address_space *local_store)
+struct spu_context *alloc_spu_context(struct spu_gang *gang)
 {
        struct spu_context *ctx;
-       ctx = kmalloc(sizeof *ctx, GFP_KERNEL);
+       ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
        if (!ctx)
                goto out;
        /* Binding to physical processor deferred
@@ -47,13 +47,12 @@ struct spu_context *alloc_spu_context(struct address_space *local_store)
        init_waitqueue_head(&ctx->ibox_wq);
        init_waitqueue_head(&ctx->wbox_wq);
        init_waitqueue_head(&ctx->stop_wq);
-       ctx->ibox_fasync = NULL;
-       ctx->wbox_fasync = NULL;
+       init_waitqueue_head(&ctx->mfc_wq);
        ctx->state = SPU_STATE_SAVED;
-       ctx->local_store = local_store;
-       ctx->spu = NULL;
        ctx->ops = &spu_backing_ops;
        ctx->owner = get_task_mm(current);
+       if (gang)
+               spu_gang_add_ctx(gang, ctx);
        goto out;
 out_free:
        kfree(ctx);
@@ -68,10 +67,10 @@ void destroy_spu_context(struct kref *kref)
        ctx = container_of(kref, struct spu_context, kref);
        down_write(&ctx->state_sema);
        spu_deactivate(ctx);
-       ctx->ibox_fasync = NULL;
-       ctx->wbox_fasync = NULL;
        up_write(&ctx->state_sema);
        spu_fini_csa(&ctx->csa);
+       if (ctx->gang)
+               spu_gang_remove_ctx(ctx->gang, ctx);
        kfree(ctx);
 }
 
@@ -109,7 +108,43 @@ void spu_release(struct spu_context *ctx)
 
 void spu_unmap_mappings(struct spu_context *ctx)
 {
-       unmap_mapping_range(ctx->local_store, 0, LS_SIZE, 1);
+       if (ctx->local_store)
+               unmap_mapping_range(ctx->local_store, 0, LS_SIZE, 1);
+       if (ctx->mfc)
+               unmap_mapping_range(ctx->mfc, 0, 0x4000, 1);
+       if (ctx->cntl)
+               unmap_mapping_range(ctx->cntl, 0, 0x4000, 1);
+       if (ctx->signal1)
+               unmap_mapping_range(ctx->signal1, 0, 0x4000, 1);
+       if (ctx->signal2)
+               unmap_mapping_range(ctx->signal2, 0, 0x4000, 1);
+}
+
+int spu_acquire_exclusive(struct spu_context *ctx)
+{
+       int ret = 0;
+
+       down_write(&ctx->state_sema);
+       /* ctx is about to be freed, can't acquire any more */
+       if (!ctx->owner) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (ctx->state == SPU_STATE_SAVED) {
+               ret = spu_activate(ctx, 0);
+               if (ret)
+                       goto out;
+               ctx->state = SPU_STATE_RUNNABLE;
+       } else {
+               /* We need to exclude userspace access to the context. */
+               spu_unmap_mappings(ctx);
+       }
+
+out:
+       if (ret)
+               up_write(&ctx->state_sema);
+       return ret;
 }
 
 int spu_acquire_runnable(struct spu_context *ctx)