[PATCH] defaults

Chris Wilson chris at chris-wilson.co.uk
Tue Oct 31 22:17:46 UTC 2017


---
 drivers/gpu/drm/i915/intel_lrc.c        | 170 +++++++++++++++++++++++++++++---
 drivers/gpu/drm/i915/intel_ringbuffer.h |   1 +
 2 files changed, 160 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index 6840ec8db037..2f7d17927202 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -1437,6 +1437,18 @@ static u8 gtiir[] = {
 	[VECS] = 3,
 };
 
+static void enable_execlists(struct intel_engine_cs *engine)
+{
+	struct drm_i915_private *dev_priv = engine->i915;
+
+	I915_WRITE(RING_HWSTAM(engine->mmio_base), 0xffffffff);
+	I915_WRITE(RING_MODE_GEN7(engine),
+		   _MASKED_BIT_ENABLE(GFX_RUN_LIST_ENABLE));
+	I915_WRITE(RING_HWS_PGA(engine->mmio_base),
+		   engine->status_page.ggtt_offset);
+	POSTING_READ(RING_HWS_PGA(engine->mmio_base));
+}
+
 static int gen8_init_common_ring(struct intel_engine_cs *engine)
 {
 	struct drm_i915_private *dev_priv = engine->i915;
@@ -1450,13 +1462,7 @@ static int gen8_init_common_ring(struct intel_engine_cs *engine)
 	intel_engine_reset_breadcrumbs(engine);
 	intel_engine_init_hangcheck(engine);
 
-	I915_WRITE(RING_HWSTAM(engine->mmio_base), 0xffffffff);
-	I915_WRITE(RING_MODE_GEN7(engine),
-		   _MASKED_BIT_ENABLE(GFX_RUN_LIST_ENABLE));
-	I915_WRITE(RING_HWS_PGA(engine->mmio_base),
-		   engine->status_page.ggtt_offset);
-	POSTING_READ(RING_HWS_PGA(engine->mmio_base));
-
+	enable_execlists(engine);
 	DRM_DEBUG_DRIVER("Execlists enabled for %s\n", engine->name);
 
 	GEM_BUG_ON(engine->id >= ARRAY_SIZE(gtiir));
@@ -1871,6 +1877,12 @@ void intel_logical_ring_cleanup(struct intel_engine_cs *engine)
 	intel_engine_cleanup_common(engine);
 
 	lrc_destroy_wa_ctx(engine);
+
+	if (engine->default_state) {
+		i915_gem_object_unpin_map(engine->default_state);
+		i915_gem_object_put(engine->default_state);
+	}
+
 	engine->i915 = NULL;
 	dev_priv->engine[engine->id] = NULL;
 	kfree(engine);
@@ -1918,6 +1930,122 @@ logical_ring_default_irqs(struct intel_engine_cs *engine)
 	engine->irq_keep_mask = GT_CONTEXT_SWITCH_INTERRUPT << shift;
 }
 
