From: Dave Gordon <david.s.gordon@xxxxxxxxx> 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@xxxxxxxxx> --- 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 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx