[Intel-gfx] [RFC 12/37] drm/i915/guc: implement submission via REQUEST_PREEMPTION action

John.C.Harrison at Intel.com John.C.Harrison at Intel.com
Mon Nov 23 03:41:47 PST 2015


From: Dave Gordon <david.s.gordon at intel.com>

If a batch is submitted via the preemptive (KMD_HIGH-priority) client
then instead of ringing the doorbell we dispatch it using the GuC
"REQUEST_PREEMPTION" action. Also, we specify "clear work queue" and
"clear submit queue" in that request, so the scheduler can reconsider
what is to be done next after preemption.

Note that the preemption request requires a reference to the GuC per-
context shared data, which in early versions of the GuC firmware was at
the end of the context object but nowadays is at the start.

For: VIZ-2021
Signed-off-by: Dave Gordon <david.s.gordon at intel.com>
---
 drivers/gpu/drm/i915/i915_guc_submission.c | 64 ++++++++++++++++++++++++++++--
 drivers/gpu/drm/i915/intel_guc_fwif.h      |  7 ++++
 drivers/gpu/drm/i915/intel_lrc.c           | 26 +++++++-----
 3 files changed, 84 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
index d8fd644..4035ac6 100644
--- a/drivers/gpu/drm/i915/i915_guc_submission.c
+++ b/drivers/gpu/drm/i915/i915_guc_submission.c
@@ -94,7 +94,8 @@ static int host2guc_action(struct intel_guc *guc, u32 *data, u32 len)
 	for (i = 0; i < len; i++)
 		I915_WRITE(SOFT_SCRATCH(i), data[i]);
 
-	POSTING_READ(SOFT_SCRATCH(i - 1));
+	I915_WRITE(SOFT_SCRATCH(15), 0);
+	POSTING_READ(SOFT_SCRATCH(0));
 
 	I915_WRITE(HOST2GUC_INTERRUPT, HOST2GUC_TRIGGER);
 
@@ -126,6 +127,55 @@ static int host2guc_action(struct intel_guc *guc, u32 *data, u32 len)
 }
 
 /*
+ * Tell the GuC to submit a request pre-emptively
+ */
+static int
+host2guc_preempt(struct i915_guc_client *client,
+		 struct intel_context *ctx,
+		 struct intel_engine_cs *ring)
+{
+	struct drm_i915_private *dev_priv = ring->dev->dev_private;
+	struct intel_guc *guc = &dev_priv->guc;
+	uint32_t engine_id = ring->id;
+	struct drm_i915_gem_object *ctx_obj = ctx->engine[engine_id].state;
+	struct intel_ringbuffer *ringbuf = ctx->engine[engine_id].ringbuf;
+	struct guc_process_desc *desc;
+	void *base;
+	u32 data[7];
+	int ret;
+
+	if (WARN_ON(!ctx_obj || !ringbuf))
+		return -EINVAL;
+
+	WARN_ON(!i915_gem_obj_is_pinned(ctx_obj));
+	WARN_ON(!i915_gem_obj_is_pinned(ringbuf->obj));
+
+	WARN_ON(guc->preempt_client != client);
+
+	base = kmap_atomic(i915_gem_object_get_page(client->client_obj, 0));
+	desc = base + client->proc_desc_offset;
+
+	/* Update the tail so it is visible to GuC */
+	desc->tail = client->wq_tail;
+	kunmap_atomic(base);
+
+	data[0] = HOST2GUC_ACTION_REQUEST_PREEMPTION;
+	data[1] = guc->preempt_client->ctx_index;		// preemptive client
+	data[2] = /* PREEMPT_ENGINE_OPTIONS */
+		  HOST2GUC_PREEMPT_OPTION_IMMEDIATE |		// submit before return
+		  HOST2GUC_PREEMPT_OPTION_DROP_WORK_Q |		// drop wq for client data[5]
+		  HOST2GUC_PREEMPT_OPTION_DROP_SUBMIT_Q;	// drop submitted (engine, priority)
+	data[3] = engine_id;					// target engine
+	data[4] = guc->execbuf_client->priority;		// victim priority
+	data[5] = guc->execbuf_client->ctx_index;		// victim ctx/wq
+	data[6] = i915_gem_obj_ggtt_offset(ctx_obj) + LRC_GUCSHR_PN*PAGE_SIZE;
+
+	ret = host2guc_action(guc, data, 7);
+	WARN_ON(ret);
+	return ret;
+}
+
+/*
  * Tell the GuC to allocate or deallocate a specific doorbell
  */
 
@@ -585,8 +635,9 @@ static void lr_context_update(struct drm_i915_gem_request *rq)
 int i915_guc_submit(struct i915_guc_client *client,
 		    struct drm_i915_gem_request *rq)
 {
-	struct intel_guc *guc = client->guc;
+	bool preemptive = client->priority <= GUC_CTX_PRIORITY_HIGH;
 	enum intel_ring_id ring_id = rq->ring->id;
+	struct intel_guc *guc = client->guc;
 	unsigned long flags;
 	int q_ret, b_ret;
 
@@ -600,8 +651,12 @@ int i915_guc_submit(struct i915_guc_client *client,
 	spin_lock_irqsave(&client->wq_lock, flags);
 
 	q_ret = guc_add_workqueue_item(client, rq);
-	if (q_ret == 0)
-		b_ret = guc_ring_doorbell(client);
+	if (q_ret == 0) {
+		if (preemptive)
+			b_ret = host2guc_preempt(client, rq->ctx, rq->ring);
+		else
+			b_ret = guc_ring_doorbell(client);
+	}
 
 	client->submissions[ring_id] += 1;
 	if (q_ret) {
@@ -612,6 +667,7 @@ int i915_guc_submit(struct i915_guc_client *client,
 		client->retcode = q_ret = b_ret;
 	} else {
 		client->retcode = 0;
+		rq->elsp_submitted += 1;
 	}
 	spin_unlock_irqrestore(&client->wq_lock, flags);
 
diff --git a/drivers/gpu/drm/i915/intel_guc_fwif.h b/drivers/gpu/drm/i915/intel_guc_fwif.h
index 40b2ea5..48da20d 100644
--- a/drivers/gpu/drm/i915/intel_guc_fwif.h
+++ b/drivers/gpu/drm/i915/intel_guc_fwif.h
@@ -302,6 +302,7 @@ struct guc_context_desc {
 /* This Action will be programmed in C180 - SOFT_SCRATCH_O_REG */
 enum host2guc_action {
 	HOST2GUC_ACTION_DEFAULT = 0x0,
+	HOST2GUC_ACTION_REQUEST_PREEMPTION = 0x2,
 	HOST2GUC_ACTION_SAMPLE_FORCEWAKE = 0x6,
 	HOST2GUC_ACTION_ALLOCATE_DOORBELL = 0x10,
 	HOST2GUC_ACTION_DEALLOCATE_DOORBELL = 0x20,
@@ -311,6 +312,12 @@ enum host2guc_action {
 	HOST2GUC_ACTION_LIMIT
 };
 
+enum action_preempt_options {
+	HOST2GUC_PREEMPT_OPTION_IMMEDIATE = 0x1,
+	HOST2GUC_PREEMPT_OPTION_DROP_WORK_Q = 0x4,
+	HOST2GUC_PREEMPT_OPTION_DROP_SUBMIT_Q = 0x8,
+};
+
 /*
  * The GuC sends its response to a command by overwriting the
  * command in SS0. The response is distinguishable from a command
diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index 296d900..e99ae53 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -746,6 +746,9 @@ intel_logical_ring_advance_and_submit(struct drm_i915_gem_request *request)
 {
 	struct intel_engine_cs *ring = request->ring;
 	struct drm_i915_private *dev_priv = request->i915;
+	struct i915_guc_client *client = dev_priv->guc.execbuf_client;
+	const static bool fake = false;	/* true => only pretend to preempt */
+	bool preemptive = false;	/* for now */
 
 	intel_logical_ring_advance(request->ringbuf);
 
@@ -754,8 +757,11 @@ intel_logical_ring_advance_and_submit(struct drm_i915_gem_request *request)
 	if (intel_ring_stopped(ring))
 		return;
 
-	if (dev_priv->guc.execbuf_client)
-		i915_guc_submit(dev_priv->guc.execbuf_client, request);
+	if (preemptive && dev_priv->guc.preempt_client && !fake)
+		client = dev_priv->guc.preempt_client;
+
+	if (client)
+		i915_guc_submit(client, request);
 	else
 		execlists_context_queue(request);
 }
@@ -1894,6 +1900,7 @@ static int gen8_emit_request(struct drm_i915_gem_request *request)
 {
 	struct intel_ringbuffer *ringbuf = request->ringbuf;
 	struct intel_engine_cs *ring = ringbuf->ring;
+	u64 addr;
 	u32 cmd;
 	int ret;
 
@@ -1906,14 +1913,15 @@ static int gen8_emit_request(struct drm_i915_gem_request *request)
 	if (ret)
 		return ret;
 
-	cmd = MI_STORE_DWORD_IMM_GEN4;
-	cmd |= MI_GLOBAL_GTT;
-
+	cmd = MI_STORE_DWORD_IMM_GEN4 | MI_GLOBAL_GTT;
 	intel_logical_ring_emit(ringbuf, cmd);
-	intel_logical_ring_emit(ringbuf,
-				(ring->status_page.gfx_addr +
-				(I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT)));
-	intel_logical_ring_emit(ringbuf, 0);
+
+	addr = I915_GEM_HWS_INDEX;
+	addr <<= MI_STORE_DWORD_INDEX_SHIFT;
+	addr += ring->status_page.gfx_addr;
+	intel_logical_ring_emit(ringbuf, lower_32_bits(addr));
+	intel_logical_ring_emit(ringbuf, upper_32_bits(addr));
+
 	intel_logical_ring_emit(ringbuf, i915_gem_request_get_seqno(request));
 	intel_logical_ring_emit(ringbuf, MI_USER_INTERRUPT);
 	intel_logical_ring_emit(ringbuf, MI_NOOP);
-- 
1.9.1



More information about the Intel-gfx mailing list