[Intel-gfx] [PATCH v2 3/5] drm/i915: context submission pvmmio optimization

Xiaolin Zhang xiaolin.zhang at intel.com
Fri Oct 19 07:27:12 UTC 2018


It is performance optimization to reduce mmio trap numbers from 4 to
1 durning ELSP porting writing (context submission).

When context subission, to cache elsp_data[4] values in
the shared page, the last elsp_data[0] port writing will be trapped
to gvt for real context submission.

Use PVMMIO_ELSP_SUBMIT to control this level of pvmmio optimization.

v0: RFC
v1: rebase
v2: added pv ops for pv context submission. to maximize code resuse,
introduced 2 more ops (submit_ports & preempt_context) instead of 1 op
(set_default_submission) in engine structure. pv version of
submit_ports and preempt_context implemented.

Cc: Zhenyu Wang <zhenyuw at linux.intel.com>
Cc: Zhi Wang <zhi.a.wang at intel.com>
Cc: Chris Wilson <chris at chris-wilson.co.uk>
Cc: Joonas Lahtinen <joonas.lahtinen at linux.intel.com>
Cc: He, Min <min.he at intel.com>
Cc: Jiang, Fei <fei.jiang at intel.com>
Cc: Gong, Zhipeng <zhipeng.gong at intel.com>
Cc: Yuan, Hang <hang.yuan at intel.com>
Cc: Zhiyuan Lv <zhiyuan.lv at intel.com>
Signed-off-by: Xiaolin Zhang <xiaolin.zhang at intel.com>
---
 drivers/gpu/drm/i915/i915_vgpu.c        |  2 +
 drivers/gpu/drm/i915/intel_lrc.c        | 88 +++++++++++++++++++++++++++++++--
 drivers/gpu/drm/i915/intel_ringbuffer.h |  3 ++
 3 files changed, 90 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_vgpu.c b/drivers/gpu/drm/i915/i915_vgpu.c
index cb409d5..9870ea6 100644
--- a/drivers/gpu/drm/i915/i915_vgpu.c
+++ b/drivers/gpu/drm/i915/i915_vgpu.c
@@ -66,6 +66,8 @@ void i915_check_vgpu(struct drm_i915_private *dev_priv)
 
 	BUILD_BUG_ON(sizeof(struct vgt_if) != VGT_PVINFO_SIZE);
 
+	dev_priv->vgpu.pv_caps = PVMMIO_ELSP_SUBMIT;
+
 	magic = __raw_i915_read64(dev_priv, vgtif_reg(magic));
 	if (magic != VGT_MAGIC)
 		return;
diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index 22b57b8..9e6ccf9 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -460,6 +460,60 @@ static void execlists_submit_ports(struct intel_engine_cs *engine)
 	execlists_clear_active(execlists, EXECLISTS_ACTIVE_HWACK);
 }
 
