diff mbox

[21/50] drm/i915/bdw: A bit more advanced context init/fini

Message ID 1399637360-4277-22-git-send-email-oscar.mateo@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

oscar.mateo@intel.com May 9, 2014, 12:08 p.m. UTC
From: Ben Widawsky <benjamin.widawsky@intel.com>

There are a few big differences between context init and fini with the
previous implementation of hardware contexts. One of them is
demonstrated in this patch: we must allocate a ctx backing object for
each engine.

Regarding the context size, reading the register to calculate the sizes
can work, I think, however the docs are very clear about the actual
context sizes on GEN8, so just hardcode that and use it.

Signed-off-by: Ben Widawsky <ben@bwidawsk.net>

v2: Rebased on top of the Full PPGTT series. It is important to notice
that at this point we have one global default context per engine, all
of them using the aliasing PPGTT (as opposed to the single global
default context we have with legacy HW contexts).

v3:
- Go back to one single global default context, this time with multiple
  backing objects inside.
- Use different context sizes for non-render engines, as suggested by
  Damien (still hardcoded, since the information about the context size
  registers in the BSpec is, well, *lacking*).
- Render ctx size is 20 (or 19) pages, but not 21 (caught by Damien).
- Move default context backing object creation to intel_init_ring (so
  that we don't waste memory in rings that might not get initialized).

Cc: Damien Lespiau <damien.lespiau@intel.com>
Signed-off-by: Oscar Mateo <oscar.mateo@intel.com>
---
 drivers/gpu/drm/i915/i915_dma.c         |  4 +-
 drivers/gpu/drm/i915/i915_drv.h         |  5 +-
 drivers/gpu/drm/i915/i915_gem_context.c | 37 +++++++++-----
 drivers/gpu/drm/i915/intel_lrc.c        | 85 ++++++++++++++++++++++++++++++++-
 drivers/gpu/drm/i915/intel_ringbuffer.c | 10 ++++
 5 files changed, 124 insertions(+), 17 deletions(-)
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 7bdb9be..e0f56f5 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1385,7 +1385,7 @@  static int i915_load_modeset_init(struct drm_device *dev)
 cleanup_gem:
 	mutex_lock(&dev->struct_mutex);
 	i915_gem_cleanup_ring(dev);
-	i915_gem_context_fini(dev);
+	i915_gem_context_fini(dev, dev_priv->lrc_enabled);
 	mutex_unlock(&dev->struct_mutex);
 	WARN_ON(dev_priv->mm.aliasing_ppgtt);
 	drm_mm_takedown(&dev_priv->gtt.base.mm);
@@ -1841,7 +1841,7 @@  int i915_driver_unload(struct drm_device *dev)
 		mutex_lock(&dev->struct_mutex);
 		i915_gem_free_all_phys_object(dev);
 		i915_gem_cleanup_ring(dev);
-		i915_gem_context_fini(dev);
+		i915_gem_context_fini(dev, dev_priv->lrc_enabled);
 		WARN_ON(dev_priv->mm.aliasing_ppgtt);
 		mutex_unlock(&dev->struct_mutex);
 		i915_gem_cleanup_stolen(dev);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 41d3f95..1cc1042 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2390,7 +2390,7 @@  void i915_gem_object_ggtt_unpin(struct drm_i915_gem_object *obj);
 /* i915_gem_context.c */
 #define ctx_to_ppgtt(ctx) container_of((ctx)->vm, struct i915_hw_ppgtt, base)
 int __must_check i915_gem_context_init(struct drm_device *dev);
-void i915_gem_context_fini(struct drm_device *dev);
+void i915_gem_context_fini(struct drm_device *dev, bool is_lrc);
 struct drm_i915_gem_object *intel_allocate_ctx_backing_obj(struct drm_device *dev,
 		size_t size);
 struct i915_hw_context *i915_gem_create_context(struct drm_device *dev,
@@ -2427,6 +2427,9 @@  int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
 
 /* intel_lrc.c */
 int gen8_gem_context_init(struct drm_device *dev);
+int gen8_create_lr_context(struct i915_hw_context *ctx,
+			   struct intel_engine *ring,
+			   struct drm_i915_file_private *file_priv);
 
 /* i915_gem_evict.c */
 int __must_check i915_gem_evict_something(struct drm_device *dev,
diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
index 708111d..16fc780 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/i915_gem_context.c
@@ -181,16 +181,22 @@  void i915_gem_context_free(struct kref *ctx_ref)
 	struct i915_hw_context *ctx = container_of(ctx_ref,
 						   typeof(*ctx), ref);
 	struct i915_hw_ppgtt *ppgtt = NULL;
-	struct drm_i915_gem_object *ctx_obj = ctx->engine[RCS].obj;
+	int i;
 
-	if (ctx_obj) {
-		/* We refcount even the aliasing PPGTT to keep the code symmetric */
-		if (USES_PPGTT(ctx_obj->base.dev))
-			ppgtt = ctx_to_ppgtt(ctx);
+	for (i = 0; i < I915_NUM_RINGS; i++) {
+		struct drm_i915_gem_object *ctx_obj = ctx->engine[i].obj;
+		if (ctx_obj) {
+			if (i == RCS) {
+				/* We refcount even the aliasing PPGTT to keep the
+				 * code symmetric */
+				if (USES_PPGTT(ctx_obj->base.dev))
+					ppgtt = ctx_to_ppgtt(ctx);
+			}
 
-		/* XXX: Free up the object before tearing down the address space, in
-		 * case we're bound in the PPGTT */
-		drm_gem_object_unreference(&ctx_obj->base);
+			/* XXX: Free up the object before tearing down the address
+			 * space, in case we're bound in the PPGTT */
+			drm_gem_object_unreference(&ctx_obj->base);
+		}
 	}
 
 	if (ppgtt)
@@ -447,15 +453,15 @@  int i915_gem_context_init(struct drm_device *dev)
 	return 0;
 }
 
-void i915_gem_context_fini(struct drm_device *dev)
+void i915_gem_context_fini(struct drm_device *dev, bool is_lrc)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	struct i915_hw_context *dctx = dev_priv->ring[RCS].default_context;
 	struct drm_i915_gem_object *dctx_obj = dctx->engine[RCS].obj;
 	struct intel_engine *ring;
-	int unused;
+	int ring_id;
 
-	if (dctx_obj) {
+	if (dctx_obj && !is_lrc) {
 		/* The only known way to stop the gpu from accessing the hw context is
 		 * to reset it. Do this as the very last operation to avoid confusing
 		 * other code, leading to spurious errors. */
@@ -477,15 +483,20 @@  void i915_gem_context_fini(struct drm_device *dev)
 		}
 	}
 
-	for_each_ring(ring, dev_priv, unused) {
+	for_each_ring(ring, dev_priv, ring_id) {
 		if (ring->last_context)
 			i915_gem_context_unreference(ring->last_context);
 
 		ring->default_context = NULL;
 		ring->last_context = NULL;
+
+		dctx_obj = dctx->engine[ring_id].obj;
+		if (dctx_obj) {
+			BUG_ON(ring_id != RCS && !is_lrc);
+			i915_gem_object_ggtt_unpin(dctx_obj);
+		}
 	}
 
-	i915_gem_object_ggtt_unpin(dctx_obj);
 	i915_gem_context_unreference(dctx);
 }
 
diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index 3a93e99..875d7b9 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -41,7 +41,90 @@ 
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
 
+#define GEN8_LR_CONTEXT_RENDER_SIZE (20 * PAGE_SIZE)
+#define GEN8_LR_CONTEXT_OTHER_SIZE (2 * PAGE_SIZE)
+
+#define GEN8_LR_CONTEXT_ALIGN 4096
+
+static uint32_t get_lr_context_size(struct intel_engine *ring)
+{
+	int ret = 0;
+
+	BUG_ON(INTEL_INFO(ring->dev)->gen != 8);
+
+	switch (ring->id) {
+	case RCS:
+		ret = GEN8_LR_CONTEXT_RENDER_SIZE;
+		break;
+	case VCS:
+	case BCS:
+	case VECS:
+	case VCS2:
+		ret = GEN8_LR_CONTEXT_OTHER_SIZE;
+		break;
+	}
+
+	return ret;
+}
+
+int gen8_create_lr_context(struct i915_hw_context *ctx,
+			   struct intel_engine *ring,
+			   struct drm_i915_file_private *file_priv)
+{
+	struct drm_device *dev = ring->dev;
+	struct drm_i915_gem_object *ctx_obj;
+	uint32_t context_size;
+	int ret;
+
+	if (ctx->engine[ring->id].obj)
+		return 0;
+
+	context_size = round_up(get_lr_context_size(ring), 4096);
+
+	ctx_obj = intel_allocate_ctx_backing_obj(dev, context_size);
+	if (IS_ERR_OR_NULL(ctx_obj)) {
+		ret = PTR_ERR(ctx_obj);
+		DRM_DEBUG_DRIVER("Alloc LRC backing obj failed: %d\n", ret);
+		return ret;
+	}
+
+	ret = i915_gem_obj_ggtt_pin(ctx_obj, GEN8_LR_CONTEXT_ALIGN, 0);
+	if (ret) {
+		DRM_DEBUG_DRIVER("Pin LRC backing obj failed: %d\n", ret);
+		drm_gem_object_unreference(&ctx_obj->base);
+		return ret;
+	}
+
+	ctx->engine[ring->id].obj = ctx_obj;
+
+	return 0;
+}
+
 int gen8_gem_context_init(struct drm_device *dev)
 {
-	return -ENOSYS;
+	struct drm_i915_private *dev_priv = to_i915(dev);
+	struct i915_hw_context *ctx;
+	struct intel_engine *ring;
+	int ring_id;
+	int ret;
+
+	/* Any value != 0 works here */
+	dev_priv->hw_context_size = GEN8_LR_CONTEXT_RENDER_SIZE;
+
+	ctx = i915_gem_create_context(dev, NULL, true, false);
+	if (IS_ERR_OR_NULL(ctx)) {
+		ret = PTR_ERR(ctx);
+		DRM_ERROR("Init LR context failed: %d\n", ret);
+		goto err_out;
+	}
+
+	for_each_ring(ring, dev_priv, ring_id)
+		ring->default_context = ctx;
+
+	DRM_DEBUG_DRIVER("LR context support initialized\n");
+	return 0;
+
+err_out:
+	i915_gem_context_fini(dev, true);
+	return ret;
 }
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index 6225123..e7f61d9 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -1443,6 +1443,7 @@  err_unref:
 static int intel_init_ring(struct drm_device *dev,
 			   struct intel_engine *ring)
 {
+	struct drm_i915_private *dev_priv = to_i915(dev);
 	struct intel_ringbuffer *ringbuf = &ring->default_ringbuf;
 	int ret;
 
@@ -1453,6 +1454,15 @@  static int intel_init_ring(struct drm_device *dev,
 
 	init_waitqueue_head(&ring->irq_queue);
 
+	if (dev_priv->lrc_enabled) {
+		ret = gen8_create_lr_context(ring->default_context, ring, NULL);
+		if (ret) {
+			DRM_ERROR("Create LR context for %s failed: %d\n",
+					ring->name, ret);
+			return ret;
+		}
+	}
+
 	if (I915_NEED_GFX_HWS(dev)) {
 		ret = init_status_page(ring);
 		if (ret)