[Intel-gfx] [PATCH 177/190] drm/i915: Use VMA as the primary object for context state

Chris Wilson chris at chris-wilson.co.uk
Mon Jan 11 03:01:18 PST 2016


When working with contexts, we most frequently want the GGTT VMA for the
context state, first and foremost. Since the object is available via the
VMA, we need only then store the VMA.

Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/i915_debugfs.c        | 13 ++--
 drivers/gpu/drm/i915/i915_drv.h            |  3 +-
 drivers/gpu/drm/i915/i915_gem_context.c    | 99 ++++++++++++++++--------------
 drivers/gpu/drm/i915/i915_gpu_error.c      |  2 +-
 drivers/gpu/drm/i915/i915_guc_submission.c |  6 +-
 drivers/gpu/drm/i915/intel_lrc.c           | 53 ++++++++--------
 6 files changed, 93 insertions(+), 83 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index f8ca00ce986e..7fb4088b3966 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -377,7 +377,7 @@ static int per_file_ctx_stats(int id, void *ptr, void *data)
 
 	for (n = 0; n < ARRAY_SIZE(ctx->engine); n++) {
 		if (ctx->engine[n].state)
-			per_file_stats(0, ctx->engine[n].state, data);
+			per_file_stats(0, ctx->engine[n].state->obj, data);
 		if (ctx->engine[n].ring)
 			per_file_stats(0, ctx->engine[n].ring->obj, data);
 	}
@@ -2002,7 +2002,7 @@ static int i915_context_status(struct seq_file *m, void *unused)
 			seq_printf(m, "%s: ", ring->name);
 			seq_putc(m, ctx->engine[i].initialised ? 'I' : 'i');
 			if (ctx->engine[i].state)
-				describe_obj(m, ctx->engine[i].state);
+				describe_obj(m, ctx->engine[i].state->obj);
 			if (ctx->engine[i].ring)
 				describe_ctx_ring(m, ctx->engine[i].ring);
 			seq_putc(m, '\n');
