|
@@ -96,16 +96,6 @@ void spu_forget(struct spu_context *ctx)
|
|
|
spu_release(ctx);
|
|
|
}
|
|
|
|
|
|
-void spu_acquire(struct spu_context *ctx)
|
|
|
-{
|
|
|
- mutex_lock(&ctx->state_mutex);
|
|
|
-}
|
|
|
-
|
|
|
-void spu_release(struct spu_context *ctx)
|
|
|
-{
|
|
|
- mutex_unlock(&ctx->state_mutex);
|
|
|
-}
|
|
|
-
|
|
|
void spu_unmap_mappings(struct spu_context *ctx)
|
|
|
{
|
|
|
if (ctx->local_store)
|
|
@@ -124,66 +114,85 @@ void spu_unmap_mappings(struct spu_context *ctx)
|
|
|
unmap_mapping_range(ctx->psmap, 0, 0x20000, 1);
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * spu_acquire_exclusive - lock spu contex and protect against userspace access
|
|
|
+ * @ctx: spu contex to lock
|
|
|
+ *
|
|
|
+ * Note:
|
|
|
+ * Returns 0 and with the context locked on success
|
|
|
+ * Returns negative error and with the context _unlocked_ on failure.
|
|
|
+ */
|
|
|
int spu_acquire_exclusive(struct spu_context *ctx)
|
|
|
{
|
|
|
- int ret = 0;
|
|
|
+ int ret = -EINVAL;
|
|
|
|
|
|
- mutex_lock(&ctx->state_mutex);
|
|
|
- /* ctx is about to be freed, can't acquire any more */
|
|
|
- if (!ctx->owner) {
|
|
|
- ret = -EINVAL;
|
|
|
- goto out;
|
|
|
- }
|
|
|
+ spu_acquire(ctx);
|
|
|
+ /*
|
|
|
+ * Context is about to be freed, so we can't acquire it anymore.
|
|
|
+ */
|
|
|
+ if (!ctx->owner)
|
|
|
+ goto out_unlock;
|
|
|
|
|
|
if (ctx->state == SPU_STATE_SAVED) {
|
|
|
ret = spu_activate(ctx, 0);
|
|
|
if (ret)
|
|
|
- goto out;
|
|
|
+ goto out_unlock;
|
|
|
} else {
|
|
|
- /* We need to exclude userspace access to the context. */
|
|
|
+ /*
|
|
|
+ * We need to exclude userspace access to the context.
|
|
|
+ *
|
|
|
+ * To protect against memory access we invalidate all ptes
|
|
|
+ * and make sure the pagefault handlers block on the mutex.
|
|
|
+ */
|
|
|
spu_unmap_mappings(ctx);
|
|
|
}
|
|
|
|
|
|
-out:
|
|
|
- if (ret)
|
|
|
- mutex_unlock(&ctx->state_mutex);
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ out_unlock:
|
|
|
+ spu_release(ctx);
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * spu_acquire_runnable - lock spu contex and make sure it is in runnable state
|
|
|
+ * @ctx: spu contex to lock
|
|
|
+ *
|
|
|
+ * Note:
|
|
|
+ * Returns 0 and with the context locked on success
|
|
|
+ * Returns negative error and with the context _unlocked_ on failure.
|
|
|
+ */
|
|
|
int spu_acquire_runnable(struct spu_context *ctx)
|
|
|
{
|
|
|
- int ret = 0;
|
|
|
-
|
|
|
- mutex_lock(&ctx->state_mutex);
|
|
|
- if (ctx->state == SPU_STATE_RUNNABLE) {
|
|
|
- ctx->spu->prio = current->prio;
|
|
|
- return 0;
|
|
|
- }
|
|
|
-
|
|
|
- /* ctx is about to be freed, can't acquire any more */
|
|
|
- if (!ctx->owner) {
|
|
|
- ret = -EINVAL;
|
|
|
- goto out;
|
|
|
- }
|
|
|
+ int ret = -EINVAL;
|
|
|
|
|
|
+ spu_acquire(ctx);
|
|
|
if (ctx->state == SPU_STATE_SAVED) {
|
|
|
+ /*
|
|
|
+ * Context is about to be freed, so we can't acquire it anymore.
|
|
|
+ */
|
|
|
+ if (!ctx->owner)
|
|
|
+ goto out_unlock;
|
|
|
ret = spu_activate(ctx, 0);
|
|
|
if (ret)
|
|
|
- goto out;
|
|
|
- }
|
|
|
+ goto out_unlock;
|
|
|
+ } else
|
|
|
+ ctx->spu->prio = current->prio;
|
|
|
|
|
|
- /* On success, we return holding the lock */
|
|
|
- return ret;
|
|
|
-out:
|
|
|
- /* Release here, to simplify calling code. */
|
|
|
- mutex_unlock(&ctx->state_mutex);
|
|
|
+ return 0;
|
|
|
|
|
|
+ out_unlock:
|
|
|
+ spu_release(ctx);
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * spu_acquire_saved - lock spu contex and make sure it is in saved state
|
|
|
+ * @ctx: spu contex to lock
|
|
|
+ */
|
|
|
void spu_acquire_saved(struct spu_context *ctx)
|
|
|
{
|
|
|
- mutex_lock(&ctx->state_mutex);
|
|
|
- if (ctx->state == SPU_STATE_RUNNABLE)
|
|
|
+ spu_acquire(ctx);
|
|
|
+ if (ctx->state != SPU_STATE_SAVED)
|
|
|
spu_deactivate(ctx);
|
|
|
}
|