Message ID | 20180503063757.22238-9-chris@chris-wilson.co.uk (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On 03/05/2018 07:36, Chris Wilson wrote: > To ease the frequent and ugly pointer dance of > &request->gem_context->engine[request->engine->id] during request > submission, store that pointer as request->hw_context. One major > advantage that we will exploit later is that this decouples the logical > context state from the engine itself. > > v2: Set mock_context->ops so we don't crash and burn in selftests. > Cleanups from Tvrtko. > > Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> > Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> > --- > drivers/gpu/drm/i915/gvt/mmio_context.c | 6 +- > drivers/gpu/drm/i915/gvt/mmio_context.h | 2 +- > drivers/gpu/drm/i915/gvt/scheduler.c | 141 +++++++----------- > drivers/gpu/drm/i915/gvt/scheduler.h | 1 - > drivers/gpu/drm/i915/i915_drv.h | 1 + > drivers/gpu/drm/i915/i915_gem.c | 12 +- > drivers/gpu/drm/i915/i915_gem_context.c | 17 ++- > drivers/gpu/drm/i915/i915_gem_context.h | 21 ++- > drivers/gpu/drm/i915/i915_gpu_error.c | 3 +- > drivers/gpu/drm/i915/i915_perf.c | 25 ++-- > drivers/gpu/drm/i915/i915_request.c | 34 ++--- > drivers/gpu/drm/i915/i915_request.h | 1 + > drivers/gpu/drm/i915/intel_engine_cs.c | 54 ++++--- > drivers/gpu/drm/i915/intel_guc_submission.c | 10 +- > drivers/gpu/drm/i915/intel_lrc.c | 118 +++++++++------ > drivers/gpu/drm/i915/intel_lrc.h | 7 - > drivers/gpu/drm/i915/intel_ringbuffer.c | 100 ++++++++----- > drivers/gpu/drm/i915/intel_ringbuffer.h | 9 +- > drivers/gpu/drm/i915/selftests/mock_context.c | 7 + > drivers/gpu/drm/i915/selftests/mock_engine.c | 41 +++-- > 20 files changed, 320 insertions(+), 290 deletions(-) > > diff --git a/drivers/gpu/drm/i915/gvt/mmio_context.c b/drivers/gpu/drm/i915/gvt/mmio_context.c > index 0f949554d118..708170e61625 100644 > --- a/drivers/gpu/drm/i915/gvt/mmio_context.c > +++ b/drivers/gpu/drm/i915/gvt/mmio_context.c > @@ -446,9 +446,9 @@ static void switch_mocs(struct intel_vgpu *pre, struct intel_vgpu *next, > > #define CTX_CONTEXT_CONTROL_VAL 0x03 > > -bool is_inhibit_context(struct i915_gem_context *ctx, int ring_id) > +bool is_inhibit_context(struct intel_context *ce) > { > - u32 *reg_state = ctx->__engine[ring_id].lrc_reg_state; > + const u32 *reg_state = ce->lrc_reg_state; > u32 inhibit_mask = > _MASKED_BIT_ENABLE(CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT); > > @@ -501,7 +501,7 @@ static void switch_mmio(struct intel_vgpu *pre, > * itself. > */ > if (mmio->in_context && > - !is_inhibit_context(s->shadow_ctx, ring_id)) > + !is_inhibit_context(&s->shadow_ctx->__engine[ring_id])) > continue; > > if (mmio->mask) > diff --git a/drivers/gpu/drm/i915/gvt/mmio_context.h b/drivers/gpu/drm/i915/gvt/mmio_context.h > index 0439eb8057a8..5c3b9ff9f96a 100644 > --- a/drivers/gpu/drm/i915/gvt/mmio_context.h > +++ b/drivers/gpu/drm/i915/gvt/mmio_context.h > @@ -49,7 +49,7 @@ void intel_gvt_switch_mmio(struct intel_vgpu *pre, > > void intel_gvt_init_engine_mmio_context(struct intel_gvt *gvt); > > -bool is_inhibit_context(struct i915_gem_context *ctx, int ring_id); > +bool is_inhibit_context(struct intel_context *ce); > > int intel_vgpu_restore_inhibit_context(struct intel_vgpu *vgpu, > struct i915_request *req); > diff --git a/drivers/gpu/drm/i915/gvt/scheduler.c b/drivers/gpu/drm/i915/gvt/scheduler.c > index f409a154491d..d9aa39d28584 100644 > --- a/drivers/gpu/drm/i915/gvt/scheduler.c > +++ b/drivers/gpu/drm/i915/gvt/scheduler.c > @@ -54,11 +54,8 @@ static void set_context_pdp_root_pointer( > > static void update_shadow_pdps(struct intel_vgpu_workload *workload) > { > - struct intel_vgpu *vgpu = workload->vgpu; > - int ring_id = workload->ring_id; > - struct i915_gem_context *shadow_ctx = vgpu->submission.shadow_ctx; > struct drm_i915_gem_object *ctx_obj = > - shadow_ctx->__engine[ring_id].state->obj; > + workload->req->hw_context->state->obj; > struct execlist_ring_context *shadow_ring_context; > struct page *page; > > @@ -128,9 +125,8 @@ static int populate_shadow_context(struct intel_vgpu_workload *workload) > struct intel_vgpu *vgpu = workload->vgpu; > struct intel_gvt *gvt = vgpu->gvt; > int ring_id = workload->ring_id; > - struct i915_gem_context *shadow_ctx = vgpu->submission.shadow_ctx; > struct drm_i915_gem_object *ctx_obj = > - shadow_ctx->__engine[ring_id].state->obj; > + workload->req->hw_context->state->obj; > struct execlist_ring_context *shadow_ring_context; > struct page *page; > void *dst; > @@ -280,10 +276,8 @@ static int shadow_context_status_change(struct notifier_block *nb, > return NOTIFY_OK; > } > > -static void shadow_context_descriptor_update(struct i915_gem_context *ctx, > - struct intel_engine_cs *engine) > +static void shadow_context_descriptor_update(struct intel_context *ce) > { > - struct intel_context *ce = to_intel_context(ctx, engine); > u64 desc = 0; > > desc = ce->lrc_desc; > @@ -292,7 +286,7 @@ static void shadow_context_descriptor_update(struct i915_gem_context *ctx, > * like GEN8_CTX_* cached in desc_template > */ > desc &= U64_MAX << 12; > - desc |= ctx->desc_template & ((1ULL << 12) - 1); > + desc |= ce->gem_context->desc_template & ((1ULL << 12) - 1); > > ce->lrc_desc = desc; > } > @@ -300,12 +294,11 @@ static void shadow_context_descriptor_update(struct i915_gem_context *ctx, > static int copy_workload_to_ring_buffer(struct intel_vgpu_workload *workload) > { > struct intel_vgpu *vgpu = workload->vgpu; > + struct i915_request *req = workload->req; > void *shadow_ring_buffer_va; > u32 *cs; > - struct i915_request *req = workload->req; > > - if (IS_KABYLAKE(req->i915) && > - is_inhibit_context(req->gem_context, req->engine->id)) > + if (IS_KABYLAKE(req->i915) && is_inhibit_context(req->hw_context)) > intel_vgpu_restore_inhibit_context(vgpu, req); > > /* allocate shadow ring buffer */ > @@ -353,60 +346,56 @@ int intel_gvt_scan_and_shadow_workload(struct intel_vgpu_workload *workload) > struct intel_vgpu_submission *s = &vgpu->submission; > struct i915_gem_context *shadow_ctx = s->shadow_ctx; > struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv; > - int ring_id = workload->ring_id; > - struct intel_engine_cs *engine = dev_priv->engine[ring_id]; > - struct intel_ring *ring; > + struct intel_engine_cs *engine = dev_priv->engine[workload->ring_id]; > + struct intel_context *ce; > int ret; > > lockdep_assert_held(&dev_priv->drm.struct_mutex); > > - if (workload->shadowed) > + if (workload->req) > return 0; > > + /* pin shadow context by gvt even the shadow context will be pinned > + * when i915 alloc request. That is because gvt will update the guest > + * context from shadow context when workload is completed, and at that > + * moment, i915 may already unpined the shadow context to make the > + * shadow_ctx pages invalid. So gvt need to pin itself. After update > + * the guest context, gvt can unpin the shadow_ctx safely. > + */ > + ce = intel_context_pin(shadow_ctx, engine); > + if (IS_ERR(ce)) { > + gvt_vgpu_err("fail to pin shadow context\n"); > + return PTR_ERR(ce); > + } > + > shadow_ctx->desc_template &= ~(0x3 << GEN8_CTX_ADDRESSING_MODE_SHIFT); > shadow_ctx->desc_template |= workload->ctx_desc.addressing_mode << > GEN8_CTX_ADDRESSING_MODE_SHIFT; > > - if (!test_and_set_bit(ring_id, s->shadow_ctx_desc_updated)) > - shadow_context_descriptor_update(shadow_ctx, > - dev_priv->engine[ring_id]); > + if (!test_and_set_bit(workload->ring_id, s->shadow_ctx_desc_updated)) > + shadow_context_descriptor_update(ce); > > ret = intel_gvt_scan_and_shadow_ringbuffer(workload); > if (ret) > - goto err_scan; > + goto err_unpin; > > if ((workload->ring_id == RCS) && > (workload->wa_ctx.indirect_ctx.size != 0)) { > ret = intel_gvt_scan_and_shadow_wa_ctx(&workload->wa_ctx); > if (ret) > - goto err_scan; > - } > - > - /* pin shadow context by gvt even the shadow context will be pinned > - * when i915 alloc request. That is because gvt will update the guest > - * context from shadow context when workload is completed, and at that > - * moment, i915 may already unpined the shadow context to make the > - * shadow_ctx pages invalid. So gvt need to pin itself. After update > - * the guest context, gvt can unpin the shadow_ctx safely. > - */ > - ring = intel_context_pin(shadow_ctx, engine); > - if (IS_ERR(ring)) { > - ret = PTR_ERR(ring); > - gvt_vgpu_err("fail to pin shadow context\n"); > - goto err_shadow; > + goto err_shadow; > } > > ret = populate_shadow_context(workload); > if (ret) > - goto err_unpin; > - workload->shadowed = true; > + goto err_shadow; > + > return 0; > > -err_unpin: > - intel_context_unpin(shadow_ctx, engine); > err_shadow: > release_shadow_wa_ctx(&workload->wa_ctx); > -err_scan: > +err_unpin: > + intel_context_unpin(ce); > return ret; > } > > @@ -414,7 +403,6 @@ static int intel_gvt_generate_request(struct intel_vgpu_workload *workload) > { > int ring_id = workload->ring_id; > struct drm_i915_private *dev_priv = workload->vgpu->gvt->dev_priv; > - struct intel_engine_cs *engine = dev_priv->engine[ring_id]; > struct i915_request *rq; > struct intel_vgpu *vgpu = workload->vgpu; > struct intel_vgpu_submission *s = &vgpu->submission; > @@ -437,7 +425,6 @@ static int intel_gvt_generate_request(struct intel_vgpu_workload *workload) > return 0; > > err_unpin: > - intel_context_unpin(shadow_ctx, engine); > release_shadow_wa_ctx(&workload->wa_ctx); > return ret; > } > @@ -517,21 +504,13 @@ static int prepare_shadow_batch_buffer(struct intel_vgpu_workload *workload) > return ret; > } > > -static int update_wa_ctx_2_shadow_ctx(struct intel_shadow_wa_ctx *wa_ctx) > +static void update_wa_ctx_2_shadow_ctx(struct intel_shadow_wa_ctx *wa_ctx) > { > - struct intel_vgpu_workload *workload = container_of(wa_ctx, > - struct intel_vgpu_workload, > - wa_ctx); > - int ring_id = workload->ring_id; > - struct intel_vgpu_submission *s = &workload->vgpu->submission; > - struct i915_gem_context *shadow_ctx = s->shadow_ctx; > - struct drm_i915_gem_object *ctx_obj = > - shadow_ctx->__engine[ring_id].state->obj; > - struct execlist_ring_context *shadow_ring_context; > - struct page *page; > - > - page = i915_gem_object_get_page(ctx_obj, LRC_STATE_PN); > - shadow_ring_context = kmap_atomic(page); > + struct intel_vgpu_workload *workload = > + container_of(wa_ctx, struct intel_vgpu_workload, wa_ctx); > + struct i915_request *rq = workload->req; > + struct execlist_ring_context *shadow_ring_context = > + (struct execlist_ring_context *)rq->hw_context->lrc_reg_state; > > shadow_ring_context->bb_per_ctx_ptr.val = > (shadow_ring_context->bb_per_ctx_ptr.val & > @@ -539,9 +518,6 @@ static int update_wa_ctx_2_shadow_ctx(struct intel_shadow_wa_ctx *wa_ctx) > shadow_ring_context->rcs_indirect_ctx.val = > (shadow_ring_context->rcs_indirect_ctx.val & > (~INDIRECT_CTX_ADDR_MASK)) | wa_ctx->indirect_ctx.shadow_gma; > - > - kunmap_atomic(shadow_ring_context); > - return 0; > } > > static int prepare_shadow_wa_ctx(struct intel_shadow_wa_ctx *wa_ctx) > @@ -670,12 +646,9 @@ static int prepare_workload(struct intel_vgpu_workload *workload) > static int dispatch_workload(struct intel_vgpu_workload *workload) > { > struct intel_vgpu *vgpu = workload->vgpu; > - struct intel_vgpu_submission *s = &vgpu->submission; > - struct i915_gem_context *shadow_ctx = s->shadow_ctx; > struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv; > int ring_id = workload->ring_id; > - struct intel_engine_cs *engine = dev_priv->engine[ring_id]; > - int ret = 0; > + int ret; > > gvt_dbg_sched("ring id %d prepare to dispatch workload %p\n", > ring_id, workload); > @@ -687,10 +660,6 @@ static int dispatch_workload(struct intel_vgpu_workload *workload) > goto out; > > ret = prepare_workload(workload); > - if (ret) { > - intel_context_unpin(shadow_ctx, engine); > - goto out; > - } > > out: > if (ret) > @@ -765,27 +734,23 @@ static struct intel_vgpu_workload *pick_next_workload( > > static void update_guest_context(struct intel_vgpu_workload *workload) > { > + struct i915_request *rq = workload->req; > struct intel_vgpu *vgpu = workload->vgpu; > struct intel_gvt *gvt = vgpu->gvt; > - struct intel_vgpu_submission *s = &vgpu->submission; > - struct i915_gem_context *shadow_ctx = s->shadow_ctx; > - int ring_id = workload->ring_id; > - struct drm_i915_gem_object *ctx_obj = > - shadow_ctx->__engine[ring_id].state->obj; > + struct drm_i915_gem_object *ctx_obj = rq->hw_context->state->obj; > struct execlist_ring_context *shadow_ring_context; > struct page *page; > void *src; > unsigned long context_gpa, context_page_num; > int i; > > - gvt_dbg_sched("ring id %d workload lrca %x\n", ring_id, > - workload->ctx_desc.lrca); > - > - context_page_num = gvt->dev_priv->engine[ring_id]->context_size; > + gvt_dbg_sched("ring id %d workload lrca %x\n", rq->engine->id, > + workload->ctx_desc.lrca); > > + context_page_num = rq->engine->context_size; > context_page_num = context_page_num >> PAGE_SHIFT; > > - if (IS_BROADWELL(gvt->dev_priv) && ring_id == RCS) > + if (IS_BROADWELL(gvt->dev_priv) && rq->engine->id == RCS) > context_page_num = 19; > > i = 2; > @@ -858,6 +823,7 @@ static void complete_current_workload(struct intel_gvt *gvt, int ring_id) > scheduler->current_workload[ring_id]; > struct intel_vgpu *vgpu = workload->vgpu; > struct intel_vgpu_submission *s = &vgpu->submission; > + struct i915_request *rq; > int event; > > mutex_lock(&gvt->lock); > @@ -866,11 +832,8 @@ static void complete_current_workload(struct intel_gvt *gvt, int ring_id) > * switch to make sure request is completed. > * For the workload w/o request, directly complete the workload. > */ > - if (workload->req) { > - struct drm_i915_private *dev_priv = > - workload->vgpu->gvt->dev_priv; > - struct intel_engine_cs *engine = > - dev_priv->engine[workload->ring_id]; > + rq = fetch_and_zero(&workload->req); > + if (rq) { > wait_event(workload->shadow_ctx_status_wq, > !atomic_read(&workload->shadow_ctx_active)); > > @@ -886,8 +849,6 @@ static void complete_current_workload(struct intel_gvt *gvt, int ring_id) > workload->status = 0; > } > > - i915_request_put(fetch_and_zero(&workload->req)); > - > if (!workload->status && !(vgpu->resetting_eng & > ENGINE_MASK(ring_id))) { > update_guest_context(workload); > @@ -896,10 +857,13 @@ static void complete_current_workload(struct intel_gvt *gvt, int ring_id) > INTEL_GVT_EVENT_MAX) > intel_vgpu_trigger_virtual_event(vgpu, event); > } > - mutex_lock(&dev_priv->drm.struct_mutex); > + > /* unpin shadow ctx as the shadow_ctx update is done */ > - intel_context_unpin(s->shadow_ctx, engine); > - mutex_unlock(&dev_priv->drm.struct_mutex); > + mutex_lock(&rq->i915->drm.struct_mutex); > + intel_context_unpin(rq->hw_context); > + mutex_unlock(&rq->i915->drm.struct_mutex); > + > + i915_request_put(rq); > } > > gvt_dbg_sched("ring id %d complete workload %p status %d\n", > @@ -1273,7 +1237,6 @@ alloc_workload(struct intel_vgpu *vgpu) > atomic_set(&workload->shadow_ctx_active, 0); > > workload->status = -EINPROGRESS; > - workload->shadowed = false; > workload->vgpu = vgpu; > > return workload; > diff --git a/drivers/gpu/drm/i915/gvt/scheduler.h b/drivers/gpu/drm/i915/gvt/scheduler.h > index 6c644782193e..21eddab4a9cd 100644 > --- a/drivers/gpu/drm/i915/gvt/scheduler.h > +++ b/drivers/gpu/drm/i915/gvt/scheduler.h > @@ -83,7 +83,6 @@ struct intel_vgpu_workload { > struct i915_request *req; > /* if this workload has been dispatched to i915? */ > bool dispatched; > - bool shadowed; > int status; > > struct intel_vgpu_mm *shadow_mm; > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h > index 04e27806e581..9341b725113b 100644 > --- a/drivers/gpu/drm/i915/i915_drv.h > +++ b/drivers/gpu/drm/i915/i915_drv.h > @@ -1949,6 +1949,7 @@ struct drm_i915_private { > */ > struct i915_perf_stream *exclusive_stream; > > + struct intel_context *pinned_ctx; > u32 specific_ctx_id; > > struct hrtimer poll_check_timer; > diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c > index ecef2e8e5e93..8a8a77c2ef5f 100644 > --- a/drivers/gpu/drm/i915/i915_gem.c > +++ b/drivers/gpu/drm/i915/i915_gem.c > @@ -3229,14 +3229,14 @@ void i915_gem_reset(struct drm_i915_private *dev_priv, > i915_retire_requests(dev_priv); > > for_each_engine(engine, dev_priv, id) { > - struct i915_gem_context *ctx; > + struct intel_context *ce; > > i915_gem_reset_engine(engine, > engine->hangcheck.active_request, > stalled_mask & ENGINE_MASK(id)); > - ctx = fetch_and_zero(&engine->last_retired_context); > - if (ctx) > - intel_context_unpin(ctx, engine); > + ce = fetch_and_zero(&engine->last_retired_context); > + if (ce) > + intel_context_unpin(ce); > > /* > * Ostensibily, we always want a context loaded for powersaving, > @@ -4946,13 +4946,13 @@ void __i915_gem_object_release_unless_active(struct drm_i915_gem_object *obj) > > static void assert_kernel_context_is_current(struct drm_i915_private *i915) > { > - struct i915_gem_context *kernel_context = i915->kernel_context; > + struct i915_gem_context *kctx = i915->kernel_context; > struct intel_engine_cs *engine; > enum intel_engine_id id; > > for_each_engine(engine, i915, id) { > GEM_BUG_ON(__i915_gem_active_peek(&engine->timeline.last_request)); > - GEM_BUG_ON(engine->last_retired_context != kernel_context); > + GEM_BUG_ON(engine->last_retired_context->gem_context != kctx); > } > } > > diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c > index 78dc4cb305c2..66aad55c5273 100644 > --- a/drivers/gpu/drm/i915/i915_gem_context.c > +++ b/drivers/gpu/drm/i915/i915_gem_context.c > @@ -127,14 +127,8 @@ static void i915_gem_context_free(struct i915_gem_context *ctx) > for (n = 0; n < ARRAY_SIZE(ctx->__engine); n++) { > struct intel_context *ce = &ctx->__engine[n]; > > - if (!ce->state) > - continue; > - > - WARN_ON(ce->pin_count); > - if (ce->ring) > - intel_ring_free(ce->ring); > - > - __i915_gem_object_release_unless_active(ce->state->obj); > + if (ce->ops) > + ce->ops->destroy(ce); > } > > kfree(ctx->name); > @@ -266,6 +260,7 @@ __create_hw_context(struct drm_i915_private *dev_priv, > struct drm_i915_file_private *file_priv) > { > struct i915_gem_context *ctx; > + unsigned int n; > int ret; > > ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); > @@ -283,6 +278,12 @@ __create_hw_context(struct drm_i915_private *dev_priv, > ctx->i915 = dev_priv; > ctx->sched.priority = I915_PRIORITY_NORMAL; > > + for (n = 0; n < ARRAY_SIZE(ctx->__engine); n++) { > + struct intel_context *ce = &ctx->__engine[n]; > + > + ce->gem_context = ctx; > + } > + > INIT_RADIX_TREE(&ctx->handles_vma, GFP_KERNEL); > INIT_LIST_HEAD(&ctx->handles_list); > > diff --git a/drivers/gpu/drm/i915/i915_gem_context.h b/drivers/gpu/drm/i915/i915_gem_context.h > index ace3b129c189..749a4ff566f5 100644 > --- a/drivers/gpu/drm/i915/i915_gem_context.h > +++ b/drivers/gpu/drm/i915/i915_gem_context.h > @@ -45,6 +45,11 @@ struct intel_ring; > > #define DEFAULT_CONTEXT_HANDLE 0 > > +struct intel_context_ops { > + void (*unpin)(struct intel_context *ce); > + void (*destroy)(struct intel_context *ce); > +}; > + > /** > * struct i915_gem_context - client state > * > @@ -144,11 +149,14 @@ struct i915_gem_context { > > /** engine: per-engine logical HW state */ > struct intel_context { > + struct i915_gem_context *gem_context; > struct i915_vma *state; > struct intel_ring *ring; > u32 *lrc_reg_state; > u64 lrc_desc; > int pin_count; > + > + const struct intel_context_ops *ops; > } __engine[I915_NUM_ENGINES]; > > /** ring_size: size for allocating the per-engine ring buffer */ > @@ -263,25 +271,22 @@ to_intel_context(struct i915_gem_context *ctx, > return &ctx->__engine[engine->id]; > } > > -static inline struct intel_ring * > +static inline struct intel_context * > intel_context_pin(struct i915_gem_context *ctx, struct intel_engine_cs *engine) > { > return engine->context_pin(engine, ctx); > } > > -static inline void __intel_context_pin(struct i915_gem_context *ctx, > - const struct intel_engine_cs *engine) > +static inline void __intel_context_pin(struct intel_context *ce) > { > - struct intel_context *ce = to_intel_context(ctx, engine); > - > GEM_BUG_ON(!ce->pin_count); > ce->pin_count++; > } > > -static inline void intel_context_unpin(struct i915_gem_context *ctx, > - struct intel_engine_cs *engine) > +static inline void intel_context_unpin(struct intel_context *ce) > { > - engine->context_unpin(engine, ctx); > + GEM_BUG_ON(!ce->ops); > + ce->ops->unpin(ce); > } > > /* i915_gem_context.c */ > diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c > index 7cc7d3bc731b..145823f0b48e 100644 > --- a/drivers/gpu/drm/i915/i915_gpu_error.c > +++ b/drivers/gpu/drm/i915/i915_gpu_error.c > @@ -1485,8 +1485,7 @@ static void gem_record_rings(struct i915_gpu_state *error) > > ee->ctx = > i915_error_object_create(i915, > - to_intel_context(ctx, > - engine)->state); > + request->hw_context->state); > > error->simulated |= > i915_gem_context_no_error_capture(ctx); > diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c > index d9341415df40..9b580aba7e25 100644 > --- a/drivers/gpu/drm/i915/i915_perf.c > +++ b/drivers/gpu/drm/i915/i915_perf.c > @@ -1221,7 +1221,7 @@ static int oa_get_render_ctx_id(struct i915_perf_stream *stream) > dev_priv->perf.oa.specific_ctx_id = stream->ctx->hw_id; > } else { > struct intel_engine_cs *engine = dev_priv->engine[RCS]; > - struct intel_ring *ring; > + struct intel_context *ce; > int ret; > > ret = i915_mutex_lock_interruptible(&dev_priv->drm); > @@ -1234,19 +1234,19 @@ static int oa_get_render_ctx_id(struct i915_perf_stream *stream) > * > * NB: implied RCS engine... > */ > - ring = intel_context_pin(stream->ctx, engine); > + ce = intel_context_pin(stream->ctx, engine); > mutex_unlock(&dev_priv->drm.struct_mutex); > - if (IS_ERR(ring)) > - return PTR_ERR(ring); > + if (IS_ERR(ce)) > + return PTR_ERR(ce); > > + dev_priv->perf.oa.pinned_ctx = ce; > > /* > * Explicitly track the ID (instead of calling > * i915_ggtt_offset() on the fly) considering the difference > * with gen8+ and execlists > */ > - dev_priv->perf.oa.specific_ctx_id = > - i915_ggtt_offset(to_intel_context(stream->ctx, engine)->state); > + dev_priv->perf.oa.specific_ctx_id = i915_ggtt_offset(ce->state); > } > > return 0; > @@ -1262,17 +1262,14 @@ static int oa_get_render_ctx_id(struct i915_perf_stream *stream) > static void oa_put_render_ctx_id(struct i915_perf_stream *stream) > { > struct drm_i915_private *dev_priv = stream->dev_priv; > + struct intel_context *ce; > > - if (HAS_LOGICAL_RING_CONTEXTS(dev_priv)) { > - dev_priv->perf.oa.specific_ctx_id = INVALID_CTX_ID; > - } else { > - struct intel_engine_cs *engine = dev_priv->engine[RCS]; > + dev_priv->perf.oa.specific_ctx_id = INVALID_CTX_ID; > > + ce = fetch_and_zero(&dev_priv->perf.oa.pinned_ctx); > + if (ce) { > mutex_lock(&dev_priv->drm.struct_mutex); > - > - dev_priv->perf.oa.specific_ctx_id = INVALID_CTX_ID; > - intel_context_unpin(stream->ctx, engine); > - > + intel_context_unpin(ce); > mutex_unlock(&dev_priv->drm.struct_mutex); > } > } > diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c > index 5205707fe03a..e5925fcf6004 100644 > --- a/drivers/gpu/drm/i915/i915_request.c > +++ b/drivers/gpu/drm/i915/i915_request.c > @@ -382,8 +382,8 @@ static void __retire_engine_request(struct intel_engine_cs *engine, > * the subsequent request. > */ > if (engine->last_retired_context) > - intel_context_unpin(engine->last_retired_context, engine); > - engine->last_retired_context = rq->gem_context; > + intel_context_unpin(engine->last_retired_context); > + engine->last_retired_context = rq->hw_context; > } > > static void __retire_engine_upto(struct intel_engine_cs *engine, > @@ -455,7 +455,7 @@ static void i915_request_retire(struct i915_request *request) > > /* Retirement decays the ban score as it is a sign of ctx progress */ > atomic_dec_if_positive(&request->gem_context->ban_score); > - intel_context_unpin(request->gem_context, request->engine); > + intel_context_unpin(request->hw_context); > > __retire_engine_upto(request->engine, request); > > @@ -656,7 +656,7 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx) > { > struct drm_i915_private *i915 = engine->i915; > struct i915_request *rq; > - struct intel_ring *ring; > + struct intel_context *ce; > int ret; > > lockdep_assert_held(&i915->drm.struct_mutex); > @@ -680,22 +680,21 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx) > * GGTT space, so do this first before we reserve a seqno for > * ourselves. > */ > - ring = intel_context_pin(ctx, engine); > - if (IS_ERR(ring)) > - return ERR_CAST(ring); > - GEM_BUG_ON(!ring); > + ce = intel_context_pin(ctx, engine); > + if (IS_ERR(ce)) > + return ERR_CAST(ce); > > ret = reserve_gt(i915); > if (ret) > goto err_unpin; > > - ret = intel_ring_wait_for_space(ring, MIN_SPACE_FOR_ADD_REQUEST); > + ret = intel_ring_wait_for_space(ce->ring, MIN_SPACE_FOR_ADD_REQUEST); > if (ret) > goto err_unreserve; > > /* Move our oldest request to the slab-cache (if not in use!) */ > - rq = list_first_entry(&ring->request_list, typeof(*rq), ring_link); > - if (!list_is_last(&rq->ring_link, &ring->request_list) && > + rq = list_first_entry(&ce->ring->request_list, typeof(*rq), ring_link); > + if (!list_is_last(&rq->ring_link, &ce->ring->request_list) && > i915_request_completed(rq)) > i915_request_retire(rq); > > @@ -760,8 +759,9 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx) > rq->i915 = i915; > rq->engine = engine; > rq->gem_context = ctx; > - rq->ring = ring; > - rq->timeline = ring->timeline; > + rq->hw_context = ce; > + rq->ring = ce->ring; > + rq->timeline = ce->ring->timeline; > GEM_BUG_ON(rq->timeline == &engine->timeline); > > spin_lock_init(&rq->lock); > @@ -813,14 +813,14 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx) > goto err_unwind; > > /* Keep a second pin for the dual retirement along engine and ring */ > - __intel_context_pin(rq->gem_context, engine); > + __intel_context_pin(ce); > > /* Check that we didn't interrupt ourselves with a new request */ > GEM_BUG_ON(rq->timeline->seqno != rq->fence.seqno); > return rq; > > err_unwind: > - rq->ring->emit = rq->head; > + ce->ring->emit = rq->head; > > /* Make sure we didn't add ourselves to external state before freeing */ > GEM_BUG_ON(!list_empty(&rq->active_list)); > @@ -831,7 +831,7 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx) > err_unreserve: > unreserve_gt(i915); > err_unpin: > - intel_context_unpin(ctx, engine); > + intel_context_unpin(ce); > return ERR_PTR(ret); > } > > @@ -1017,8 +1017,8 @@ i915_request_await_object(struct i915_request *to, > void __i915_request_add(struct i915_request *request, bool flush_caches) > { > struct intel_engine_cs *engine = request->engine; > - struct intel_ring *ring = request->ring; > struct i915_timeline *timeline = request->timeline; > + struct intel_ring *ring = request->ring; > struct i915_request *prev; > u32 *cs; > int err; > diff --git a/drivers/gpu/drm/i915/i915_request.h b/drivers/gpu/drm/i915/i915_request.h > index dddecd9ffd0c..1bbbb7a9fa03 100644 > --- a/drivers/gpu/drm/i915/i915_request.h > +++ b/drivers/gpu/drm/i915/i915_request.h > @@ -95,6 +95,7 @@ struct i915_request { > */ > struct i915_gem_context *gem_context; > struct intel_engine_cs *engine; > + struct intel_context *hw_context; > struct intel_ring *ring; > struct i915_timeline *timeline; > struct intel_signal_node signaling; > diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c > index a1b85440ce5a..bddc57ccfa4a 100644 > --- a/drivers/gpu/drm/i915/intel_engine_cs.c > +++ b/drivers/gpu/drm/i915/intel_engine_cs.c > @@ -656,6 +656,12 @@ static int init_phys_status_page(struct intel_engine_cs *engine) > return 0; > } > > +static void __intel_context_unpin(struct i915_gem_context *ctx, > + struct intel_engine_cs *engine) > +{ > + intel_context_unpin(to_intel_context(ctx, engine)); > +} > + > /** > * intel_engines_init_common - initialize cengine state which might require hw access > * @engine: Engine to initialize. > @@ -669,7 +675,8 @@ static int init_phys_status_page(struct intel_engine_cs *engine) > */ > int intel_engine_init_common(struct intel_engine_cs *engine) > { > - struct intel_ring *ring; > + struct drm_i915_private *i915 = engine->i915; > + struct intel_context *ce; > int ret; > > engine->set_default_submission(engine); > @@ -681,18 +688,18 @@ int intel_engine_init_common(struct intel_engine_cs *engine) > * be available. To avoid this we always pin the default > * context. > */ > - ring = intel_context_pin(engine->i915->kernel_context, engine); > - if (IS_ERR(ring)) > - return PTR_ERR(ring); > + ce = intel_context_pin(i915->kernel_context, engine); > + if (IS_ERR(ce)) > + return PTR_ERR(ce); > > /* > * Similarly the preempt context must always be available so that > * we can interrupt the engine at any time. > */ > - if (engine->i915->preempt_context) { > - ring = intel_context_pin(engine->i915->preempt_context, engine); > - if (IS_ERR(ring)) { > - ret = PTR_ERR(ring); > + if (i915->preempt_context) { > + ce = intel_context_pin(i915->preempt_context, engine); > + if (IS_ERR(ce)) { > + ret = PTR_ERR(ce); > goto err_unpin_kernel; > } > } > @@ -701,7 +708,7 @@ int intel_engine_init_common(struct intel_engine_cs *engine) > if (ret) > goto err_unpin_preempt; > > - if (HWS_NEEDS_PHYSICAL(engine->i915)) > + if (HWS_NEEDS_PHYSICAL(i915)) > ret = init_phys_status_page(engine); > else > ret = init_status_page(engine); > @@ -713,10 +720,11 @@ int intel_engine_init_common(struct intel_engine_cs *engine) > err_breadcrumbs: > intel_engine_fini_breadcrumbs(engine); > err_unpin_preempt: > - if (engine->i915->preempt_context) > - intel_context_unpin(engine->i915->preempt_context, engine); > + if (i915->preempt_context) > + __intel_context_unpin(i915->preempt_context, engine); > + > err_unpin_kernel: > - intel_context_unpin(engine->i915->kernel_context, engine); > + __intel_context_unpin(i915->kernel_context, engine); > return ret; > } > > @@ -729,6 +737,8 @@ int intel_engine_init_common(struct intel_engine_cs *engine) > */ > void intel_engine_cleanup_common(struct intel_engine_cs *engine) > { > + struct drm_i915_private *i915 = engine->i915; > + > intel_engine_cleanup_scratch(engine); > > if (HWS_NEEDS_PHYSICAL(engine->i915)) > @@ -743,9 +753,9 @@ void intel_engine_cleanup_common(struct intel_engine_cs *engine) > if (engine->default_state) > i915_gem_object_put(engine->default_state); > > - if (engine->i915->preempt_context) > - intel_context_unpin(engine->i915->preempt_context, engine); > - intel_context_unpin(engine->i915->kernel_context, engine); > + if (i915->preempt_context) > + __intel_context_unpin(i915->preempt_context, engine); > + __intel_context_unpin(i915->kernel_context, engine); > > i915_timeline_fini(&engine->timeline); > } > @@ -989,8 +999,8 @@ bool intel_engines_are_idle(struct drm_i915_private *dev_priv) > */ > bool intel_engine_has_kernel_context(const struct intel_engine_cs *engine) > { > - const struct i915_gem_context * const kernel_context = > - engine->i915->kernel_context; > + const struct intel_context *kernel_context = > + to_intel_context(engine->i915->kernel_context, engine); > struct i915_request *rq; > > lockdep_assert_held(&engine->i915->drm.struct_mutex); > @@ -1002,7 +1012,7 @@ bool intel_engine_has_kernel_context(const struct intel_engine_cs *engine) > */ > rq = __i915_gem_active_peek(&engine->timeline.last_request); > if (rq) > - return rq->gem_context == kernel_context; > + return rq->hw_context == kernel_context; > else > return engine->last_retired_context == kernel_context; > } > @@ -1087,16 +1097,16 @@ void intel_engines_unpark(struct drm_i915_private *i915) > */ > void intel_engine_lost_context(struct intel_engine_cs *engine) > { > - struct i915_gem_context *ctx; > + struct intel_context *ce; > > lockdep_assert_held(&engine->i915->drm.struct_mutex); > > engine->legacy_active_context = NULL; > engine->legacy_active_ppgtt = NULL; > > - ctx = fetch_and_zero(&engine->last_retired_context); > - if (ctx) > - intel_context_unpin(ctx, engine); > + ce = fetch_and_zero(&engine->last_retired_context); > + if (ce) > + intel_context_unpin(ce); > } > > bool intel_engine_can_store_dword(struct intel_engine_cs *engine) > diff --git a/drivers/gpu/drm/i915/intel_guc_submission.c b/drivers/gpu/drm/i915/intel_guc_submission.c > index cc7b0c1b5e8c..3d4aaaf74a84 100644 > --- a/drivers/gpu/drm/i915/intel_guc_submission.c > +++ b/drivers/gpu/drm/i915/intel_guc_submission.c > @@ -513,9 +513,7 @@ static void guc_add_request(struct intel_guc *guc, struct i915_request *rq) > { > struct intel_guc_client *client = guc->execbuf_client; > struct intel_engine_cs *engine = rq->engine; > - u32 ctx_desc = > - lower_32_bits(intel_lr_context_descriptor(rq->gem_context, > - engine)); > + u32 ctx_desc = lower_32_bits(rq->hw_context->lrc_desc); > u32 ring_tail = intel_ring_set_tail(rq->ring, rq->tail) / sizeof(u64); > > spin_lock(&client->wq_lock); > @@ -553,8 +551,8 @@ static void inject_preempt_context(struct work_struct *work) > preempt_work[engine->id]); > struct intel_guc_client *client = guc->preempt_client; > struct guc_stage_desc *stage_desc = __get_stage_desc(client); > - u32 ctx_desc = lower_32_bits(intel_lr_context_descriptor(client->owner, > - engine)); > + u32 ctx_desc = lower_32_bits(to_intel_context(client->owner, > + engine)->lrc_desc); > u32 data[7]; > > /* > @@ -710,7 +708,7 @@ static void guc_dequeue(struct intel_engine_cs *engine) > struct i915_request *rq, *rn; > > list_for_each_entry_safe(rq, rn, &p->requests, sched.link) { > - if (last && rq->gem_context != last->gem_context) { > + if (last && rq->hw_context != last->hw_context) { > if (port == last_port) { > __list_del_many(&p->requests, > &rq->sched.link); > diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c > index 578cb89b3af7..c29d5f5582c2 100644 > --- a/drivers/gpu/drm/i915/intel_lrc.c > +++ b/drivers/gpu/drm/i915/intel_lrc.c > @@ -164,7 +164,8 @@ > #define WA_TAIL_BYTES (sizeof(u32) * WA_TAIL_DWORDS) > > static int execlists_context_deferred_alloc(struct i915_gem_context *ctx, > - struct intel_engine_cs *engine); > + struct intel_engine_cs *engine, > + struct intel_context *ce); > static void execlists_init_reg_state(u32 *reg_state, > struct i915_gem_context *ctx, > struct intel_engine_cs *engine, > @@ -222,9 +223,9 @@ static inline bool need_preempt(const struct intel_engine_cs *engine, > */ > static void > intel_lr_context_descriptor_update(struct i915_gem_context *ctx, > - struct intel_engine_cs *engine) > + struct intel_engine_cs *engine, > + struct intel_context *ce) > { > - struct intel_context *ce = to_intel_context(ctx, engine); > u64 desc; > > BUILD_BUG_ON(MAX_CONTEXT_HW_ID > (BIT(GEN8_CTX_ID_WIDTH))); > @@ -416,8 +417,7 @@ execlists_update_context_pdps(struct i915_hw_ppgtt *ppgtt, u32 *reg_state) > > static u64 execlists_update_context(struct i915_request *rq) > { > - struct intel_context *ce = > - to_intel_context(rq->gem_context, rq->engine); > + struct intel_context *ce = rq->hw_context; > struct i915_hw_ppgtt *ppgtt = > rq->gem_context->ppgtt ?: rq->i915->mm.aliasing_ppgtt; > u32 *reg_state = ce->lrc_reg_state; > @@ -494,14 +494,14 @@ static void execlists_submit_ports(struct intel_engine_cs *engine) > execlists_clear_active(execlists, EXECLISTS_ACTIVE_HWACK); > } > > -static bool ctx_single_port_submission(const struct i915_gem_context *ctx) > +static bool ctx_single_port_submission(const struct intel_context *ce) > { > return (IS_ENABLED(CONFIG_DRM_I915_GVT) && > - i915_gem_context_force_single_submission(ctx)); > + i915_gem_context_force_single_submission(ce->gem_context)); > } > > -static bool can_merge_ctx(const struct i915_gem_context *prev, > - const struct i915_gem_context *next) > +static bool can_merge_ctx(const struct intel_context *prev, > + const struct intel_context *next) > { > if (prev != next) > return false; > @@ -669,8 +669,8 @@ static void execlists_dequeue(struct intel_engine_cs *engine) > * second request, and so we never need to tell the > * hardware about the first. > */ > - if (last && !can_merge_ctx(rq->gem_context, > - last->gem_context)) { > + if (last && > + !can_merge_ctx(rq->hw_context, last->hw_context)) { > /* > * If we are on the second port and cannot > * combine this request with the last, then we > @@ -689,14 +689,14 @@ static void execlists_dequeue(struct intel_engine_cs *engine) > * the same context (even though a different > * request) to the second port. > */ > - if (ctx_single_port_submission(last->gem_context) || > - ctx_single_port_submission(rq->gem_context)) { > + if (ctx_single_port_submission(last->hw_context) || > + ctx_single_port_submission(rq->hw_context)) { > __list_del_many(&p->requests, > &rq->sched.link); > goto done; > } > > - GEM_BUG_ON(last->gem_context == rq->gem_context); > + GEM_BUG_ON(last->hw_context == rq->hw_context); > > if (submit) > port_assign(port, last); > @@ -1303,6 +1303,37 @@ static void execlists_schedule(struct i915_request *request, > spin_unlock_irq(&engine->timeline.lock); > } > > +static void execlists_context_destroy(struct intel_context *ce) > +{ > + GEM_BUG_ON(!ce->state); > + GEM_BUG_ON(ce->pin_count); > + > + intel_ring_free(ce->ring); > + __i915_gem_object_release_unless_active(ce->state->obj); > +} > + > +static void __execlists_context_unpin(struct intel_context *ce) > +{ > + intel_ring_unpin(ce->ring); > + > + ce->state->obj->pin_global--; > + i915_gem_object_unpin_map(ce->state->obj); > + i915_vma_unpin(ce->state); > + > + i915_gem_context_put(ce->gem_context); > +} > + > +static void execlists_context_unpin(struct intel_context *ce) > +{ > + lockdep_assert_held(&ce->gem_context->i915->drm.struct_mutex); > + GEM_BUG_ON(ce->pin_count == 0); > + > + if (--ce->pin_count) > + return; > + > + __execlists_context_unpin(ce); > +} > + > static int __context_pin(struct i915_gem_context *ctx, struct i915_vma *vma) > { > unsigned int flags; > @@ -1326,21 +1357,15 @@ static int __context_pin(struct i915_gem_context *ctx, struct i915_vma *vma) > return i915_vma_pin(vma, 0, GEN8_LR_CONTEXT_ALIGN, flags); > } > > -static struct intel_ring * > -execlists_context_pin(struct intel_engine_cs *engine, > - struct i915_gem_context *ctx) > +static struct intel_context * > +__execlists_context_pin(struct intel_engine_cs *engine, > + struct i915_gem_context *ctx, > + struct intel_context *ce) > { > - struct intel_context *ce = to_intel_context(ctx, engine); > void *vaddr; > int ret; > > - lockdep_assert_held(&ctx->i915->drm.struct_mutex); > - > - if (likely(ce->pin_count++)) > - goto out; > - GEM_BUG_ON(!ce->pin_count); /* no overflow please! */ > - > - ret = execlists_context_deferred_alloc(ctx, engine); > + ret = execlists_context_deferred_alloc(ctx, engine, ce); > if (ret) > goto err; > GEM_BUG_ON(!ce->state); > @@ -1359,7 +1384,7 @@ execlists_context_pin(struct intel_engine_cs *engine, > if (ret) > goto unpin_map; > > - intel_lr_context_descriptor_update(ctx, engine); > + intel_lr_context_descriptor_update(ctx, engine, ce); > > ce->lrc_reg_state = vaddr + LRC_STATE_PN * PAGE_SIZE; > ce->lrc_reg_state[CTX_RING_BUFFER_START+1] = > @@ -1368,8 +1393,7 @@ execlists_context_pin(struct intel_engine_cs *engine, > > ce->state->obj->pin_global++; > i915_gem_context_get(ctx); > -out: > - return ce->ring; > + return ce; > > unpin_map: > i915_gem_object_unpin_map(ce->state->obj); > @@ -1380,33 +1404,33 @@ execlists_context_pin(struct intel_engine_cs *engine, > return ERR_PTR(ret); > } > > -static void execlists_context_unpin(struct intel_engine_cs *engine, > - struct i915_gem_context *ctx) > +static const struct intel_context_ops execlists_context_ops = { > + .unpin = execlists_context_unpin, > + .destroy = execlists_context_destroy, > +}; > + > +static struct intel_context * > +execlists_context_pin(struct intel_engine_cs *engine, > + struct i915_gem_context *ctx) > { > struct intel_context *ce = to_intel_context(ctx, engine); > > lockdep_assert_held(&ctx->i915->drm.struct_mutex); > - GEM_BUG_ON(ce->pin_count == 0); > > - if (--ce->pin_count) > - return; > - > - intel_ring_unpin(ce->ring); > + if (likely(ce->pin_count++)) > + return ce; > + GEM_BUG_ON(!ce->pin_count); /* no overflow please! */ > > - ce->state->obj->pin_global--; > - i915_gem_object_unpin_map(ce->state->obj); > - i915_vma_unpin(ce->state); > + ce->ops = &execlists_context_ops; > > - i915_gem_context_put(ctx); > + return __execlists_context_pin(engine, ctx, ce); > } > > static int execlists_request_alloc(struct i915_request *request) > { > - struct intel_context *ce = > - to_intel_context(request->gem_context, request->engine); > int ret; > > - GEM_BUG_ON(!ce->pin_count); > + GEM_BUG_ON(!request->hw_context->pin_count); > > /* Flush enough space to reduce the likelihood of waiting after > * we start building the request - in which case we will just > @@ -1857,7 +1881,7 @@ static void reset_common_ring(struct intel_engine_cs *engine, > * future request will be after userspace has had the opportunity > * to recreate its own state. > */ > - regs = to_intel_context(request->gem_context, engine)->lrc_reg_state; > + regs = request->hw_context->lrc_reg_state; > if (engine->default_state) { > void *defaults; > > @@ -2216,8 +2240,6 @@ logical_ring_default_vfuncs(struct intel_engine_cs *engine) > engine->reset_hw = reset_common_ring; > > engine->context_pin = execlists_context_pin; > - engine->context_unpin = execlists_context_unpin; > - > engine->request_alloc = execlists_request_alloc; > > engine->emit_flush = gen8_emit_flush; > @@ -2452,7 +2474,7 @@ static void execlists_init_reg_state(u32 *regs, > struct drm_i915_private *dev_priv = engine->i915; > struct i915_hw_ppgtt *ppgtt = ctx->ppgtt ?: dev_priv->mm.aliasing_ppgtt; > u32 base = engine->mmio_base; > - bool rcs = engine->id == RCS; > + bool rcs = engine->class == RENDER_CLASS; > > /* A context is actually a big batch buffer with several > * MI_LOAD_REGISTER_IMM commands followed by (reg, value) pairs. The > @@ -2597,10 +2619,10 @@ populate_lr_context(struct i915_gem_context *ctx, > } > > static int execlists_context_deferred_alloc(struct i915_gem_context *ctx, > - struct intel_engine_cs *engine) > + struct intel_engine_cs *engine, > + struct intel_context *ce) > { > struct drm_i915_gem_object *ctx_obj; > - struct intel_context *ce = to_intel_context(ctx, engine); > struct i915_vma *vma; > uint32_t context_size; > struct intel_ring *ring; > diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h > index 4ec7d8dd13c8..1593194e930c 100644 > --- a/drivers/gpu/drm/i915/intel_lrc.h > +++ b/drivers/gpu/drm/i915/intel_lrc.h > @@ -104,11 +104,4 @@ struct i915_gem_context; > > void intel_lr_context_resume(struct drm_i915_private *dev_priv); > > -static inline uint64_t > -intel_lr_context_descriptor(struct i915_gem_context *ctx, > - struct intel_engine_cs *engine) > -{ > - return to_intel_context(ctx, engine)->lrc_desc; > -} > - > #endif /* _INTEL_LRC_H_ */ > diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c > index fbd23127505d..526ee8302fce 100644 > --- a/drivers/gpu/drm/i915/intel_ringbuffer.c > +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c > @@ -558,8 +558,7 @@ static void reset_ring_common(struct intel_engine_cs *engine, > */ > if (request) { > struct drm_i915_private *dev_priv = request->i915; > - struct intel_context *ce = > - to_intel_context(request->gem_context, engine); > + struct intel_context *ce = request->hw_context; > struct i915_hw_ppgtt *ppgtt; > > if (ce->state) { > @@ -1169,7 +1168,31 @@ intel_ring_free(struct intel_ring *ring) > kfree(ring); > } > > -static int context_pin(struct intel_context *ce) > +static void intel_ring_context_destroy(struct intel_context *ce) > +{ > + GEM_BUG_ON(ce->pin_count); > + > + if (ce->state) > + __i915_gem_object_release_unless_active(ce->state->obj); > +} > + > +static void intel_ring_context_unpin(struct intel_context *ce) > +{ > + lockdep_assert_held(&ce->gem_context->i915->drm.struct_mutex); > + GEM_BUG_ON(ce->pin_count == 0); > + > + if (--ce->pin_count) > + return; > + > + if (ce->state) { > + ce->state->obj->pin_global--; > + i915_vma_unpin(ce->state); > + } > + > + i915_gem_context_put(ce->gem_context); > +} > + > +static int __context_pin(struct intel_context *ce) > { > struct i915_vma *vma = ce->state; > int ret; > @@ -1258,25 +1281,19 @@ alloc_context_vma(struct intel_engine_cs *engine) > return ERR_PTR(err); > } > > -static struct intel_ring * > -intel_ring_context_pin(struct intel_engine_cs *engine, > - struct i915_gem_context *ctx) > +static struct intel_context * > +__ring_context_pin(struct intel_engine_cs *engine, > + struct i915_gem_context *ctx, > + struct intel_context *ce) > { > - struct intel_context *ce = to_intel_context(ctx, engine); > - int ret; > - > - lockdep_assert_held(&ctx->i915->drm.struct_mutex); > - > - if (likely(ce->pin_count++)) > - goto out; > - GEM_BUG_ON(!ce->pin_count); /* no overflow please! */ > + int err; > > if (!ce->state && engine->context_size) { > struct i915_vma *vma; > > vma = alloc_context_vma(engine); > if (IS_ERR(vma)) { > - ret = PTR_ERR(vma); > + err = PTR_ERR(vma); > goto err; > } > > @@ -1284,8 +1301,8 @@ intel_ring_context_pin(struct intel_engine_cs *engine, > } > > if (ce->state) { > - ret = context_pin(ce); > - if (ret) > + err = __context_pin(ce); > + if (err) > goto err; > > ce->state->obj->pin_global++; > @@ -1293,32 +1310,37 @@ intel_ring_context_pin(struct intel_engine_cs *engine, > > i915_gem_context_get(ctx); > > -out: > /* One ringbuffer to rule them all */ > - return engine->buffer; > + GEM_BUG_ON(!engine->buffer); > + ce->ring = engine->buffer; > + > + return ce; > > err: > ce->pin_count = 0; > - return ERR_PTR(ret); > + return ERR_PTR(err); > } > > -static void intel_ring_context_unpin(struct intel_engine_cs *engine, > - struct i915_gem_context *ctx) > +static const struct intel_context_ops ring_context_ops = { > + .unpin = intel_ring_context_unpin, > + .destroy = intel_ring_context_destroy, > +}; > + > +static struct intel_context * > +intel_ring_context_pin(struct intel_engine_cs *engine, > + struct i915_gem_context *ctx) > { > struct intel_context *ce = to_intel_context(ctx, engine); > > lockdep_assert_held(&ctx->i915->drm.struct_mutex); > - GEM_BUG_ON(ce->pin_count == 0); > > - if (--ce->pin_count) > - return; > + if (likely(ce->pin_count++)) > + return ce; > + GEM_BUG_ON(!ce->pin_count); /* no overflow please! */ > > - if (ce->state) { > - ce->state->obj->pin_global--; > - i915_vma_unpin(ce->state); > - } > + ce->ops = &ring_context_ops; > > - i915_gem_context_put(ctx); > + return __ring_context_pin(engine, ctx, ce); > } > > static int intel_init_ring_buffer(struct intel_engine_cs *engine) > @@ -1329,10 +1351,6 @@ static int intel_init_ring_buffer(struct intel_engine_cs *engine) > > intel_engine_setup_common(engine); > > - err = intel_engine_init_common(engine); > - if (err) > - goto err; > - > timeline = i915_timeline_create(engine->i915, engine->name); > if (IS_ERR(timeline)) { > err = PTR_ERR(timeline); > @@ -1354,8 +1372,14 @@ static int intel_init_ring_buffer(struct intel_engine_cs *engine) > GEM_BUG_ON(engine->buffer); > engine->buffer = ring; > > + err = intel_engine_init_common(engine); > + if (err) > + goto err_unpin; > + > return 0; > > +err_unpin: > + intel_ring_unpin(ring); > err_ring: > intel_ring_free(ring); > err: > @@ -1441,7 +1465,7 @@ static inline int mi_set_context(struct i915_request *rq, u32 flags) > > *cs++ = MI_NOOP; > *cs++ = MI_SET_CONTEXT; > - *cs++ = i915_ggtt_offset(to_intel_context(rq->gem_context, engine)->state) | flags; > + *cs++ = i915_ggtt_offset(rq->hw_context->state) | flags; > /* > * w/a: MI_SET_CONTEXT must always be followed by MI_NOOP > * WaMiSetContext_Hang:snb,ivb,vlv > @@ -1532,7 +1556,7 @@ static int switch_context(struct i915_request *rq) > hw_flags = MI_FORCE_RESTORE; > } > > - if (to_intel_context(to_ctx, engine)->state && > + if (rq->hw_context->state && > (to_ctx != from_ctx || hw_flags & MI_FORCE_RESTORE)) { > GEM_BUG_ON(engine->id != RCS); > > @@ -1580,7 +1604,7 @@ static int ring_request_alloc(struct i915_request *request) > { > int ret; > > - GEM_BUG_ON(!to_intel_context(request->gem_context, request->engine)->pin_count); > + GEM_BUG_ON(!request->hw_context->pin_count); > > /* Flush enough space to reduce the likelihood of waiting after > * we start building the request - in which case we will just > @@ -2009,8 +2033,6 @@ static void intel_ring_default_vfuncs(struct drm_i915_private *dev_priv, > engine->reset_hw = reset_ring_common; > > engine->context_pin = intel_ring_context_pin; > - engine->context_unpin = intel_ring_context_unpin; > - > engine->request_alloc = ring_request_alloc; > > engine->emit_breadcrumb = i9xx_emit_breadcrumb; > diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h > index c4e56044e34f..5e78ee3f5775 100644 > --- a/drivers/gpu/drm/i915/intel_ringbuffer.h > +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h > @@ -431,10 +431,9 @@ struct intel_engine_cs { > > void (*set_default_submission)(struct intel_engine_cs *engine); > > - struct intel_ring *(*context_pin)(struct intel_engine_cs *engine, > - struct i915_gem_context *ctx); > - void (*context_unpin)(struct intel_engine_cs *engine, > - struct i915_gem_context *ctx); > + struct intel_context *(*context_pin)(struct intel_engine_cs *engine, > + struct i915_gem_context *ctx); > + > int (*request_alloc)(struct i915_request *rq); > int (*init_context)(struct i915_request *rq); > > @@ -550,7 +549,7 @@ struct intel_engine_cs { > * to the kernel context and trash it as the save may not happen > * before the hardware is powered down. > */ > - struct i915_gem_context *last_retired_context; > + struct intel_context *last_retired_context; > > /* We track the current MI_SET_CONTEXT in order to eliminate > * redudant context switches. This presumes that requests are not > diff --git a/drivers/gpu/drm/i915/selftests/mock_context.c b/drivers/gpu/drm/i915/selftests/mock_context.c > index 501becc47c0c..8904f1ce64e3 100644 > --- a/drivers/gpu/drm/i915/selftests/mock_context.c > +++ b/drivers/gpu/drm/i915/selftests/mock_context.c > @@ -30,6 +30,7 @@ mock_context(struct drm_i915_private *i915, > const char *name) > { > struct i915_gem_context *ctx; > + unsigned int n; > int ret; > > ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); > @@ -43,6 +44,12 @@ mock_context(struct drm_i915_private *i915, > INIT_RADIX_TREE(&ctx->handles_vma, GFP_KERNEL); > INIT_LIST_HEAD(&ctx->handles_list); > > + for (n = 0; n < ARRAY_SIZE(ctx->__engine); n++) { > + struct intel_context *ce = &ctx->__engine[n]; > + > + ce->gem_context = ctx; > + } > + > ret = ida_simple_get(&i915->contexts.hw_ida, > 0, MAX_CONTEXT_HW_ID, GFP_KERNEL); > if (ret < 0) > diff --git a/drivers/gpu/drm/i915/selftests/mock_engine.c b/drivers/gpu/drm/i915/selftests/mock_engine.c > index 26bf29d97007..33eddfc1f8ce 100644 > --- a/drivers/gpu/drm/i915/selftests/mock_engine.c > +++ b/drivers/gpu/drm/i915/selftests/mock_engine.c > @@ -72,25 +72,37 @@ static void hw_delay_complete(struct timer_list *t) > spin_unlock(&engine->hw_lock); > } > > -static struct intel_ring * > -mock_context_pin(struct intel_engine_cs *engine, > - struct i915_gem_context *ctx) > +static void mock_context_unpin(struct intel_context *ce) > { > - struct intel_context *ce = to_intel_context(ctx, engine); > + if (--ce->pin_count) > + return; > > - if (!ce->pin_count++) > - i915_gem_context_get(ctx); > + i915_gem_context_put(ce->gem_context); > +} > > - return engine->buffer; > +static void mock_context_destroy(struct intel_context *ce) > +{ > + GEM_BUG_ON(ce->pin_count); > } > > -static void mock_context_unpin(struct intel_engine_cs *engine, > - struct i915_gem_context *ctx) > +static const struct intel_context_ops mock_context_ops = { > + .unpin = mock_context_unpin, > + .destroy = mock_context_destroy, > +}; > + > +static struct intel_context * > +mock_context_pin(struct intel_engine_cs *engine, > + struct i915_gem_context *ctx) > { > struct intel_context *ce = to_intel_context(ctx, engine); > > - if (!--ce->pin_count) > - i915_gem_context_put(ctx); > + if (!ce->pin_count++) { > + i915_gem_context_get(ctx); > + ce->ring = engine->buffer; > + ce->ops = &mock_context_ops; > + } > + > + return ce; > } > > static int mock_request_alloc(struct i915_request *request) > @@ -185,7 +197,6 @@ struct intel_engine_cs *mock_engine(struct drm_i915_private *i915, > engine->base.status_page.page_addr = (void *)(engine + 1); > > engine->base.context_pin = mock_context_pin; > - engine->base.context_unpin = mock_context_unpin; > engine->base.request_alloc = mock_request_alloc; > engine->base.emit_flush = mock_emit_flush; > engine->base.emit_breadcrumb = mock_emit_breadcrumb; > @@ -238,11 +249,13 @@ void mock_engine_free(struct intel_engine_cs *engine) > { > struct mock_engine *mock = > container_of(engine, typeof(*mock), base); > + struct intel_context *ce; > > GEM_BUG_ON(timer_pending(&mock->hw_delay)); > > - if (engine->last_retired_context) > - intel_context_unpin(engine->last_retired_context, engine); > + ce = fetch_and_zero(&engine->last_retired_context); > + if (ce) > + intel_context_unpin(ce); > > mock_ring_free(engine->buffer); > > For other than GVT parts: Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Regards, Tvrtko
diff --git a/drivers/gpu/drm/i915/gvt/mmio_context.c b/drivers/gpu/drm/i915/gvt/mmio_context.c index 0f949554d118..708170e61625 100644 --- a/drivers/gpu/drm/i915/gvt/mmio_context.c +++ b/drivers/gpu/drm/i915/gvt/mmio_context.c @@ -446,9 +446,9 @@ static void switch_mocs(struct intel_vgpu *pre, struct intel_vgpu *next, #define CTX_CONTEXT_CONTROL_VAL 0x03 -bool is_inhibit_context(struct i915_gem_context *ctx, int ring_id) +bool is_inhibit_context(struct intel_context *ce) { - u32 *reg_state = ctx->__engine[ring_id].lrc_reg_state; + const u32 *reg_state = ce->lrc_reg_state; u32 inhibit_mask = _MASKED_BIT_ENABLE(CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT); @@ -501,7 +501,7 @@ static void switch_mmio(struct intel_vgpu *pre, * itself. */ if (mmio->in_context && - !is_inhibit_context(s->shadow_ctx, ring_id)) + !is_inhibit_context(&s->shadow_ctx->__engine[ring_id])) continue; if (mmio->mask) diff --git a/drivers/gpu/drm/i915/gvt/mmio_context.h b/drivers/gpu/drm/i915/gvt/mmio_context.h index 0439eb8057a8..5c3b9ff9f96a 100644 --- a/drivers/gpu/drm/i915/gvt/mmio_context.h +++ b/drivers/gpu/drm/i915/gvt/mmio_context.h @@ -49,7 +49,7 @@ void intel_gvt_switch_mmio(struct intel_vgpu *pre, void intel_gvt_init_engine_mmio_context(struct intel_gvt *gvt); -bool is_inhibit_context(struct i915_gem_context *ctx, int ring_id); +bool is_inhibit_context(struct intel_context *ce); int intel_vgpu_restore_inhibit_context(struct intel_vgpu *vgpu, struct i915_request *req); diff --git a/drivers/gpu/drm/i915/gvt/scheduler.c b/drivers/gpu/drm/i915/gvt/scheduler.c index f409a154491d..d9aa39d28584 100644 --- a/drivers/gpu/drm/i915/gvt/scheduler.c +++ b/drivers/gpu/drm/i915/gvt/scheduler.c @@ -54,11 +54,8 @@ static void set_context_pdp_root_pointer( static void update_shadow_pdps(struct intel_vgpu_workload *workload) { - struct intel_vgpu *vgpu = workload->vgpu; - int ring_id = workload->ring_id; - struct i915_gem_context *shadow_ctx = vgpu->submission.shadow_ctx; struct drm_i915_gem_object *ctx_obj = - shadow_ctx->__engine[ring_id].state->obj; + workload->req->hw_context->state->obj; struct execlist_ring_context *shadow_ring_context; struct page *page; @@ -128,9 +125,8 @@ static int populate_shadow_context(struct intel_vgpu_workload *workload) struct intel_vgpu *vgpu = workload->vgpu; struct intel_gvt *gvt = vgpu->gvt; int ring_id = workload->ring_id; - struct i915_gem_context *shadow_ctx = vgpu->submission.shadow_ctx; struct drm_i915_gem_object *ctx_obj = - shadow_ctx->__engine[ring_id].state->obj; + workload->req->hw_context->state->obj; struct execlist_ring_context *shadow_ring_context; struct page *page; void *dst; @@ -280,10 +276,8 @@ static int shadow_context_status_change(struct notifier_block *nb, return NOTIFY_OK; } -static void shadow_context_descriptor_update(struct i915_gem_context *ctx, - struct intel_engine_cs *engine) +static void shadow_context_descriptor_update(struct intel_context *ce) { - struct intel_context *ce = to_intel_context(ctx, engine); u64 desc = 0; desc = ce->lrc_desc; @@ -292,7 +286,7 @@ static void shadow_context_descriptor_update(struct i915_gem_context *ctx, * like GEN8_CTX_* cached in desc_template */ desc &= U64_MAX << 12; - desc |= ctx->desc_template & ((1ULL << 12) - 1); + desc |= ce->gem_context->desc_template & ((1ULL << 12) - 1); ce->lrc_desc = desc; } @@ -300,12 +294,11 @@ static void shadow_context_descriptor_update(struct i915_gem_context *ctx, static int copy_workload_to_ring_buffer(struct intel_vgpu_workload *workload) { struct intel_vgpu *vgpu = workload->vgpu; + struct i915_request *req = workload->req; void *shadow_ring_buffer_va; u32 *cs; - struct i915_request *req = workload->req; - if (IS_KABYLAKE(req->i915) && - is_inhibit_context(req->gem_context, req->engine->id)) + if (IS_KABYLAKE(req->i915) && is_inhibit_context(req->hw_context)) intel_vgpu_restore_inhibit_context(vgpu, req); /* allocate shadow ring buffer */ @@ -353,60 +346,56 @@ int intel_gvt_scan_and_shadow_workload(struct intel_vgpu_workload *workload) struct intel_vgpu_submission *s = &vgpu->submission; struct i915_gem_context *shadow_ctx = s->shadow_ctx; struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv; - int ring_id = workload->ring_id; - struct intel_engine_cs *engine = dev_priv->engine[ring_id]; - struct intel_ring *ring; + struct intel_engine_cs *engine = dev_priv->engine[workload->ring_id]; + struct intel_context *ce; int ret; lockdep_assert_held(&dev_priv->drm.struct_mutex); - if (workload->shadowed) + if (workload->req) return 0; + /* pin shadow context by gvt even the shadow context will be pinned + * when i915 alloc request. That is because gvt will update the guest + * context from shadow context when workload is completed, and at that + * moment, i915 may already unpined the shadow context to make the + * shadow_ctx pages invalid. So gvt need to pin itself. After update + * the guest context, gvt can unpin the shadow_ctx safely. + */ + ce = intel_context_pin(shadow_ctx, engine); + if (IS_ERR(ce)) { + gvt_vgpu_err("fail to pin shadow context\n"); + return PTR_ERR(ce); + } + shadow_ctx->desc_template &= ~(0x3 << GEN8_CTX_ADDRESSING_MODE_SHIFT); shadow_ctx->desc_template |= workload->ctx_desc.addressing_mode << GEN8_CTX_ADDRESSING_MODE_SHIFT; - if (!test_and_set_bit(ring_id, s->shadow_ctx_desc_updated)) - shadow_context_descriptor_update(shadow_ctx, - dev_priv->engine[ring_id]); + if (!test_and_set_bit(workload->ring_id, s->shadow_ctx_desc_updated)) + shadow_context_descriptor_update(ce); ret = intel_gvt_scan_and_shadow_ringbuffer(workload); if (ret) - goto err_scan; + goto err_unpin; if ((workload->ring_id == RCS) && (workload->wa_ctx.indirect_ctx.size != 0)) { ret = intel_gvt_scan_and_shadow_wa_ctx(&workload->wa_ctx); if (ret) - goto err_scan; - } - - /* pin shadow context by gvt even the shadow context will be pinned - * when i915 alloc request. That is because gvt will update the guest - * context from shadow context when workload is completed, and at that - * moment, i915 may already unpined the shadow context to make the - * shadow_ctx pages invalid. So gvt need to pin itself. After update - * the guest context, gvt can unpin the shadow_ctx safely. - */ - ring = intel_context_pin(shadow_ctx, engine); - if (IS_ERR(ring)) { - ret = PTR_ERR(ring); - gvt_vgpu_err("fail to pin shadow context\n"); - goto err_shadow; + goto err_shadow; } ret = populate_shadow_context(workload); if (ret) - goto err_unpin; - workload->shadowed = true; + goto err_shadow; + return 0; -err_unpin: - intel_context_unpin(shadow_ctx, engine); err_shadow: release_shadow_wa_ctx(&workload->wa_ctx); -err_scan: +err_unpin: + intel_context_unpin(ce); return ret; } @@ -414,7 +403,6 @@ static int intel_gvt_generate_request(struct intel_vgpu_workload *workload) { int ring_id = workload->ring_id; struct drm_i915_private *dev_priv = workload->vgpu->gvt->dev_priv; - struct intel_engine_cs *engine = dev_priv->engine[ring_id]; struct i915_request *rq; struct intel_vgpu *vgpu = workload->vgpu; struct intel_vgpu_submission *s = &vgpu->submission; @@ -437,7 +425,6 @@ static int intel_gvt_generate_request(struct intel_vgpu_workload *workload) return 0; err_unpin: - intel_context_unpin(shadow_ctx, engine); release_shadow_wa_ctx(&workload->wa_ctx); return ret; } @@ -517,21 +504,13 @@ static int prepare_shadow_batch_buffer(struct intel_vgpu_workload *workload) return ret; } -static int update_wa_ctx_2_shadow_ctx(struct intel_shadow_wa_ctx *wa_ctx) +static void update_wa_ctx_2_shadow_ctx(struct intel_shadow_wa_ctx *wa_ctx) { - struct intel_vgpu_workload *workload = container_of(wa_ctx, - struct intel_vgpu_workload, - wa_ctx); - int ring_id = workload->ring_id; - struct intel_vgpu_submission *s = &workload->vgpu->submission; - struct i915_gem_context *shadow_ctx = s->shadow_ctx; - struct drm_i915_gem_object *ctx_obj = - shadow_ctx->__engine[ring_id].state->obj; - struct execlist_ring_context *shadow_ring_context; - struct page *page; - - page = i915_gem_object_get_page(ctx_obj, LRC_STATE_PN); - shadow_ring_context = kmap_atomic(page); + struct intel_vgpu_workload *workload = + container_of(wa_ctx, struct intel_vgpu_workload, wa_ctx); + struct i915_request *rq = workload->req; + struct execlist_ring_context *shadow_ring_context = + (struct execlist_ring_context *)rq->hw_context->lrc_reg_state; shadow_ring_context->bb_per_ctx_ptr.val = (shadow_ring_context->bb_per_ctx_ptr.val & @@ -539,9 +518,6 @@ static int update_wa_ctx_2_shadow_ctx(struct intel_shadow_wa_ctx *wa_ctx) shadow_ring_context->rcs_indirect_ctx.val = (shadow_ring_context->rcs_indirect_ctx.val & (~INDIRECT_CTX_ADDR_MASK)) | wa_ctx->indirect_ctx.shadow_gma; - - kunmap_atomic(shadow_ring_context); - return 0; } static int prepare_shadow_wa_ctx(struct intel_shadow_wa_ctx *wa_ctx) @@ -670,12 +646,9 @@ static int prepare_workload(struct intel_vgpu_workload *workload) static int dispatch_workload(struct intel_vgpu_workload *workload) { struct intel_vgpu *vgpu = workload->vgpu; - struct intel_vgpu_submission *s = &vgpu->submission; - struct i915_gem_context *shadow_ctx = s->shadow_ctx; struct drm_i915_private *dev_priv = vgpu->gvt->dev_priv; int ring_id = workload->ring_id; - struct intel_engine_cs *engine = dev_priv->engine[ring_id]; - int ret = 0; + int ret; gvt_dbg_sched("ring id %d prepare to dispatch workload %p\n", ring_id, workload); @@ -687,10 +660,6 @@ static int dispatch_workload(struct intel_vgpu_workload *workload) goto out; ret = prepare_workload(workload); - if (ret) { - intel_context_unpin(shadow_ctx, engine); - goto out; - } out: if (ret) @@ -765,27 +734,23 @@ static struct intel_vgpu_workload *pick_next_workload( static void update_guest_context(struct intel_vgpu_workload *workload) { + struct i915_request *rq = workload->req; struct intel_vgpu *vgpu = workload->vgpu; struct intel_gvt *gvt = vgpu->gvt; - struct intel_vgpu_submission *s = &vgpu->submission; - struct i915_gem_context *shadow_ctx = s->shadow_ctx; - int ring_id = workload->ring_id; - struct drm_i915_gem_object *ctx_obj = - shadow_ctx->__engine[ring_id].state->obj; + struct drm_i915_gem_object *ctx_obj = rq->hw_context->state->obj; struct execlist_ring_context *shadow_ring_context; struct page *page; void *src; unsigned long context_gpa, context_page_num; int i; - gvt_dbg_sched("ring id %d workload lrca %x\n", ring_id, - workload->ctx_desc.lrca); - - context_page_num = gvt->dev_priv->engine[ring_id]->context_size; + gvt_dbg_sched("ring id %d workload lrca %x\n", rq->engine->id, + workload->ctx_desc.lrca); + context_page_num = rq->engine->context_size; context_page_num = context_page_num >> PAGE_SHIFT; - if (IS_BROADWELL(gvt->dev_priv) && ring_id == RCS) + if (IS_BROADWELL(gvt->dev_priv) && rq->engine->id == RCS) context_page_num = 19; i = 2; @@ -858,6 +823,7 @@ static void complete_current_workload(struct intel_gvt *gvt, int ring_id) scheduler->current_workload[ring_id]; struct intel_vgpu *vgpu = workload->vgpu; struct intel_vgpu_submission *s = &vgpu->submission; + struct i915_request *rq; int event; mutex_lock(&gvt->lock); @@ -866,11 +832,8 @@ static void complete_current_workload(struct intel_gvt *gvt, int ring_id) * switch to make sure request is completed. * For the workload w/o request, directly complete the workload. */ - if (workload->req) { - struct drm_i915_private *dev_priv = - workload->vgpu->gvt->dev_priv; - struct intel_engine_cs *engine = - dev_priv->engine[workload->ring_id]; + rq = fetch_and_zero(&workload->req); + if (rq) { wait_event(workload->shadow_ctx_status_wq, !atomic_read(&workload->shadow_ctx_active)); @@ -886,8 +849,6 @@ static void complete_current_workload(struct intel_gvt *gvt, int ring_id) workload->status = 0; } - i915_request_put(fetch_and_zero(&workload->req)); - if (!workload->status && !(vgpu->resetting_eng & ENGINE_MASK(ring_id))) { update_guest_context(workload); @@ -896,10 +857,13 @@ static void complete_current_workload(struct intel_gvt *gvt, int ring_id) INTEL_GVT_EVENT_MAX) intel_vgpu_trigger_virtual_event(vgpu, event); } - mutex_lock(&dev_priv->drm.struct_mutex); + /* unpin shadow ctx as the shadow_ctx update is done */ - intel_context_unpin(s->shadow_ctx, engine); - mutex_unlock(&dev_priv->drm.struct_mutex); + mutex_lock(&rq->i915->drm.struct_mutex); + intel_context_unpin(rq->hw_context); + mutex_unlock(&rq->i915->drm.struct_mutex); + + i915_request_put(rq); } gvt_dbg_sched("ring id %d complete workload %p status %d\n", @@ -1273,7 +1237,6 @@ alloc_workload(struct intel_vgpu *vgpu) atomic_set(&workload->shadow_ctx_active, 0); workload->status = -EINPROGRESS; - workload->shadowed = false; workload->vgpu = vgpu; return workload; diff --git a/drivers/gpu/drm/i915/gvt/scheduler.h b/drivers/gpu/drm/i915/gvt/scheduler.h index 6c644782193e..21eddab4a9cd 100644 --- a/drivers/gpu/drm/i915/gvt/scheduler.h +++ b/drivers/gpu/drm/i915/gvt/scheduler.h @@ -83,7 +83,6 @@ struct intel_vgpu_workload { struct i915_request *req; /* if this workload has been dispatched to i915? */ bool dispatched; - bool shadowed; int status; struct intel_vgpu_mm *shadow_mm; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 04e27806e581..9341b725113b 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1949,6 +1949,7 @@ struct drm_i915_private { */ struct i915_perf_stream *exclusive_stream; + struct intel_context *pinned_ctx; u32 specific_ctx_id; struct hrtimer poll_check_timer; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index ecef2e8e5e93..8a8a77c2ef5f 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3229,14 +3229,14 @@ void i915_gem_reset(struct drm_i915_private *dev_priv, i915_retire_requests(dev_priv); for_each_engine(engine, dev_priv, id) { - struct i915_gem_context *ctx; + struct intel_context *ce; i915_gem_reset_engine(engine, engine->hangcheck.active_request, stalled_mask & ENGINE_MASK(id)); - ctx = fetch_and_zero(&engine->last_retired_context); - if (ctx) - intel_context_unpin(ctx, engine); + ce = fetch_and_zero(&engine->last_retired_context); + if (ce) + intel_context_unpin(ce); /* * Ostensibily, we always want a context loaded for powersaving, @@ -4946,13 +4946,13 @@ void __i915_gem_object_release_unless_active(struct drm_i915_gem_object *obj) static void assert_kernel_context_is_current(struct drm_i915_private *i915) { - struct i915_gem_context *kernel_context = i915->kernel_context; + struct i915_gem_context *kctx = i915->kernel_context; struct intel_engine_cs *engine; enum intel_engine_id id; for_each_engine(engine, i915, id) { GEM_BUG_ON(__i915_gem_active_peek(&engine->timeline.last_request)); - GEM_BUG_ON(engine->last_retired_context != kernel_context); + GEM_BUG_ON(engine->last_retired_context->gem_context != kctx); } } diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 78dc4cb305c2..66aad55c5273 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -127,14 +127,8 @@ static void i915_gem_context_free(struct i915_gem_context *ctx) for (n = 0; n < ARRAY_SIZE(ctx->__engine); n++) { struct intel_context *ce = &ctx->__engine[n]; - if (!ce->state) - continue; - - WARN_ON(ce->pin_count); - if (ce->ring) - intel_ring_free(ce->ring); - - __i915_gem_object_release_unless_active(ce->state->obj); + if (ce->ops) + ce->ops->destroy(ce); } kfree(ctx->name); @@ -266,6 +260,7 @@ __create_hw_context(struct drm_i915_private *dev_priv, struct drm_i915_file_private *file_priv) { struct i915_gem_context *ctx; + unsigned int n; int ret; ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); @@ -283,6 +278,12 @@ __create_hw_context(struct drm_i915_private *dev_priv, ctx->i915 = dev_priv; ctx->sched.priority = I915_PRIORITY_NORMAL; + for (n = 0; n < ARRAY_SIZE(ctx->__engine); n++) { + struct intel_context *ce = &ctx->__engine[n]; + + ce->gem_context = ctx; + } + INIT_RADIX_TREE(&ctx->handles_vma, GFP_KERNEL); INIT_LIST_HEAD(&ctx->handles_list); diff --git a/drivers/gpu/drm/i915/i915_gem_context.h b/drivers/gpu/drm/i915/i915_gem_context.h index ace3b129c189..749a4ff566f5 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.h +++ b/drivers/gpu/drm/i915/i915_gem_context.h @@ -45,6 +45,11 @@ struct intel_ring; #define DEFAULT_CONTEXT_HANDLE 0 +struct intel_context_ops { + void (*unpin)(struct intel_context *ce); + void (*destroy)(struct intel_context *ce); +}; + /** * struct i915_gem_context - client state * @@ -144,11 +149,14 @@ struct i915_gem_context { /** engine: per-engine logical HW state */ struct intel_context { + struct i915_gem_context *gem_context; struct i915_vma *state; struct intel_ring *ring; u32 *lrc_reg_state; u64 lrc_desc; int pin_count; + + const struct intel_context_ops *ops; } __engine[I915_NUM_ENGINES]; /** ring_size: size for allocating the per-engine ring buffer */ @@ -263,25 +271,22 @@ to_intel_context(struct i915_gem_context *ctx, return &ctx->__engine[engine->id]; } -static inline struct intel_ring * +static inline struct intel_context * intel_context_pin(struct i915_gem_context *ctx, struct intel_engine_cs *engine) { return engine->context_pin(engine, ctx); } -static inline void __intel_context_pin(struct i915_gem_context *ctx, - const struct intel_engine_cs *engine) +static inline void __intel_context_pin(struct intel_context *ce) { - struct intel_context *ce = to_intel_context(ctx, engine); - GEM_BUG_ON(!ce->pin_count); ce->pin_count++; } -static inline void intel_context_unpin(struct i915_gem_context *ctx, - struct intel_engine_cs *engine) +static inline void intel_context_unpin(struct intel_context *ce) { - engine->context_unpin(engine, ctx); + GEM_BUG_ON(!ce->ops); + ce->ops->unpin(ce); } /* i915_gem_context.c */ diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index 7cc7d3bc731b..145823f0b48e 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -1485,8 +1485,7 @@ static void gem_record_rings(struct i915_gpu_state *error) ee->ctx = i915_error_object_create(i915, - to_intel_context(ctx, - engine)->state); + request->hw_context->state); error->simulated |= i915_gem_context_no_error_capture(ctx); diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c index d9341415df40..9b580aba7e25 100644 --- a/drivers/gpu/drm/i915/i915_perf.c +++ b/drivers/gpu/drm/i915/i915_perf.c @@ -1221,7 +1221,7 @@ static int oa_get_render_ctx_id(struct i915_perf_stream *stream) dev_priv->perf.oa.specific_ctx_id = stream->ctx->hw_id; } else { struct intel_engine_cs *engine = dev_priv->engine[RCS]; - struct intel_ring *ring; + struct intel_context *ce; int ret; ret = i915_mutex_lock_interruptible(&dev_priv->drm); @@ -1234,19 +1234,19 @@ static int oa_get_render_ctx_id(struct i915_perf_stream *stream) * * NB: implied RCS engine... */ - ring = intel_context_pin(stream->ctx, engine); + ce = intel_context_pin(stream->ctx, engine); mutex_unlock(&dev_priv->drm.struct_mutex); - if (IS_ERR(ring)) - return PTR_ERR(ring); + if (IS_ERR(ce)) + return PTR_ERR(ce); + dev_priv->perf.oa.pinned_ctx = ce; /* * Explicitly track the ID (instead of calling * i915_ggtt_offset() on the fly) considering the difference * with gen8+ and execlists */ - dev_priv->perf.oa.specific_ctx_id = - i915_ggtt_offset(to_intel_context(stream->ctx, engine)->state); + dev_priv->perf.oa.specific_ctx_id = i915_ggtt_offset(ce->state); } return 0; @@ -1262,17 +1262,14 @@ static int oa_get_render_ctx_id(struct i915_perf_stream *stream) static void oa_put_render_ctx_id(struct i915_perf_stream *stream) { struct drm_i915_private *dev_priv = stream->dev_priv; + struct intel_context *ce; - if (HAS_LOGICAL_RING_CONTEXTS(dev_priv)) { - dev_priv->perf.oa.specific_ctx_id = INVALID_CTX_ID; - } else { - struct intel_engine_cs *engine = dev_priv->engine[RCS]; + dev_priv->perf.oa.specific_ctx_id = INVALID_CTX_ID; + ce = fetch_and_zero(&dev_priv->perf.oa.pinned_ctx); + if (ce) { mutex_lock(&dev_priv->drm.struct_mutex); - - dev_priv->perf.oa.specific_ctx_id = INVALID_CTX_ID; - intel_context_unpin(stream->ctx, engine); - + intel_context_unpin(ce); mutex_unlock(&dev_priv->drm.struct_mutex); } } diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c index 5205707fe03a..e5925fcf6004 100644 --- a/drivers/gpu/drm/i915/i915_request.c +++ b/drivers/gpu/drm/i915/i915_request.c @@ -382,8 +382,8 @@ static void __retire_engine_request(struct intel_engine_cs *engine, * the subsequent request. */ if (engine->last_retired_context) - intel_context_unpin(engine->last_retired_context, engine); - engine->last_retired_context = rq->gem_context; + intel_context_unpin(engine->last_retired_context); + engine->last_retired_context = rq->hw_context; } static void __retire_engine_upto(struct intel_engine_cs *engine, @@ -455,7 +455,7 @@ static void i915_request_retire(struct i915_request *request) /* Retirement decays the ban score as it is a sign of ctx progress */ atomic_dec_if_positive(&request->gem_context->ban_score); - intel_context_unpin(request->gem_context, request->engine); + intel_context_unpin(request->hw_context); __retire_engine_upto(request->engine, request); @@ -656,7 +656,7 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx) { struct drm_i915_private *i915 = engine->i915; struct i915_request *rq; - struct intel_ring *ring; + struct intel_context *ce; int ret; lockdep_assert_held(&i915->drm.struct_mutex); @@ -680,22 +680,21 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx) * GGTT space, so do this first before we reserve a seqno for * ourselves. */ - ring = intel_context_pin(ctx, engine); - if (IS_ERR(ring)) - return ERR_CAST(ring); - GEM_BUG_ON(!ring); + ce = intel_context_pin(ctx, engine); + if (IS_ERR(ce)) + return ERR_CAST(ce); ret = reserve_gt(i915); if (ret) goto err_unpin; - ret = intel_ring_wait_for_space(ring, MIN_SPACE_FOR_ADD_REQUEST); + ret = intel_ring_wait_for_space(ce->ring, MIN_SPACE_FOR_ADD_REQUEST); if (ret) goto err_unreserve; /* Move our oldest request to the slab-cache (if not in use!) */ - rq = list_first_entry(&ring->request_list, typeof(*rq), ring_link); - if (!list_is_last(&rq->ring_link, &ring->request_list) && + rq = list_first_entry(&ce->ring->request_list, typeof(*rq), ring_link); + if (!list_is_last(&rq->ring_link, &ce->ring->request_list) && i915_request_completed(rq)) i915_request_retire(rq); @@ -760,8 +759,9 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx) rq->i915 = i915; rq->engine = engine; rq->gem_context = ctx; - rq->ring = ring; - rq->timeline = ring->timeline; + rq->hw_context = ce; + rq->ring = ce->ring; + rq->timeline = ce->ring->timeline; GEM_BUG_ON(rq->timeline == &engine->timeline); spin_lock_init(&rq->lock); @@ -813,14 +813,14 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx) goto err_unwind; /* Keep a second pin for the dual retirement along engine and ring */ - __intel_context_pin(rq->gem_context, engine); + __intel_context_pin(ce); /* Check that we didn't interrupt ourselves with a new request */ GEM_BUG_ON(rq->timeline->seqno != rq->fence.seqno); return rq; err_unwind: - rq->ring->emit = rq->head; + ce->ring->emit = rq->head; /* Make sure we didn't add ourselves to external state before freeing */ GEM_BUG_ON(!list_empty(&rq->active_list)); @@ -831,7 +831,7 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx) err_unreserve: unreserve_gt(i915); err_unpin: - intel_context_unpin(ctx, engine); + intel_context_unpin(ce); return ERR_PTR(ret); } @@ -1017,8 +1017,8 @@ i915_request_await_object(struct i915_request *to, void __i915_request_add(struct i915_request *request, bool flush_caches) { struct intel_engine_cs *engine = request->engine; - struct intel_ring *ring = request->ring; struct i915_timeline *timeline = request->timeline; + struct intel_ring *ring = request->ring; struct i915_request *prev; u32 *cs; int err; diff --git a/drivers/gpu/drm/i915/i915_request.h b/drivers/gpu/drm/i915/i915_request.h index dddecd9ffd0c..1bbbb7a9fa03 100644 --- a/drivers/gpu/drm/i915/i915_request.h +++ b/drivers/gpu/drm/i915/i915_request.h @@ -95,6 +95,7 @@ struct i915_request { */ struct i915_gem_context *gem_context; struct intel_engine_cs *engine; + struct intel_context *hw_context; struct intel_ring *ring; struct i915_timeline *timeline; struct intel_signal_node signaling; diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c index a1b85440ce5a..bddc57ccfa4a 100644 --- a/drivers/gpu/drm/i915/intel_engine_cs.c +++ b/drivers/gpu/drm/i915/intel_engine_cs.c @@ -656,6 +656,12 @@ static int init_phys_status_page(struct intel_engine_cs *engine) return 0; } +static void __intel_context_unpin(struct i915_gem_context *ctx, + struct intel_engine_cs *engine) +{ + intel_context_unpin(to_intel_context(ctx, engine)); +} + /** * intel_engines_init_common - initialize cengine state which might require hw access * @engine: Engine to initialize. @@ -669,7 +675,8 @@ static int init_phys_status_page(struct intel_engine_cs *engine) */ int intel_engine_init_common(struct intel_engine_cs *engine) { - struct intel_ring *ring; + struct drm_i915_private *i915 = engine->i915; + struct intel_context *ce; int ret; engine->set_default_submission(engine); @@ -681,18 +688,18 @@ int intel_engine_init_common(struct intel_engine_cs *engine) * be available. To avoid this we always pin the default * context. */ - ring = intel_context_pin(engine->i915->kernel_context, engine); - if (IS_ERR(ring)) - return PTR_ERR(ring); + ce = intel_context_pin(i915->kernel_context, engine); + if (IS_ERR(ce)) + return PTR_ERR(ce); /* * Similarly the preempt context must always be available so that * we can interrupt the engine at any time. */ - if (engine->i915->preempt_context) { - ring = intel_context_pin(engine->i915->preempt_context, engine); - if (IS_ERR(ring)) { - ret = PTR_ERR(ring); + if (i915->preempt_context) { + ce = intel_context_pin(i915->preempt_context, engine); + if (IS_ERR(ce)) { + ret = PTR_ERR(ce); goto err_unpin_kernel; } } @@ -701,7 +708,7 @@ int intel_engine_init_common(struct intel_engine_cs *engine) if (ret) goto err_unpin_preempt; - if (HWS_NEEDS_PHYSICAL(engine->i915)) + if (HWS_NEEDS_PHYSICAL(i915)) ret = init_phys_status_page(engine); else ret = init_status_page(engine); @@ -713,10 +720,11 @@ int intel_engine_init_common(struct intel_engine_cs *engine) err_breadcrumbs: intel_engine_fini_breadcrumbs(engine); err_unpin_preempt: - if (engine->i915->preempt_context) - intel_context_unpin(engine->i915->preempt_context, engine); + if (i915->preempt_context) + __intel_context_unpin(i915->preempt_context, engine); + err_unpin_kernel: - intel_context_unpin(engine->i915->kernel_context, engine); + __intel_context_unpin(i915->kernel_context, engine); return ret; } @@ -729,6 +737,8 @@ int intel_engine_init_common(struct intel_engine_cs *engine) */ void intel_engine_cleanup_common(struct intel_engine_cs *engine) { + struct drm_i915_private *i915 = engine->i915; + intel_engine_cleanup_scratch(engine); if (HWS_NEEDS_PHYSICAL(engine->i915)) @@ -743,9 +753,9 @@ void intel_engine_cleanup_common(struct intel_engine_cs *engine) if (engine->default_state) i915_gem_object_put(engine->default_state); - if (engine->i915->preempt_context) - intel_context_unpin(engine->i915->preempt_context, engine); - intel_context_unpin(engine->i915->kernel_context, engine); + if (i915->preempt_context) + __intel_context_unpin(i915->preempt_context, engine); + __intel_context_unpin(i915->kernel_context, engine); i915_timeline_fini(&engine->timeline); } @@ -989,8 +999,8 @@ bool intel_engines_are_idle(struct drm_i915_private *dev_priv) */ bool intel_engine_has_kernel_context(const struct intel_engine_cs *engine) { - const struct i915_gem_context * const kernel_context = - engine->i915->kernel_context; + const struct intel_context *kernel_context = + to_intel_context(engine->i915->kernel_context, engine); struct i915_request *rq; lockdep_assert_held(&engine->i915->drm.struct_mutex); @@ -1002,7 +1012,7 @@ bool intel_engine_has_kernel_context(const struct intel_engine_cs *engine) */ rq = __i915_gem_active_peek(&engine->timeline.last_request); if (rq) - return rq->gem_context == kernel_context; + return rq->hw_context == kernel_context; else return engine->last_retired_context == kernel_context; } @@ -1087,16 +1097,16 @@ void intel_engines_unpark(struct drm_i915_private *i915) */ void intel_engine_lost_context(struct intel_engine_cs *engine) { - struct i915_gem_context *ctx; + struct intel_context *ce; lockdep_assert_held(&engine->i915->drm.struct_mutex); engine->legacy_active_context = NULL; engine->legacy_active_ppgtt = NULL; - ctx = fetch_and_zero(&engine->last_retired_context); - if (ctx) - intel_context_unpin(ctx, engine); + ce = fetch_and_zero(&engine->last_retired_context); + if (ce) + intel_context_unpin(ce); } bool intel_engine_can_store_dword(struct intel_engine_cs *engine) diff --git a/drivers/gpu/drm/i915/intel_guc_submission.c b/drivers/gpu/drm/i915/intel_guc_submission.c index cc7b0c1b5e8c..3d4aaaf74a84 100644 --- a/drivers/gpu/drm/i915/intel_guc_submission.c +++ b/drivers/gpu/drm/i915/intel_guc_submission.c @@ -513,9 +513,7 @@ static void guc_add_request(struct intel_guc *guc, struct i915_request *rq) { struct intel_guc_client *client = guc->execbuf_client; struct intel_engine_cs *engine = rq->engine; - u32 ctx_desc = - lower_32_bits(intel_lr_context_descriptor(rq->gem_context, - engine)); + u32 ctx_desc = lower_32_bits(rq->hw_context->lrc_desc); u32 ring_tail = intel_ring_set_tail(rq->ring, rq->tail) / sizeof(u64); spin_lock(&client->wq_lock); @@ -553,8 +551,8 @@ static void inject_preempt_context(struct work_struct *work) preempt_work[engine->id]); struct intel_guc_client *client = guc->preempt_client; struct guc_stage_desc *stage_desc = __get_stage_desc(client); - u32 ctx_desc = lower_32_bits(intel_lr_context_descriptor(client->owner, - engine)); + u32 ctx_desc = lower_32_bits(to_intel_context(client->owner, + engine)->lrc_desc); u32 data[7]; /* @@ -710,7 +708,7 @@ static void guc_dequeue(struct intel_engine_cs *engine) struct i915_request *rq, *rn; list_for_each_entry_safe(rq, rn, &p->requests, sched.link) { - if (last && rq->gem_context != last->gem_context) { + if (last && rq->hw_context != last->hw_context) { if (port == last_port) { __list_del_many(&p->requests, &rq->sched.link); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 578cb89b3af7..c29d5f5582c2 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -164,7 +164,8 @@ #define WA_TAIL_BYTES (sizeof(u32) * WA_TAIL_DWORDS) static int execlists_context_deferred_alloc(struct i915_gem_context *ctx, - struct intel_engine_cs *engine); + struct intel_engine_cs *engine, + struct intel_context *ce); static void execlists_init_reg_state(u32 *reg_state, struct i915_gem_context *ctx, struct intel_engine_cs *engine, @@ -222,9 +223,9 @@ static inline bool need_preempt(const struct intel_engine_cs *engine, */ static void intel_lr_context_descriptor_update(struct i915_gem_context *ctx, - struct intel_engine_cs *engine) + struct intel_engine_cs *engine, + struct intel_context *ce) { - struct intel_context *ce = to_intel_context(ctx, engine); u64 desc; BUILD_BUG_ON(MAX_CONTEXT_HW_ID > (BIT(GEN8_CTX_ID_WIDTH))); @@ -416,8 +417,7 @@ execlists_update_context_pdps(struct i915_hw_ppgtt *ppgtt, u32 *reg_state) static u64 execlists_update_context(struct i915_request *rq) { - struct intel_context *ce = - to_intel_context(rq->gem_context, rq->engine); + struct intel_context *ce = rq->hw_context; struct i915_hw_ppgtt *ppgtt = rq->gem_context->ppgtt ?: rq->i915->mm.aliasing_ppgtt; u32 *reg_state = ce->lrc_reg_state; @@ -494,14 +494,14 @@ static void execlists_submit_ports(struct intel_engine_cs *engine) execlists_clear_active(execlists, EXECLISTS_ACTIVE_HWACK); } -static bool ctx_single_port_submission(const struct i915_gem_context *ctx) +static bool ctx_single_port_submission(const struct intel_context *ce) { return (IS_ENABLED(CONFIG_DRM_I915_GVT) && - i915_gem_context_force_single_submission(ctx)); + i915_gem_context_force_single_submission(ce->gem_context)); } -static bool can_merge_ctx(const struct i915_gem_context *prev, - const struct i915_gem_context *next) +static bool can_merge_ctx(const struct intel_context *prev, + const struct intel_context *next) { if (prev != next) return false; @@ -669,8 +669,8 @@ static void execlists_dequeue(struct intel_engine_cs *engine) * second request, and so we never need to tell the * hardware about the first. */ - if (last && !can_merge_ctx(rq->gem_context, - last->gem_context)) { + if (last && + !can_merge_ctx(rq->hw_context, last->hw_context)) { /* * If we are on the second port and cannot * combine this request with the last, then we @@ -689,14 +689,14 @@ static void execlists_dequeue(struct intel_engine_cs *engine) * the same context (even though a different * request) to the second port. */ - if (ctx_single_port_submission(last->gem_context) || - ctx_single_port_submission(rq->gem_context)) { + if (ctx_single_port_submission(last->hw_context) || + ctx_single_port_submission(rq->hw_context)) { __list_del_many(&p->requests, &rq->sched.link); goto done; } - GEM_BUG_ON(last->gem_context == rq->gem_context); + GEM_BUG_ON(last->hw_context == rq->hw_context); if (submit) port_assign(port, last); @@ -1303,6 +1303,37 @@ static void execlists_schedule(struct i915_request *request, spin_unlock_irq(&engine->timeline.lock); } +static void execlists_context_destroy(struct intel_context *ce) +{ + GEM_BUG_ON(!ce->state); + GEM_BUG_ON(ce->pin_count); + + intel_ring_free(ce->ring); + __i915_gem_object_release_unless_active(ce->state->obj); +} + +static void __execlists_context_unpin(struct intel_context *ce) +{ + intel_ring_unpin(ce->ring); + + ce->state->obj->pin_global--; + i915_gem_object_unpin_map(ce->state->obj); + i915_vma_unpin(ce->state); + + i915_gem_context_put(ce->gem_context); +} + +static void execlists_context_unpin(struct intel_context *ce) +{ + lockdep_assert_held(&ce->gem_context->i915->drm.struct_mutex); + GEM_BUG_ON(ce->pin_count == 0); + + if (--ce->pin_count) + return; + + __execlists_context_unpin(ce); +} + static int __context_pin(struct i915_gem_context *ctx, struct i915_vma *vma) { unsigned int flags; @@ -1326,21 +1357,15 @@ static int __context_pin(struct i915_gem_context *ctx, struct i915_vma *vma) return i915_vma_pin(vma, 0, GEN8_LR_CONTEXT_ALIGN, flags); } -static struct intel_ring * -execlists_context_pin(struct intel_engine_cs *engine, - struct i915_gem_context *ctx) +static struct intel_context * +__execlists_context_pin(struct intel_engine_cs *engine, + struct i915_gem_context *ctx, + struct intel_context *ce) { - struct intel_context *ce = to_intel_context(ctx, engine); void *vaddr; int ret; - lockdep_assert_held(&ctx->i915->drm.struct_mutex); - - if (likely(ce->pin_count++)) - goto out; - GEM_BUG_ON(!ce->pin_count); /* no overflow please! */ - - ret = execlists_context_deferred_alloc(ctx, engine); + ret = execlists_context_deferred_alloc(ctx, engine, ce); if (ret) goto err; GEM_BUG_ON(!ce->state); @@ -1359,7 +1384,7 @@ execlists_context_pin(struct intel_engine_cs *engine, if (ret) goto unpin_map; - intel_lr_context_descriptor_update(ctx, engine); + intel_lr_context_descriptor_update(ctx, engine, ce); ce->lrc_reg_state = vaddr + LRC_STATE_PN * PAGE_SIZE; ce->lrc_reg_state[CTX_RING_BUFFER_START+1] = @@ -1368,8 +1393,7 @@ execlists_context_pin(struct intel_engine_cs *engine, ce->state->obj->pin_global++; i915_gem_context_get(ctx); -out: - return ce->ring; + return ce; unpin_map: i915_gem_object_unpin_map(ce->state->obj); @@ -1380,33 +1404,33 @@ execlists_context_pin(struct intel_engine_cs *engine, return ERR_PTR(ret); } -static void execlists_context_unpin(struct intel_engine_cs *engine, - struct i915_gem_context *ctx) +static const struct intel_context_ops execlists_context_ops = { + .unpin = execlists_context_unpin, + .destroy = execlists_context_destroy, +}; + +static struct intel_context * +execlists_context_pin(struct intel_engine_cs *engine, + struct i915_gem_context *ctx) { struct intel_context *ce = to_intel_context(ctx, engine); lockdep_assert_held(&ctx->i915->drm.struct_mutex); - GEM_BUG_ON(ce->pin_count == 0); - if (--ce->pin_count) - return; - - intel_ring_unpin(ce->ring); + if (likely(ce->pin_count++)) + return ce; + GEM_BUG_ON(!ce->pin_count); /* no overflow please! */ - ce->state->obj->pin_global--; - i915_gem_object_unpin_map(ce->state->obj); - i915_vma_unpin(ce->state); + ce->ops = &execlists_context_ops; - i915_gem_context_put(ctx); + return __execlists_context_pin(engine, ctx, ce); } static int execlists_request_alloc(struct i915_request *request) { - struct intel_context *ce = - to_intel_context(request->gem_context, request->engine); int ret; - GEM_BUG_ON(!ce->pin_count); + GEM_BUG_ON(!request->hw_context->pin_count); /* Flush enough space to reduce the likelihood of waiting after * we start building the request - in which case we will just @@ -1857,7 +1881,7 @@ static void reset_common_ring(struct intel_engine_cs *engine, * future request will be after userspace has had the opportunity * to recreate its own state. */ - regs = to_intel_context(request->gem_context, engine)->lrc_reg_state; + regs = request->hw_context->lrc_reg_state; if (engine->default_state) { void *defaults; @@ -2216,8 +2240,6 @@ logical_ring_default_vfuncs(struct intel_engine_cs *engine) engine->reset_hw = reset_common_ring; engine->context_pin = execlists_context_pin; - engine->context_unpin = execlists_context_unpin; - engine->request_alloc = execlists_request_alloc; engine->emit_flush = gen8_emit_flush; @@ -2452,7 +2474,7 @@ static void execlists_init_reg_state(u32 *regs, struct drm_i915_private *dev_priv = engine->i915; struct i915_hw_ppgtt *ppgtt = ctx->ppgtt ?: dev_priv->mm.aliasing_ppgtt; u32 base = engine->mmio_base; - bool rcs = engine->id == RCS; + bool rcs = engine->class == RENDER_CLASS; /* A context is actually a big batch buffer with several * MI_LOAD_REGISTER_IMM commands followed by (reg, value) pairs. The @@ -2597,10 +2619,10 @@ populate_lr_context(struct i915_gem_context *ctx, } static int execlists_context_deferred_alloc(struct i915_gem_context *ctx, - struct intel_engine_cs *engine) + struct intel_engine_cs *engine, + struct intel_context *ce) { struct drm_i915_gem_object *ctx_obj; - struct intel_context *ce = to_intel_context(ctx, engine); struct i915_vma *vma; uint32_t context_size; struct intel_ring *ring; diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index 4ec7d8dd13c8..1593194e930c 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -104,11 +104,4 @@ struct i915_gem_context; void intel_lr_context_resume(struct drm_i915_private *dev_priv); -static inline uint64_t -intel_lr_context_descriptor(struct i915_gem_context *ctx, - struct intel_engine_cs *engine) -{ - return to_intel_context(ctx, engine)->lrc_desc; -} - #endif /* _INTEL_LRC_H_ */ diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index fbd23127505d..526ee8302fce 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -558,8 +558,7 @@ static void reset_ring_common(struct intel_engine_cs *engine, */ if (request) { struct drm_i915_private *dev_priv = request->i915; - struct intel_context *ce = - to_intel_context(request->gem_context, engine); + struct intel_context *ce = request->hw_context; struct i915_hw_ppgtt *ppgtt; if (ce->state) { @@ -1169,7 +1168,31 @@ intel_ring_free(struct intel_ring *ring) kfree(ring); } -static int context_pin(struct intel_context *ce) +static void intel_ring_context_destroy(struct intel_context *ce) +{ + GEM_BUG_ON(ce->pin_count); + + if (ce->state) + __i915_gem_object_release_unless_active(ce->state->obj); +} + +static void intel_ring_context_unpin(struct intel_context *ce) +{ + lockdep_assert_held(&ce->gem_context->i915->drm.struct_mutex); + GEM_BUG_ON(ce->pin_count == 0); + + if (--ce->pin_count) + return; + + if (ce->state) { + ce->state->obj->pin_global--; + i915_vma_unpin(ce->state); + } + + i915_gem_context_put(ce->gem_context); +} + +static int __context_pin(struct intel_context *ce) { struct i915_vma *vma = ce->state; int ret; @@ -1258,25 +1281,19 @@ alloc_context_vma(struct intel_engine_cs *engine) return ERR_PTR(err); } -static struct intel_ring * -intel_ring_context_pin(struct intel_engine_cs *engine, - struct i915_gem_context *ctx) +static struct intel_context * +__ring_context_pin(struct intel_engine_cs *engine, + struct i915_gem_context *ctx, + struct intel_context *ce) { - struct intel_context *ce = to_intel_context(ctx, engine); - int ret; - - lockdep_assert_held(&ctx->i915->drm.struct_mutex); - - if (likely(ce->pin_count++)) - goto out; - GEM_BUG_ON(!ce->pin_count); /* no overflow please! */ + int err; if (!ce->state && engine->context_size) { struct i915_vma *vma; vma = alloc_context_vma(engine); if (IS_ERR(vma)) { - ret = PTR_ERR(vma); + err = PTR_ERR(vma); goto err; } @@ -1284,8 +1301,8 @@ intel_ring_context_pin(struct intel_engine_cs *engine, } if (ce->state) { - ret = context_pin(ce); - if (ret) + err = __context_pin(ce); + if (err) goto err; ce->state->obj->pin_global++; @@ -1293,32 +1310,37 @@ intel_ring_context_pin(struct intel_engine_cs *engine, i915_gem_context_get(ctx); -out: /* One ringbuffer to rule them all */ - return engine->buffer; + GEM_BUG_ON(!engine->buffer); + ce->ring = engine->buffer; + + return ce; err: ce->pin_count = 0; - return ERR_PTR(ret); + return ERR_PTR(err); } -static void intel_ring_context_unpin(struct intel_engine_cs *engine, - struct i915_gem_context *ctx) +static const struct intel_context_ops ring_context_ops = { + .unpin = intel_ring_context_unpin, + .destroy = intel_ring_context_destroy, +}; + +static struct intel_context * +intel_ring_context_pin(struct intel_engine_cs *engine, + struct i915_gem_context *ctx) { struct intel_context *ce = to_intel_context(ctx, engine); lockdep_assert_held(&ctx->i915->drm.struct_mutex); - GEM_BUG_ON(ce->pin_count == 0); - if (--ce->pin_count) - return; + if (likely(ce->pin_count++)) + return ce; + GEM_BUG_ON(!ce->pin_count); /* no overflow please! */ - if (ce->state) { - ce->state->obj->pin_global--; - i915_vma_unpin(ce->state); - } + ce->ops = &ring_context_ops; - i915_gem_context_put(ctx); + return __ring_context_pin(engine, ctx, ce); } static int intel_init_ring_buffer(struct intel_engine_cs *engine) @@ -1329,10 +1351,6 @@ static int intel_init_ring_buffer(struct intel_engine_cs *engine) intel_engine_setup_common(engine); - err = intel_engine_init_common(engine); - if (err) - goto err; - timeline = i915_timeline_create(engine->i915, engine->name); if (IS_ERR(timeline)) { err = PTR_ERR(timeline); @@ -1354,8 +1372,14 @@ static int intel_init_ring_buffer(struct intel_engine_cs *engine) GEM_BUG_ON(engine->buffer); engine->buffer = ring; + err = intel_engine_init_common(engine); + if (err) + goto err_unpin; + return 0; +err_unpin: + intel_ring_unpin(ring); err_ring: intel_ring_free(ring); err: @@ -1441,7 +1465,7 @@ static inline int mi_set_context(struct i915_request *rq, u32 flags) *cs++ = MI_NOOP; *cs++ = MI_SET_CONTEXT; - *cs++ = i915_ggtt_offset(to_intel_context(rq->gem_context, engine)->state) | flags; + *cs++ = i915_ggtt_offset(rq->hw_context->state) | flags; /* * w/a: MI_SET_CONTEXT must always be followed by MI_NOOP * WaMiSetContext_Hang:snb,ivb,vlv @@ -1532,7 +1556,7 @@ static int switch_context(struct i915_request *rq) hw_flags = MI_FORCE_RESTORE; } - if (to_intel_context(to_ctx, engine)->state && + if (rq->hw_context->state && (to_ctx != from_ctx || hw_flags & MI_FORCE_RESTORE)) { GEM_BUG_ON(engine->id != RCS); @@ -1580,7 +1604,7 @@ static int ring_request_alloc(struct i915_request *request) { int ret; - GEM_BUG_ON(!to_intel_context(request->gem_context, request->engine)->pin_count); + GEM_BUG_ON(!request->hw_context->pin_count); /* Flush enough space to reduce the likelihood of waiting after * we start building the request - in which case we will just @@ -2009,8 +2033,6 @@ static void intel_ring_default_vfuncs(struct drm_i915_private *dev_priv, engine->reset_hw = reset_ring_common; engine->context_pin = intel_ring_context_pin; - engine->context_unpin = intel_ring_context_unpin; - engine->request_alloc = ring_request_alloc; engine->emit_breadcrumb = i9xx_emit_breadcrumb; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index c4e56044e34f..5e78ee3f5775 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -431,10 +431,9 @@ struct intel_engine_cs { void (*set_default_submission)(struct intel_engine_cs *engine); - struct intel_ring *(*context_pin)(struct intel_engine_cs *engine, - struct i915_gem_context *ctx); - void (*context_unpin)(struct intel_engine_cs *engine, - struct i915_gem_context *ctx); + struct intel_context *(*context_pin)(struct intel_engine_cs *engine, + struct i915_gem_context *ctx); + int (*request_alloc)(struct i915_request *rq); int (*init_context)(struct i915_request *rq); @@ -550,7 +549,7 @@ struct intel_engine_cs { * to the kernel context and trash it as the save may not happen * before the hardware is powered down. */ - struct i915_gem_context *last_retired_context; + struct intel_context *last_retired_context; /* We track the current MI_SET_CONTEXT in order to eliminate * redudant context switches. This presumes that requests are not diff --git a/drivers/gpu/drm/i915/selftests/mock_context.c b/drivers/gpu/drm/i915/selftests/mock_context.c index 501becc47c0c..8904f1ce64e3 100644 --- a/drivers/gpu/drm/i915/selftests/mock_context.c +++ b/drivers/gpu/drm/i915/selftests/mock_context.c @@ -30,6 +30,7 @@ mock_context(struct drm_i915_private *i915, const char *name) { struct i915_gem_context *ctx; + unsigned int n; int ret; ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); @@ -43,6 +44,12 @@ mock_context(struct drm_i915_private *i915, INIT_RADIX_TREE(&ctx->handles_vma, GFP_KERNEL); INIT_LIST_HEAD(&ctx->handles_list); + for (n = 0; n < ARRAY_SIZE(ctx->__engine); n++) { + struct intel_context *ce = &ctx->__engine[n]; + + ce->gem_context = ctx; + } + ret = ida_simple_get(&i915->contexts.hw_ida, 0, MAX_CONTEXT_HW_ID, GFP_KERNEL); if (ret < 0) diff --git a/drivers/gpu/drm/i915/selftests/mock_engine.c b/drivers/gpu/drm/i915/selftests/mock_engine.c index 26bf29d97007..33eddfc1f8ce 100644 --- a/drivers/gpu/drm/i915/selftests/mock_engine.c +++ b/drivers/gpu/drm/i915/selftests/mock_engine.c @@ -72,25 +72,37 @@ static void hw_delay_complete(struct timer_list *t) spin_unlock(&engine->hw_lock); } -static struct intel_ring * -mock_context_pin(struct intel_engine_cs *engine, - struct i915_gem_context *ctx) +static void mock_context_unpin(struct intel_context *ce) { - struct intel_context *ce = to_intel_context(ctx, engine); + if (--ce->pin_count) + return; - if (!ce->pin_count++) - i915_gem_context_get(ctx); + i915_gem_context_put(ce->gem_context); +} - return engine->buffer; +static void mock_context_destroy(struct intel_context *ce) +{ + GEM_BUG_ON(ce->pin_count); } -static void mock_context_unpin(struct intel_engine_cs *engine, - struct i915_gem_context *ctx) +static const struct intel_context_ops mock_context_ops = { + .unpin = mock_context_unpin, + .destroy = mock_context_destroy, +}; + +static struct intel_context * +mock_context_pin(struct intel_engine_cs *engine, + struct i915_gem_context *ctx) { struct intel_context *ce = to_intel_context(ctx, engine); - if (!--ce->pin_count) - i915_gem_context_put(ctx); + if (!ce->pin_count++) { + i915_gem_context_get(ctx); + ce->ring = engine->buffer; + ce->ops = &mock_context_ops; + } + + return ce; } static int mock_request_alloc(struct i915_request *request) @@ -185,7 +197,6 @@ struct intel_engine_cs *mock_engine(struct drm_i915_private *i915, engine->base.status_page.page_addr = (void *)(engine + 1); engine->base.context_pin = mock_context_pin; - engine->base.context_unpin = mock_context_unpin; engine->base.request_alloc = mock_request_alloc; engine->base.emit_flush = mock_emit_flush; engine->base.emit_breadcrumb = mock_emit_breadcrumb; @@ -238,11 +249,13 @@ void mock_engine_free(struct intel_engine_cs *engine) { struct mock_engine *mock = container_of(engine, typeof(*mock), base); + struct intel_context *ce; GEM_BUG_ON(timer_pending(&mock->hw_delay)); - if (engine->last_retired_context) - intel_context_unpin(engine->last_retired_context, engine); + ce = fetch_and_zero(&engine->last_retired_context); + if (ce) + intel_context_unpin(ce); mock_ring_free(engine->buffer);
To ease the frequent and ugly pointer dance of &request->gem_context->engine[request->engine->id] during request submission, store that pointer as request->hw_context. One major advantage that we will exploit later is that this decouples the logical context state from the engine itself. v2: Set mock_context->ops so we don't crash and burn in selftests. Cleanups from Tvrtko. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> --- drivers/gpu/drm/i915/gvt/mmio_context.c | 6 +- drivers/gpu/drm/i915/gvt/mmio_context.h | 2 +- drivers/gpu/drm/i915/gvt/scheduler.c | 141 +++++++----------- drivers/gpu/drm/i915/gvt/scheduler.h | 1 - drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_gem.c | 12 +- drivers/gpu/drm/i915/i915_gem_context.c | 17 ++- drivers/gpu/drm/i915/i915_gem_context.h | 21 ++- drivers/gpu/drm/i915/i915_gpu_error.c | 3 +- drivers/gpu/drm/i915/i915_perf.c | 25 ++-- drivers/gpu/drm/i915/i915_request.c | 34 ++--- drivers/gpu/drm/i915/i915_request.h | 1 + drivers/gpu/drm/i915/intel_engine_cs.c | 54 ++++--- drivers/gpu/drm/i915/intel_guc_submission.c | 10 +- drivers/gpu/drm/i915/intel_lrc.c | 118 +++++++++------ drivers/gpu/drm/i915/intel_lrc.h | 7 - drivers/gpu/drm/i915/intel_ringbuffer.c | 100 ++++++++----- drivers/gpu/drm/i915/intel_ringbuffer.h | 9 +- drivers/gpu/drm/i915/selftests/mock_context.c | 7 + drivers/gpu/drm/i915/selftests/mock_engine.c | 41 +++-- 20 files changed, 320 insertions(+), 290 deletions(-)