@@ -2025,14 +2025,13 @@ static void i915_dump_lrc_obj(struct seq_file *m,
 			      struct intel_engine_cs *ring,
 			      struct intel_context *ctx)
 {
-	struct drm_i915_gem_object *obj = ctx->engine[ring->id].state;
-	struct i915_vma *vma = ctx->engine[ring->id].vma;
+	struct i915_vma *vma = ctx->engine[ring->id].state;
 	struct page *page;
 	int j;
 
 	seq_printf(m, "CONTEXT: %s\n", ring->name);
 
-	if (obj == NULL) {
+	if (vma == NULL) {
 		seq_printf(m, "\tUnallocated\n\n");
 		return;
 	}
@@ -2045,12 +2044,12 @@ static void i915_dump_lrc_obj(struct seq_file *m,
 			   lower_32_bits(vma->node.start));
 	}
 
-	if (i915_gem_object_get_pages(obj)) {
+	if (i915_gem_object_get_pages(vma->obj)) {
 		seq_puts(m, "\tFailed to get pages for context object\n\n");
 		return;
 	}
 
-	page = i915_gem_object_get_page(obj, LRC_STATE_PN);
+	page = i915_gem_object_get_page(vma->obj, LRC_STATE_PN);
 	if (page != NULL) {
 		uint32_t *reg_state = kmap_atomic(page);
 		for (j = 0; j < 0x600 / sizeof(u32) / 4; j += 4) {
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index a4311e2d2140..6827e26b5681 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -886,8 +886,7 @@ struct intel_context {
 #define CONTEXT_NO_ERROR_CAPTURE	(1<<1)
 
 	struct intel_context_engine {
-		struct drm_i915_gem_object *state;
-		struct i915_vma *vma;
+		struct i915_vma *state;
 		struct intel_ring *ring;
 		int pin_count;
 		bool initialised;
diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
index 4e0c5e161e84..0c4864eca5f6 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/i915_gem_context.c
@@ -214,7 +214,7 @@ void i915_gem_context_free(struct kref *ctx_ref)
 		if (ce->ring)
 			intel_ring_free(ce->ring);
 
-		__i915_gem_object_release_unless_active(ce->state);
+		__i915_gem_object_release_unless_active(ce->state->obj);
 	}
 
 	decouple_vma(ctx);
@@ -322,13 +322,26 @@ __create_hw_context(struct drm_device *dev,
 	INIT_WORK(&ctx->vma_ht_resize, resize_vma_ht);
 
 	if (dev_priv->hw_context_size) {
-		struct drm_i915_gem_object *obj =
-				i915_gem_alloc_context_obj(dev, dev_priv->hw_context_size);
+		struct drm_i915_gem_object *obj;
+		struct i915_vma *vma;
+
+		obj = i915_gem_alloc_context_obj(dev,
+						 dev_priv->hw_context_size);
 		if (IS_ERR(obj)) {
 			ret = PTR_ERR(obj);
 			goto err_out;
 		}
-		ctx->engine[RCS].state = obj;
+
+		vma = i915_gem_obj_lookup_or_create_vma(obj,
+							&dev_priv->gtt.base,
+							NULL);
+		if (IS_ERR(vma)) {
+			drm_gem_object_unreference(&obj->base);
+			ret = PTR_ERR(vma);
+			goto err_out;
+		}
+
+		ctx->engine[RCS].state = vma;
 	}
 
 	/* Default context will never have a file_priv */
@@ -421,10 +434,8 @@ void i915_gem_context_reset(struct drm_device *dev)
 		if (lctx == NULL)
 			continue;
 
-		if (lctx->engine[i].vma) {
-			i915_vma_unpin(lctx->engine[i].vma);
-			lctx->engine[i].vma = NULL;
-		}
+		if (lctx->engine[i].state)
+			i915_vma_unpin(lctx->engine[i].state);
 
 		i915_gem_context_unreference(lctx);
 		ring->last_context = NULL;
@@ -469,8 +480,7 @@ int i915_gem_context_init(struct drm_device *dev)
 	}
 
 	if (ctx->engine[RCS].state) {
-		u32 alignment = get_context_alignment(dev);
-		struct i915_vma *vma;
+		int ret;
 
 		/* We may need to do things with the shrinker which
 		 * require us to immediately switch back to the default
@@ -479,13 +489,14 @@ int i915_gem_context_init(struct drm_device *dev)
 		 * be available. To avoid this we always pin the default
 		 * context.
 		 */
-		vma = i915_gem_object_ggtt_pin(ctx->engine[RCS].state,
-					       NULL, 0, alignment, PIN_HIGH);
-		if (IS_ERR(vma)) {
+		ret = i915_vma_pin(ctx->engine[RCS].state,
+				   0, get_context_alignment(dev),
+				   PIN_GLOBAL | PIN_HIGH);
+		if (ret) {
 			DRM_ERROR("Failed to pinned default global context (error %d)\n",
-				  (int)PTR_ERR(vma));
+				  ret);
 			i915_gem_context_unreference(ctx);
-			return PTR_ERR(vma);
+			return ret;
 		}
 	}
 
@@ -518,13 +529,13 @@ void i915_gem_context_fini(struct drm_device *dev)
 		WARN_ON(!dev_priv->ring[RCS].last_context);
 		if (dev_priv->ring[RCS].last_context == dctx) {
 			/* Fake switch to NULL context */
-			WARN_ON(dctx->engine[RCS].vma->active);
-			i915_vma_unpin(dctx->engine[RCS].vma);
+			WARN_ON(dctx->engine[RCS].state->active);
+			i915_vma_unpin(dctx->engine[RCS].state);
 			i915_gem_context_unreference(dctx);
 			dev_priv->ring[RCS].last_context = NULL;
 		}
 
-		i915_vma_unpin(dctx->engine[RCS].vma);
+		i915_vma_unpin(dctx->engine[RCS].state);
 	}
 
 	for (i = 0; i < I915_NUM_RINGS; i++) {
@@ -644,7 +655,7 @@ mi_set_context(struct drm_i915_gem_request *req, u32 hw_flags)
 
 	intel_ring_emit(ring, MI_NOOP);
 	intel_ring_emit(ring, MI_SET_CONTEXT);
-	intel_ring_emit(ring, req->ctx->engine[RCS].vma->node.start | flags);
+	intel_ring_emit(ring, req->ctx->engine[RCS].state->node.start | flags);
 	/*
 	 * w/a: MI_SET_CONTEXT must always be followed by MI_NOOP
 	 * WaMiSetContext_Hang:snb,ivb,vlv
@@ -752,6 +763,20 @@ static int remap_l3(struct drm_i915_gem_request *req, int slice)
 	return 0;
 }
 
+static void flush_cpu_writes(struct drm_i915_gem_object *obj)
+{
+	if (obj->base.write_domain == 0)
+		return;
+
+	if (obj->base.write_domain & I915_GEM_DOMAIN_CPU) {
+		if (i915_gem_clflush_object(obj, false))
+			i915_gem_chipset_flush(obj->base.dev);
+	}
+
+	wmb();
+	obj->base.write_domain = 0;
+}
+
 static int do_switch(struct drm_i915_gem_request *req)
 {
 	struct intel_context *to = req->ctx;
@@ -765,20 +790,11 @@ static int do_switch(struct drm_i915_gem_request *req)
 
 	/* Trying to pin first makes error handling easier. */
 	if (engine->id == RCS) {
-		u32 alignment = get_context_alignment(engine->dev);
-		struct i915_vma *vma;
-
-		vma = i915_gem_object_ggtt_pin(to->engine[RCS].state,
-					       NULL, 0, alignment, PIN_HIGH);
-		if (IS_ERR(vma))
-			return PTR_ERR(vma);
-
-		to->engine[RCS].vma = vma;
-
-		if (WARN_ON(!(vma->bound & GLOBAL_BIND))) {
-			ret = -ENODEV;
-			goto unpin_out;
-		}
+		ret = i915_vma_pin(to->engine[RCS].state, 
+				   0, get_context_alignment(engine->dev),
+				   PIN_GLOBAL | PIN_HIGH);
+		if (ret)
+			return ret;
 	}
 
 	/*
@@ -813,16 +829,9 @@ static int do_switch(struct drm_i915_gem_request *req)
 	}
 
 	/*
-	 * Clear this page out of any CPU caches for coherent swap-in/out. Note
-	 * that thanks to write = false in this call and us not setting any gpu
-	 * write domains when putting a context object onto the active list
-	 * (when switching away from it), this won't block.
-	 *
-	 * XXX: We need a real interface to do this instead of trickery.
+	 * Clear this page out of any CPU caches for coherent swap-in/out.
 	 */
-	ret = i915_gem_object_set_to_gtt_domain(to->engine[RCS].state, false);
-	if (ret)
-		goto unpin_out;
+	flush_cpu_writes(to->engine[RCS].state->obj);
 
 	if (!to->engine[RCS].initialised || i915_gem_context_is_default(to)) {
 		hw_flags |= MI_RESTORE_INHIBIT;
@@ -896,9 +905,9 @@ static int do_switch(struct drm_i915_gem_request *req)
 		 * able to defer doing this until we know the object would be
 		 * swapped, but there is no way to do that yet.
 		 */
-		i915_vma_move_to_active(from->engine[RCS].vma, req, 0);
+		i915_vma_move_to_active(from->engine[RCS].state, req, 0);
 		/* obj is kept alive until the next request by its active ref */
-		i915_vma_unpin(from->engine[RCS].vma);
+		i915_vma_unpin(from->engine[RCS].state);
 
 		i915_gem_context_unreference(from);
 	}
@@ -910,7 +919,7 @@ done:
 
 unpin_out:
 	if (engine->id == RCS)
-		i915_vma_unpin(to->engine[RCS].vma);
+		i915_vma_unpin(to->engine[RCS].state);
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c
index 6fbb11a53b60..f0249dafda07 100644
--- a/drivers/gpu/drm/i915/i915_gpu_error.c
+++ b/drivers/gpu/drm/i915/i915_gpu_error.c
@@ -986,7 +986,7 @@ static void i915_gem_record_rings(struct drm_device *dev,
 
 			error->ring[i].ctx =
 				i915_error_object_create(dev_priv,
-							 request->ctx->engine[i].vma);
+							 request->ctx->engine[i].state);
 
 			pid = request->ctx->pid;
 			if (pid) {
diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
index d6df94129796..17d23f55367c 100644
--- a/drivers/gpu/drm/i915/i915_guc_submission.c
+++ b/drivers/gpu/drm/i915/i915_guc_submission.c
@@ -407,7 +407,7 @@ static void guc_init_ctx_desc(struct intel_guc *guc,
 		lrc->context_desc = engine->execlist_context_descriptor;
 
 		/* The state page is after PPHWSP */
-		lrc->ring_lcra = ctx->engine[i].vma->node.start +
+		lrc->ring_lcra = ctx->engine[i].state->node.start +
 				LRC_STATE_PN * PAGE_SIZE;
 		lrc->context_id = (client->ctx_index << GUC_ELC_CTXID_OFFSET) |
 				(engine->id << GUC_ELC_ENGINE_OFFSET);
@@ -987,7 +987,7 @@ int intel_guc_suspend(struct drm_device *dev)
 	/* any value greater than GUC_POWER_D0 */
 	data[1] = GUC_POWER_D1;
 	/* first page is shared data with GuC */
-	data[2] = ctx->engine[RCS].vma->node.start;
+	data[2] = ctx->engine[RCS].state->node.start;
 
 	return host2guc_action(guc, data, ARRAY_SIZE(data));
 }
@@ -1012,7 +1012,7 @@ int intel_guc_resume(struct drm_device *dev)
 	data[0] = HOST2GUC_ACTION_EXIT_S_STATE;
 	data[1] = GUC_POWER_D0;
 	/* first page is shared data with GuC */
-	data[2] = ctx->engine[RCS].vma->node.start;
+	data[2] = ctx->engine[RCS].state->node.start;
 
 	return host2guc_action(guc, data, ARRAY_SIZE(data));
 }
diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index 3e61fce1326e..e687b191453a 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -571,7 +571,6 @@ static int intel_lr_context_pin(struct intel_context *ctx,
 				struct intel_engine_cs *engine)
 {
 	struct intel_context_engine *ce = &ctx->engine[engine->id];
-	struct i915_vma *vma;
 	struct intel_ring *ring;
 	u32 ggtt_offset;
 	int ret;
@@ -581,14 +580,11 @@ static int intel_lr_context_pin(struct intel_context *ctx,
 
 	lockdep_assert_held(&engine->dev->struct_mutex);
 
-	vma = i915_gem_object_ggtt_pin(ce->state, NULL,
-				       0, GEN8_LR_CONTEXT_ALIGN,
-				       PIN_OFFSET_BIAS | GUC_WOPCM_TOP |
-				       PIN_HIGH);
-	if (IS_ERR(vma)) {
-		ret = PTR_ERR(vma);
+	ret = i915_vma_pin(ce->state, 0, GEN8_LR_CONTEXT_ALIGN,
+			   PIN_OFFSET_BIAS | GUC_WOPCM_TOP |
+			   PIN_GLOBAL | PIN_HIGH);
+	if (ret)
 		goto err;
-	}
 
 	ring = ce->ring;
 	ret = intel_ring_map(ring);
@@ -596,15 +592,15 @@ static int intel_lr_context_pin(struct intel_context *ctx,
 		goto unpin;
 
 	i915_gem_context_reference(ctx);
-	ce->vma = vma;
-	i915_gem_object_set_dirty(vma->obj);
+	i915_gem_object_set_dirty(ce->state->obj);
 
-	ggtt_offset = vma->node.start + LRC_PPHWSP_PN * PAGE_SIZE;
+	ggtt_offset = ce->state->node.start + LRC_PPHWSP_PN * PAGE_SIZE;
 	ring->context_descriptor =
 		ggtt_offset | engine->execlist_context_descriptor;
 
 	ring->registers =
-		kmap(i915_gem_object_get_dirty_page(vma->obj, LRC_STATE_PN));
+		kmap(i915_gem_object_get_dirty_page(ce->state->obj,
+						    LRC_STATE_PN));
 	ring->registers[CTX_RING_BUFFER_START+1] = ring->vma->node.start;
 
 	/* Invalidate GuC TLB. */
@@ -616,7 +612,7 @@ static int intel_lr_context_pin(struct intel_context *ctx,
 	return 0;
 
 unpin:
-	__i915_vma_unpin(vma);
+	__i915_vma_unpin(ce->state);
 err:
 	ce->pin_count = 0;
 	return ret;
@@ -626,7 +622,6 @@ void intel_lr_context_unpin(struct intel_context *ctx,
 			    struct intel_engine_cs *engine)
 {
 	struct intel_context_engine *ce = &ctx->engine[engine->id];
-	struct i915_vma *vma;
 
 	lockdep_assert_held(&engine->dev->struct_mutex);
 	if (--ce->pin_count)
@@ -634,9 +629,8 @@ void intel_lr_context_unpin(struct intel_context *ctx,
 
 	intel_ring_unmap(ce->ring);
 
-	vma = ce->vma;
-	kunmap(i915_gem_object_get_page(vma->obj, LRC_STATE_PN));
-	i915_vma_unpin(vma);
+	kunmap(i915_gem_object_get_page(ce->state->obj, LRC_STATE_PN));
+	i915_vma_unpin(ce->state);
 
 	i915_gem_context_unreference(ctx);
 }
@@ -1064,7 +1058,7 @@ static int gen8_init_common_ring(struct intel_engine_cs *ring)
 	struct drm_device *dev = ring->dev;
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	lrc_setup_hardware_status_page(ring,
-			dev_priv->kernel_context->engine[ring->id].vma);
+			dev_priv->kernel_context->engine[ring->id].state);
 
 	I915_WRITE_IMR(ring, ~(ring->irq_enable_mask | ring->irq_keep_mask));
 	I915_WRITE(RING_HWSTAM(ring->mmio_base), 0xffffffff);
@@ -1935,6 +1929,7 @@ static int execlists_context_deferred_alloc(struct intel_context *ctx,
 {
 	struct intel_context_engine *ce = &ctx->engine[engine->id];
 	struct drm_i915_gem_object *ctx_obj;
+	struct i915_vma *vma;
 	uint32_t context_size;
 	struct intel_ring *ring;
 	int ret;
@@ -1952,6 +1947,14 @@ static int execlists_context_deferred_alloc(struct intel_context *ctx,
 		return -ENOMEM;
 	}
 
+	vma = i915_gem_obj_lookup_or_create_vma(ctx_obj,
+						&engine->i915->gtt.base,
+						NULL);
+	if (IS_ERR(vma)) {
+		ret = PTR_ERR(vma);
+		goto error_deref_obj;
+	}
+
 	ring = intel_engine_create_ring(engine, 4 * PAGE_SIZE);
 	if (IS_ERR(ring)) {
 		ret = PTR_ERR(ring);
@@ -1965,7 +1968,7 @@ static int execlists_context_deferred_alloc(struct intel_context *ctx,
 	}
 
 	ce->ring = ring;
-	ce->state = ctx_obj;
+	ce->state = vma;
 	ce->initialised = engine->init_context == NULL;
 
 	return 0;
@@ -1974,8 +1977,6 @@ error_ringbuf:
 	intel_ring_free(ring);
 error_deref_obj:
 	drm_gem_object_unreference(&ctx_obj->base);
-	ce->ring = NULL;
-	ce->state = NULL;
 	return ret;
 }
 
@@ -1988,17 +1989,19 @@ void intel_lr_context_reset(struct drm_device *dev,
 
 	for_each_ring(unused, dev_priv, i) {
 		struct intel_context_engine *ce = &ctx->engine[i];
+		struct drm_i915_gem_object *obj;
 		uint32_t *reg_state;
 		struct page *page;
 
 		if (ce->state == NULL)
 			continue;
 
-		if (i915_gem_object_get_pages(ce->state)) {
-			WARN(1, "Failed get_pages for context obj\n");
+		obj = ce->state->obj;
+		if (WARN(i915_gem_object_get_pages(obj),
+			 "Failed get_pages for context obj\n"))
 			continue;
-		}
-		page = i915_gem_object_get_dirty_page(ce->state, LRC_STATE_PN);
+
+		page = i915_gem_object_get_dirty_page(obj, LRC_STATE_PN);
 		reg_state = kmap_atomic(page);
 
 		reg_state[CTX_RING_HEAD+1] = ce->ring->head;
-- 
2.7.0.rc3



More information about the Intel-gfx mailing list