+static bool csb_idle(struct intel_engine_cs *engine)
+{
+	struct drm_i915_private *i915 = engine->i915;
+	u32 __iomem *status =
+		i915->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_BUF_LO(engine, 0));
+	u32 __iomem *ring =
+		i915->regs + i915_mmio_reg_offset(RING_CONTEXT_STATUS_PTR(engine));
+	u32 head, tail;
+	bool idle = false;
+
+	head = ioread32(ring);
+	tail = GEN8_CSB_WRITE_PTR(head);
+	head = GEN8_CSB_READ_PTR(head);
+
+	if (head >= GEN8_CSB_ENTRIES || tail >= GEN8_CSB_ENTRIES)
+		return false;
+
+	while (head != tail) {
+		if (++head == GEN8_CSB_ENTRIES)
+			head = 0;
+
+		if (ioread32(status + 2 * head) & GEN8_CTX_STATUS_ACTIVE_IDLE)
+			idle = true;
+	}
+
+	iowrite32(_MASKED_FIELD(GEN8_CSB_READ_PTR_MASK, head << 8), ring);
+
+	return idle;
+}
+
+static int lrc_record_defaults(struct intel_engine_cs *engine)
+{
+	struct drm_i915_private *i915 = engine->i915;
+	u32 __iomem *elsp =
+		i915->regs + i915_mmio_reg_offset(RING_ELSP(engine));
+	struct i915_gem_context *kctx = i915->kernel_context;
+	struct intel_context *ce = &kctx->engine[engine->id];
+	struct drm_i915_gem_object *obj;
+	struct i915_vma *vma;
+	u32 context_size;
+	void *vaddr;
+	u32 *regs;
+	u64 desc;
+	int err;
+
+	/*
+	 * As we reset the gpu during very early sanitisation, the current
+	 * register state on the GPU should reflect its defaults values.
+	 * We load a context onto the hw (with restore-inhibit), then switch
+	 * over to a second context to save that default register state. We
+	 * then prime every new context with that state so they all start
+	 * from defaults.
+	 */
+
+	GEM_BUG_ON(engine->default_state);
+
+	intel_runtime_pm_get(i915);
+	intel_uncore_forcewake_get(i915, FORCEWAKE_ALL);
+
+	context_size = round_up(engine->context_size, I915_GTT_PAGE_SIZE);
+	obj = i915_gem_object_create_internal(i915, context_size);
+	if (IS_ERR(obj)) {
+		err = PTR_ERR(obj);
+		goto out_rpm;
+	}
+
+	vma = i915_vma_instance(obj, &i915->ggtt.base, NULL);
+	if (IS_ERR(vma)) {
+		err = PTR_ERR(vma);
+		goto out_obj;
+	}
+
+	err = i915_vma_pin(vma, 0, GEN8_LR_CONTEXT_ALIGN, PIN_GLOBAL);
+	if (err)
+		goto out_obj;
+
+	vaddr = i915_gem_object_pin_map(obj, I915_MAP_WB);
+	if (IS_ERR(vaddr)) {
+		err = PTR_ERR(vaddr);
+		goto out_vma;
+	}
+
+	regs = vaddr + PAGE_SIZE;
+	execlists_init_reg_state(regs, kctx, engine, ce->ring);
+	regs[CTX_CONTEXT_CONTROL+1] |=
+		_MASKED_BIT_ENABLE(CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT);
+
+	desc = kctx->desc_template;
+	desc |= i915_ggtt_offset(vma);
+	desc |= (u64)(MAX_CONTEXT_HW_ID - 1) << GEN8_CTX_ID_SHIFT;
+
+	/* ELSP is programmed backwards. 2nd context first, 1st context last. */
+	enable_execlists(engine);
+	elsp_write(ce->lrc_desc, elsp);
+	elsp_write(desc, elsp);
+
+	msleep(1);
+	if (!wait_for(csb_idle(engine), 1000)) {
+		/* Keep a ref on the pages and owner */
+		engine->default_state = i915_gem_object_get(obj);
+	} else {
+		i915_gem_object_unpin_map(obj);
+		err = -EIO;
+	}
+
+out_vma:
+	i915_vma_unpin(vma);
+out_obj:
+	i915_gem_object_put(obj);
+out_rpm:
+	intel_uncore_forcewake_put(i915, FORCEWAKE_ALL);
+	intel_runtime_pm_put(i915);
+
+	return err;
+}
+
 static void
 logical_ring_setup(struct intel_engine_cs *engine)
 {
@@ -1958,6 +2086,10 @@ static int logical_ring_init(struct intel_engine_cs *engine)
 	if (ret)
 		goto error;
 
+	ret = lrc_record_defaults(engine);
+	if (ret)
+		goto error;
+
 	return 0;
 
 error:
@@ -2100,7 +2232,6 @@ static void execlists_init_reg_state(u32 *regs,
 
 	CTX_REG(regs, CTX_CONTEXT_CONTROL, RING_CONTEXT_CONTROL(engine),
 		_MASKED_BIT_ENABLE(CTX_CTRL_INHIBIT_SYN_CTX_SWITCH |
-				   CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT |
 				   (HAS_RESOURCE_STREAMER(dev_priv) ?
 				   CTX_CTRL_RS_CTX_ENABLE : 0)));
 	CTX_REG(regs, CTX_RING_HEAD, RING_HEAD(base), 0);
@@ -2177,6 +2308,7 @@ populate_lr_context(struct i915_gem_context *ctx,
 		    struct intel_ring *ring)
 {
 	void *vaddr;
+	u32 *regs;
 	int ret;
 
 	ret = i915_gem_object_set_to_cpu_domain(ctx_obj, true);
@@ -2193,11 +2325,27 @@ populate_lr_context(struct i915_gem_context *ctx,
 	}
 	ctx_obj->mm.dirty = true;
 
+	if (engine->default_state) {
+		void *defaults;
+
+		defaults = i915_gem_object_pin_map(engine->default_state,
+						   I915_MAP_WB);
+		if (IS_ERR(defaults))
+			return PTR_ERR(defaults);
+
+		memcpy(vaddr + LRC_HEADER_PAGES * PAGE_SIZE,
+		       defaults, engine->context_size);
+		i915_gem_object_unpin_map(engine->default_state);
+	}
+
 	/* The second page of the context object contains some fields which must
 	 * be set up prior to the first execution. */
-
-	execlists_init_reg_state(vaddr + LRC_STATE_PN * PAGE_SIZE,
-				 ctx, engine, ring);
+	regs = vaddr + LRC_STATE_PN * PAGE_SIZE,
+	execlists_init_reg_state(regs, ctx, engine, ring);
+	if (!engine->default_state) {
+		regs[CTX_CONTEXT_CONTROL+1] |=
+			_MASKED_BIT_ENABLE(CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT);
+	}
 
 	i915_gem_object_unpin_map(ctx_obj);
 
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index 69ad875fd011..1d752b9a3065 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -303,6 +303,7 @@ struct intel_engine_cs {
 	struct intel_ring *buffer;
 	struct intel_timeline *timeline;
 
+	struct drm_i915_gem_object *default_state;
 	struct intel_render_state *render_state;
 
 	atomic_t irq_count;
-- 
2.15.0.rc2



More information about the Intel-gfx-trybot mailing list