drm/i915: Permit contexts on all rings
authorBen Widawsky <ben@bwidawsk.net>
Fri, 6 Dec 2013 22:11:01 +0000 (14:11 -0800)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Wed, 18 Dec 2013 14:27:53 +0000 (15:27 +0100)
If we want to use contexts in more abstract terms (specifically with
PPGTT in mind), we need to allow them to be specified for any ring.

Since the upcoming patches will bring about the use of multiple address
spaces, and each ring needs to have an address space programmed (which
we intend to do at context switch time), we can no longer only use RCS.

With multiple rings having a last context, we must now unreference these
contexts.

NOTE: This commit requires an update to intel-gpu-tools to make it not
fail.

v2: Rebased with some logical conflicts.
Squashed in the context fini refcount patch

Signed-off-by: Ben Widawsky <ben@bwidawsk.net>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/gpu/drm/i915/i915_gem_context.c
drivers/gpu/drm/i915/i915_gem_execbuffer.c

index 40413704614e27e5864e304a6cab33ec51679d37..7a5311c3225af1eb5ba7144ccd25787c9cfe9816 100644 (file)
@@ -98,7 +98,8 @@
 
 static struct i915_hw_context *
 i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id);
-static int do_switch(struct i915_hw_context *to);
+static int do_switch(struct intel_ring_buffer *ring,
+                    struct i915_hw_context *to);
 
 static size_t get_context_alignment(struct drm_device *dev)
 {
@@ -240,7 +241,7 @@ static int create_default_context(struct drm_device *dev)
                goto err_destroy;
        }
 
-       ret = do_switch(ctx);
+       ret = do_switch(&dev_priv->ring[RCS], ctx);
        if (ret) {
                DRM_DEBUG_DRIVER("Switch failed %d\n", ret);
                goto err_unpin;
@@ -261,7 +262,8 @@ err_destroy:
 int i915_gem_context_init(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       int ret;
+       struct intel_ring_buffer *ring;
+       int i, ret;
 
        if (!HAS_HW_CONTEXTS(dev))
                return 0;
@@ -284,6 +286,16 @@ int i915_gem_context_init(struct drm_device *dev)
                return ret;
        }
 
+       for (i = RCS + 1; i < I915_NUM_RINGS; i++) {
+               if (!(INTEL_INFO(dev)->ring_mask & (1<<i)))
+                       continue;
+
+               ring = &dev_priv->ring[i];
+
+               /* NB: RCS will hold a ref for all rings */
+               ring->default_context = dev_priv->ring[RCS].default_context;
+       }
+
        DRM_DEBUG_DRIVER("HW context support initialized\n");
        return 0;
 }
@@ -292,6 +304,7 @@ void i915_gem_context_fini(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct i915_hw_context *dctx = dev_priv->ring[RCS].default_context;
+       int i;
 
        if (!HAS_HW_CONTEXTS(dev))
                return;
@@ -313,12 +326,22 @@ void i915_gem_context_fini(struct drm_device *dev)
                WARN_ON(dctx->obj->active);
                i915_gem_object_ggtt_unpin(dctx->obj);
                i915_gem_context_unreference(dctx);
+               dev_priv->ring[RCS].last_context = NULL;
+       }
+
+       for (i = 0; i < I915_NUM_RINGS; i++) {
+               struct intel_ring_buffer *ring = &dev_priv->ring[i];
+               if (!(INTEL_INFO(dev)->ring_mask & (1<<i)))
+                       continue;
+
+               if (ring->last_context)
+                       i915_gem_context_unreference(ring->last_context);
+
+               ring->default_context = NULL;
        }
 
        i915_gem_object_ggtt_unpin(dctx->obj);
        i915_gem_context_unreference(dctx);
-       dev_priv->ring[RCS].default_context = NULL;
-       dev_priv->ring[RCS].last_context = NULL;
 }
 
 static int context_idr_cleanup(int id, void *p, void *data)
@@ -431,19 +454,28 @@ mi_set_context(struct intel_ring_buffer *ring,
        return ret;
 }
 
-static int do_switch(struct i915_hw_context *to)
+static int do_switch(struct intel_ring_buffer *ring,
+                    struct i915_hw_context *to)
 {
-       struct intel_ring_buffer *ring = to->ring;
        struct drm_i915_private *dev_priv = ring->dev->dev_private;
        struct i915_hw_context *from = ring->last_context;
        u32 hw_flags = 0;
        int ret, i;
 
-       BUG_ON(from != NULL && from->obj != NULL && !i915_gem_obj_is_pinned(from->obj));
+       if (from != NULL && ring == &dev_priv->ring[RCS]) {
+               BUG_ON(from->obj == NULL);
+               BUG_ON(!i915_gem_obj_is_pinned(from->obj));
+       }
 
        if (from == to && !to->remap_slice)
                return 0;
 
+       if (ring != &dev_priv->ring[RCS]) {
+               if (from)
+                       i915_gem_context_unreference(from);
+               goto done;
+       }
+
        ret = i915_gem_obj_ggtt_pin(to->obj, get_context_alignment(ring->dev),
                                    false, false);
        if (ret)
@@ -511,6 +543,7 @@ static int do_switch(struct i915_hw_context *to)
                i915_gem_context_unreference(from);
        }
 
+done:
        i915_gem_context_reference(to);
        ring->last_context = to;
        to->is_initialized = true;
@@ -541,9 +574,6 @@ int i915_switch_context(struct intel_ring_buffer *ring,
 
        WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
 
-       if (ring != &dev_priv->ring[RCS])
-               return 0;
-
        if (to_id == DEFAULT_CONTEXT_ID) {
                to = ring->default_context;
        } else {
@@ -555,7 +585,7 @@ int i915_switch_context(struct intel_ring_buffer *ring,
                        return -ENOENT;
        }
 
-       return do_switch(to);
+       return do_switch(ring, to);
 }
 
 int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
index dfe7cb912e29268fd3f6d3c5e6ac502fadaf486c..d608a07f439806ecab1447ec3498c3469af348c3 100644 (file)
@@ -1011,9 +1011,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                          (int)(args->flags & I915_EXEC_RING_MASK));
                return -EINVAL;
        }
-       if (ctx_id != DEFAULT_CONTEXT_ID &&
-           (args->flags & I915_EXEC_RING_MASK) > I915_EXEC_RENDER)
-               return -EPERM;
 
        if ((args->flags & I915_EXEC_RING_MASK) == I915_EXEC_DEFAULT)
                ring = &dev_priv->ring[RCS];