|
@@ -416,14 +416,43 @@ out:
|
|
|
return ctx;
|
|
|
}
|
|
|
|
|
|
+static struct i915_gem_context *
|
|
|
+create_kernel_context(struct drm_i915_private *i915, int prio)
|
|
|
+{
|
|
|
+ struct i915_gem_context *ctx;
|
|
|
+
|
|
|
+ ctx = i915_gem_create_context(i915, NULL);
|
|
|
+ if (IS_ERR(ctx))
|
|
|
+ return ctx;
|
|
|
+
|
|
|
+ i915_gem_context_clear_bannable(ctx);
|
|
|
+ ctx->priority = prio;
|
|
|
+ ctx->ring_size = PAGE_SIZE;
|
|
|
+
|
|
|
+ GEM_BUG_ON(!i915_gem_context_is_kernel(ctx));
|
|
|
+
|
|
|
+ return ctx;
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+destroy_kernel_context(struct i915_gem_context **ctxp)
|
|
|
+{
|
|
|
+ struct i915_gem_context *ctx;
|
|
|
+
|
|
|
+ /* Keep the context ref so that we can free it immediately ourselves */
|
|
|
+ ctx = i915_gem_context_get(fetch_and_zero(ctxp));
|
|
|
+ GEM_BUG_ON(!i915_gem_context_is_kernel(ctx));
|
|
|
+
|
|
|
+ context_close(ctx);
|
|
|
+ i915_gem_context_free(ctx);
|
|
|
+}
|
|
|
+
|
|
|
int i915_gem_contexts_init(struct drm_i915_private *dev_priv)
|
|
|
{
|
|
|
struct i915_gem_context *ctx;
|
|
|
+ int err;
|
|
|
|
|
|
- /* Init should only be called once per module load. Eventually the
|
|
|
- * restriction on the context_disabled check can be loosened. */
|
|
|
- if (WARN_ON(dev_priv->kernel_context))
|
|
|
- return 0;
|
|
|
+ GEM_BUG_ON(dev_priv->kernel_context);
|
|
|
|
|
|
INIT_LIST_HEAD(&dev_priv->contexts.list);
|
|
|
INIT_WORK(&dev_priv->contexts.free_work, contexts_free_worker);
|
|
@@ -441,28 +470,38 @@ int i915_gem_contexts_init(struct drm_i915_private *dev_priv)
|
|
|
BUILD_BUG_ON(MAX_CONTEXT_HW_ID > INT_MAX);
|
|
|
ida_init(&dev_priv->contexts.hw_ida);
|
|
|
|
|
|
- ctx = i915_gem_create_context(dev_priv, NULL);
|
|
|
+ /* lowest priority; idle task */
|
|
|
+ ctx = create_kernel_context(dev_priv, I915_PRIORITY_MIN);
|
|
|
if (IS_ERR(ctx)) {
|
|
|
- DRM_ERROR("Failed to create default global context (error %ld)\n",
|
|
|
- PTR_ERR(ctx));
|
|
|
- return PTR_ERR(ctx);
|
|
|
+ DRM_ERROR("Failed to create default global context\n");
|
|
|
+ err = PTR_ERR(ctx);
|
|
|
+ goto err;
|
|
|
}
|
|
|
-
|
|
|
- /* For easy recognisablity, we want the kernel context to be 0 and then
|
|
|
+ /*
|
|
|
+ * For easy recognisablity, we want the kernel context to be 0 and then
|
|
|
* all user contexts will have non-zero hw_id.
|
|
|
*/
|
|
|
GEM_BUG_ON(ctx->hw_id);
|
|
|
-
|
|
|
- i915_gem_context_clear_bannable(ctx);
|
|
|
- ctx->priority = I915_PRIORITY_MIN; /* lowest priority; idle task */
|
|
|
dev_priv->kernel_context = ctx;
|
|
|
|
|
|
- GEM_BUG_ON(!i915_gem_context_is_kernel(ctx));
|
|
|
+ /* highest priority; preempting task */
|
|
|
+ ctx = create_kernel_context(dev_priv, INT_MAX);
|
|
|
+ if (IS_ERR(ctx)) {
|
|
|
+ DRM_ERROR("Failed to create default preempt context\n");
|
|
|
+ err = PTR_ERR(ctx);
|
|
|
+ goto err_kernel_context;
|
|
|
+ }
|
|
|
+ dev_priv->preempt_context = ctx;
|
|
|
|
|
|
DRM_DEBUG_DRIVER("%s context support initialized\n",
|
|
|
dev_priv->engine[RCS]->context_size ? "logical" :
|
|
|
"fake");
|
|
|
return 0;
|
|
|
+
|
|
|
+err_kernel_context:
|
|
|
+ destroy_kernel_context(&dev_priv->kernel_context);
|
|
|
+err:
|
|
|
+ return err;
|
|
|
}
|
|
|
|
|
|
void i915_gem_contexts_lost(struct drm_i915_private *dev_priv)
|
|
@@ -507,15 +546,10 @@ void i915_gem_contexts_lost(struct drm_i915_private *dev_priv)
|
|
|
|
|
|
void i915_gem_contexts_fini(struct drm_i915_private *i915)
|
|
|
{
|
|
|
- struct i915_gem_context *ctx;
|
|
|
-
|
|
|
lockdep_assert_held(&i915->drm.struct_mutex);
|
|
|
|
|
|
- /* Keep the context so that we can free it immediately ourselves */
|
|
|
- ctx = i915_gem_context_get(fetch_and_zero(&i915->kernel_context));
|
|
|
- GEM_BUG_ON(!i915_gem_context_is_kernel(ctx));
|
|
|
- context_close(ctx);
|
|
|
- i915_gem_context_free(ctx);
|
|
|
+ destroy_kernel_context(&i915->preempt_context);
|
|
|
+ destroy_kernel_context(&i915->kernel_context);
|
|
|
|
|
|
/* Must free all deferred contexts (via flush_workqueue) first */
|
|
|
ida_destroy(&i915->contexts.hw_ida);
|