+static void execlists_submit_ports_pv(struct intel_engine_cs *engine)
+{
+	struct intel_engine_execlists *execlists = &engine->execlists;
+	struct execlist_port *port = execlists->port;
+	u32 __iomem *elsp =
+		engine->i915->regs + i915_mmio_reg_offset(RING_ELSP(engine));
+	u32 *elsp_data;
+	unsigned int n;
+	u32 descs[4];
+	int i = 0;
+
+	/*
+	 * ELSQ note: the submit queue is not cleared after being submitted
+	 * to the HW so we need to make sure we always clean it up. This is
+	 * currently ensured by the fact that we always write the same number
+	 * of elsq entries, keep this in mind before changing the loop below.
+	 */
+	for (n = execlists_num_ports(execlists); n--; ) {
+		struct i915_request *rq;
+		unsigned int count;
+		u64 desc;
+
+		rq = port_unpack(&port[n], &count);
+		if (rq) {
+			GEM_BUG_ON(count > !n);
+			if (!count++)
+				execlists_context_schedule_in(rq);
+			port_set(&port[n], port_pack(rq, count));
+			desc = execlists_update_context(rq);
+		} else {
+			GEM_BUG_ON(!n);
+			desc = 0;
+		}
+		GEM_BUG_ON(i >= 4);
+		descs[i] = upper_32_bits(desc);
+		descs[i + 1] = lower_32_bits(desc);
+		i += 2;
+	}
+
+	spin_lock(&engine->i915->vgpu.shared_page_lock);
+	elsp_data = engine->i915->vgpu.shared_page->elsp_data;
+	*elsp_data = descs[0];
+	*(elsp_data + 1) = descs[1];
+	*(elsp_data + 2) = descs[2];
+	writel(descs[3], elsp);
+	spin_unlock(&engine->i915->vgpu.shared_page_lock);
+
+	/* we need to manually load the submit queue */
+	if (execlists->ctrl_reg)
+		writel(EL_CTRL_LOAD, execlists->ctrl_reg);
+
+	execlists_clear_active(execlists, EXECLISTS_ACTIVE_HWACK);
+}
+
 static bool ctx_single_port_submission(const struct intel_context *ce)
 {
 	return (IS_ENABLED(CONFIG_DRM_I915_GVT) &&
@@ -497,7 +551,6 @@ static void inject_preempt_context(struct intel_engine_cs *engine)
 
 	GEM_BUG_ON(execlists->preempt_complete_status !=
 		   upper_32_bits(ce->lrc_desc));
-
 	/*
 	 * Switch to our empty preempt context so
 	 * the state of the GPU is known (idle).
@@ -516,6 +569,27 @@ static void inject_preempt_context(struct intel_engine_cs *engine)
 	execlists_set_active(execlists, EXECLISTS_ACTIVE_PREEMPT);
 }
 
+static void inject_preempt_context_pv(struct intel_engine_cs *engine)
+{
+	struct intel_engine_execlists *execlists = &engine->execlists;
+	struct intel_context *ce =
+		to_intel_context(engine->i915->preempt_context, engine);
+	u32 __iomem *elsp =
+		engine->i915->regs + i915_mmio_reg_offset(RING_ELSP(engine));
+	u32 *elsp_data;
+
+	GEM_BUG_ON(execlists->preempt_complete_status !=
+		   upper_32_bits(ce->lrc_desc));
+
+	spin_lock(&engine->i915->vgpu.shared_page_lock);
+	elsp_data = engine->i915->vgpu.shared_page->elsp_data;
+	*elsp_data = 0;
+	*(elsp_data + 1) = 0;
+	*(elsp_data + 2) = upper_32_bits(ce->lrc_desc);
+	writel(lower_32_bits(ce->lrc_desc), elsp);
+	spin_unlock(&engine->i915->vgpu.shared_page_lock);
+}
+
 static void complete_preempt_context(struct intel_engine_execlists *execlists)
 {
 	GEM_BUG_ON(!execlists_is_active(execlists, EXECLISTS_ACTIVE_PREEMPT));
@@ -583,7 +657,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
 			return;
 
 		if (need_preempt(engine, last, execlists->queue_priority)) {
-			inject_preempt_context(engine);
+			engine->preempt_context(engine);
 			return;
 		}
 
@@ -705,7 +779,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
 
 	if (submit) {
 		port_assign(port, last);
-		execlists_submit_ports(engine);
+		engine->submit_ports(engine);
 	}
 
 	/* We must always keep the beast fed if we have work piled up */
@@ -2134,6 +2208,14 @@ void intel_execlists_set_default_submission(struct intel_engine_cs *engine)
 
 	engine->reset.prepare = execlists_reset_prepare;
 
+	engine->preempt_context = inject_preempt_context;
+	engine->submit_ports = execlists_submit_ports;
+
+	if (PVMMIO_LEVEL_ENABLE(engine->i915, PVMMIO_ELSP_SUBMIT)) {
+		engine->preempt_context = inject_preempt_context_pv;
+		engine->submit_ports = execlists_submit_ports_pv;
+	}
+
 	engine->park = NULL;
 	engine->unpark = NULL;
 
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index f6ec48a..e9895bf 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -523,6 +523,9 @@ struct intel_engine_cs {
 	void		(*irq_seqno_barrier)(struct intel_engine_cs *engine);
 	void		(*cleanup)(struct intel_engine_cs *engine);
 
+	void		(*preempt_context)(struct intel_engine_cs *engine);
+	void		(*submit_ports)(struct intel_engine_cs *engine);
+
 	/* GEN8 signal/wait table - never trust comments!
 	 *	  signal to	signal to    signal to   signal to      signal to
 	 *	    RCS		   VCS          BCS        VECS		 VCS2
-- 
2.7.4



More information about the Intel-gfx mailing list