[Intel-gfx] [PATCH v2 13/22] drm/i915: Update reset path to fix incomplete requests

Mika Kuoppala mika.kuoppala at linux.intel.com
Thu Sep 8 12:03:46 UTC 2016


Chris Wilson <chris at chris-wilson.co.uk> writes:

> Update reset path in preparation for engine reset which requires
> identification of incomplete requests and associated context and fixing
> their state so that engine can resume correctly after reset.
>
> The request that caused the hang will be skipped and head is reset to the
> start of breadcrumb. This allows us to resume from where we left-off.
> Since this request didn't complete normally we also need to cleanup elsp
> queue manually. This is vital if we employ nonblocking request
> submission where we may have a web of dependencies upon the hung request
> and so advancing the seqno manually is no longer trivial.
>
> ABI: gem_reset_stats / DRM_IOCTL_I915_GET_RESET_STATS
>
> We change the way we count pending batches. Only the active context
> involved in the reset is marked as either innocent or guilty, and not
> mark the entire world as pending. By inspection this only affects
> igt/gem_reset_stats (which assumes implementation details) and not
> piglit.
>
> ARB_robustness gives this guide on how we expect the user of this
> interface to behave:
>
>  * Provide a mechanism for an OpenGL application to learn about
>    graphics resets that affect the context.  When a graphics reset
>    occurs, the OpenGL context becomes unusable and the application
>    must create a new context to continue operation. Detecting a
>    graphics reset happens through an inexpensive query.
>
> And with regards to the actual meaning of the reset values:
>
>    Certain events can result in a reset of the GL context. Such a reset
>    causes all context state to be lost. Recovery from such events
>    requires recreation of all objects in the affected context. The
>    current status of the graphics reset state is returned by
>
> 	enum GetGraphicsResetStatusARB();
>
>    The symbolic constant returned indicates if the GL context has been
>    in a reset state at any point since the last call to
>    GetGraphicsResetStatusARB. NO_ERROR indicates that the GL context
>    has not been in a reset state since the last call.
>    GUILTY_CONTEXT_RESET_ARB indicates that a reset has been detected
>    that is attributable to the current GL context.
>    INNOCENT_CONTEXT_RESET_ARB indicates a reset has been detected that
>    is not attributable to the current GL context.
>    UNKNOWN_CONTEXT_RESET_ARB indicates a detected graphics reset whose
>    cause is unknown.
>
> The language here is explicit in that we must mark up the guilty batch,
> but is loose enough for us to relax the innocent (i.e. pending)
> accounting as only the active batches are involved with the reset.
>
> In the future, we are looking towards single engine resetting (with
> minimal locking), where it seems inappropriate to mark the entire world
> as innocent since the reset occurred on a different engine. Reducing the
> information available means we only have to encounter the pain once, and
> also reduces the information leaking from one context to another.
>
> v2: Legacy ringbuffer submission required a reset following hibernation,
> or else we restore stale values to the RING_HEAD and walked over
> stolen garbage.
>
> v3: GuC requires replaying the requests after a reset.
>
> v4: Restore engine IRQ after reset (so waiters will be woken!)
>     Rearm hangcheck if resetting with a waiter.
>
> Cc: Tvrtko Ursulin <tvrtko.ursulin at intel.com>
> Cc: Mika Kuoppala <mika.kuoppala at intel.com>
> Cc: Arun Siluvery <arun.siluvery at linux.intel.com>
> Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>

Reviewed-by: Mika Kuoppala <mika.kuoppala at intel.com>

> ---
>  drivers/gpu/drm/i915/i915_drv.c            |   8 +-
>  drivers/gpu/drm/i915/i915_drv.h            |   5 +-
>  drivers/gpu/drm/i915/i915_gem.c            | 123 +++++++++++++++++------------
>  drivers/gpu/drm/i915/i915_gem_context.c    |  16 ----
>  drivers/gpu/drm/i915/i915_guc_submission.c |   8 +-
>  drivers/gpu/drm/i915/intel_engine_cs.c     |  15 +++-
>  drivers/gpu/drm/i915/intel_lrc.c           |  49 ++++++++++--
>  drivers/gpu/drm/i915/intel_lrc.h           |   3 +-
>  drivers/gpu/drm/i915/intel_ringbuffer.c    |  47 +++++++----
>  drivers/gpu/drm/i915/intel_ringbuffer.h    |   7 +-
>  10 files changed, 183 insertions(+), 98 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
> index c1b890dbd6cc..2b0727d1467d 100644
> --- a/drivers/gpu/drm/i915/i915_drv.c
> +++ b/drivers/gpu/drm/i915/i915_drv.c
> @@ -559,7 +559,6 @@ static void i915_gem_fini(struct drm_device *dev)
>  	}
>  
>  	mutex_lock(&dev->struct_mutex);
> -	i915_gem_reset(dev);
>  	i915_gem_cleanup_engines(dev);
>  	i915_gem_context_fini(dev);
>  	mutex_unlock(&dev->struct_mutex);
> @@ -1579,7 +1578,7 @@ static int i915_drm_resume(struct drm_device *dev)
>  	mutex_lock(&dev->struct_mutex);
>  	if (i915_gem_init_hw(dev)) {
>  		DRM_ERROR("failed to re-initialize GPU, declaring wedged!\n");
> -		set_bit(I915_WEDGED, &dev_priv->gpu_error.flags);
> +		i915_gem_set_wedged(dev_priv);
>  	}
>  	mutex_unlock(&dev->struct_mutex);
>  
> @@ -1756,8 +1755,6 @@ int i915_reset(struct drm_i915_private *dev_priv)
>  
>  	pr_notice("drm/i915: Resetting chip after gpu hang\n");
>  
> -	i915_gem_reset(dev);
> -
>  	ret = intel_gpu_reset(dev_priv, ALL_ENGINES);
>  	if (ret) {
>  		if (ret != -ENODEV)
> @@ -1767,6 +1764,7 @@ int i915_reset(struct drm_i915_private *dev_priv)
>  		goto error;
>  	}
>  
> +	i915_gem_reset(dev_priv);
>  	intel_overlay_reset(dev_priv);
>  
>  	/* Ok, now get things going again... */
> @@ -1803,7 +1801,7 @@ out:
>  	return ret;
>  
>  error:
> -	set_bit(I915_WEDGED, &error->flags);
> +	i915_gem_set_wedged(dev_priv);
>  	goto out;
>  }
>  
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 2e2fd8a77233..a63bf820aa8f 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -2029,6 +2029,7 @@ struct drm_i915_private {
>  
>  	/* Abstract the submission mechanism (legacy ringbuffer or execlists) away */
>  	struct {
> +		void (*resume)(struct drm_i915_private *);
>  		void (*cleanup_engine)(struct intel_engine_cs *engine);
>  
>  		/**
> @@ -3262,7 +3263,8 @@ static inline u32 i915_reset_count(struct i915_gpu_error *error)
>  	return READ_ONCE(error->reset_count);
>  }
>  
> -void i915_gem_reset(struct drm_device *dev);
> +void i915_gem_reset(struct drm_i915_private *dev_priv);
> +void i915_gem_set_wedged(struct drm_i915_private *dev_priv);
>  bool i915_gem_clflush_object(struct drm_i915_gem_object *obj, bool force);
>  int __must_check i915_gem_init(struct drm_device *dev);
>  int __must_check i915_gem_init_hw(struct drm_device *dev);
> @@ -3391,7 +3393,6 @@ void i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj);
>  int __must_check i915_gem_context_init(struct drm_device *dev);
>  void i915_gem_context_lost(struct drm_i915_private *dev_priv);
>  void i915_gem_context_fini(struct drm_device *dev);
> -void i915_gem_context_reset(struct drm_device *dev);
>  int i915_gem_context_open(struct drm_device *dev, struct drm_file *file);
>  void i915_gem_context_close(struct drm_device *dev, struct drm_file *file);
>  int i915_switch_context(struct drm_i915_gem_request *req);
> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> index 23069a2d2850..65a69bbe021d 100644
> --- a/drivers/gpu/drm/i915/i915_gem.c
> +++ b/drivers/gpu/drm/i915/i915_gem.c
> @@ -2555,29 +2555,83 @@ i915_gem_find_active_request(struct intel_engine_cs *engine)
>  	return NULL;
>  }
>  
> -static void i915_gem_reset_engine_status(struct intel_engine_cs *engine)
> +static void reset_request(struct drm_i915_gem_request *request)
> +{
> +	void *vaddr = request->ring->vaddr;
> +	u32 head;
> +
> +	/* As this request likely depends on state from the lost
> +	 * context, clear out all the user operations leaving the
> +	 * breadcrumb at the end (so we get the fence notifications).
> +	 */
> +	head = request->head;
> +	if (request->postfix < head) {
> +		memset(vaddr + head, 0, request->ring->size - head);
> +		head = 0;
> +	}
> +	memset(vaddr + head, 0, request->postfix - head);
> +}
> +
> +static void i915_gem_reset_engine(struct intel_engine_cs *engine)
>  {
>  	struct drm_i915_gem_request *request;
> +	struct i915_gem_context *incomplete_ctx;
>  	bool ring_hung;
>  
> +	/* Ensure irq handler finishes, and not run again. */
> +	tasklet_kill(&engine->irq_tasklet);
> +
>  	request = i915_gem_find_active_request(engine);
> -	if (request == NULL)
> +	if (!request)
>  		return;
>  
>  	ring_hung = engine->hangcheck.score >= HANGCHECK_SCORE_RING_HUNG;
> -
>  	i915_set_reset_status(request->ctx, ring_hung);
> +	if (!ring_hung)
> +		return;
> +
> +	DRM_DEBUG_DRIVER("reseting %s to start from tail of request 0x%x\n",
> +			 engine->name, request->fence.seqno);
> +
> +	/* Setup the CS to resume from the breadcrumb of the hung request */
> +	engine->reset_hw(engine, request);
> +
> +	/* Users of the default context do not rely on logical state
> +	 * preserved between batches. They have to emit full state on
> +	 * every batch and so it is safe to execute queued requests following
> +	 * the hang.
> +	 *
> +	 * Other contexts preserve state, now corrupt. We want to skip all
> +	 * queued requests that reference the corrupt context.
> +	 */
> +	incomplete_ctx = request->ctx;
> +	if (i915_gem_context_is_default(incomplete_ctx))
> +		return;
> +
>  	list_for_each_entry_continue(request, &engine->request_list, link)
> -		i915_set_reset_status(request->ctx, false);
> +		if (request->ctx == incomplete_ctx)
> +			reset_request(request);
>  }
>  
> -static void i915_gem_reset_engine_cleanup(struct intel_engine_cs *engine)
> +void i915_gem_reset(struct drm_i915_private *dev_priv)
>  {
> -	struct drm_i915_gem_request *request;
> -	struct intel_ring *ring;
> +	struct intel_engine_cs *engine;
>  
> -	/* Ensure irq handler finishes, and not run again. */
> -	tasklet_kill(&engine->irq_tasklet);
> +	i915_gem_retire_requests(dev_priv);
> +
> +	for_each_engine(engine, dev_priv)
> +		i915_gem_reset_engine(engine);
> +
> +	i915_gem_restore_fences(&dev_priv->drm);
> +}
> +
> +static void nop_submit_request(struct drm_i915_gem_request *request)
> +{
> +}
> +
> +static void i915_gem_cleanup_engine(struct intel_engine_cs *engine)
> +{
> +	engine->submit_request = nop_submit_request;
>  
>  	/* Mark all pending requests as complete so that any concurrent
>  	 * (lockless) lookup doesn't try and wait upon the request as we
> @@ -2600,54 +2654,22 @@ static void i915_gem_reset_engine_cleanup(struct intel_engine_cs *engine)
>  		spin_unlock(&engine->execlist_lock);
>  	}
>  
> -	/*
> -	 * We must free the requests after all the corresponding objects have
> -	 * been moved off active lists. Which is the same order as the normal
> -	 * retire_requests function does. This is important if object hold
> -	 * implicit references on things like e.g. ppgtt address spaces through
> -	 * the request.
> -	 */
> -	request = i915_gem_active_raw(&engine->last_request,
> -				      &engine->i915->drm.struct_mutex);
> -	if (request)
> -		i915_gem_request_retire_upto(request);
> -	GEM_BUG_ON(intel_engine_is_active(engine));
> -
> -	/* Having flushed all requests from all queues, we know that all
> -	 * ringbuffers must now be empty. However, since we do not reclaim
> -	 * all space when retiring the request (to prevent HEADs colliding
> -	 * with rapid ringbuffer wraparound) the amount of available space
> -	 * upon reset is less than when we start. Do one more pass over
> -	 * all the ringbuffers to reset last_retired_head.
> -	 */
> -	list_for_each_entry(ring, &engine->buffers, link) {
> -		ring->last_retired_head = ring->tail;
> -		intel_ring_update_space(ring);
> -	}
> -
>  	engine->i915->gt.active_engines &= ~intel_engine_flag(engine);
>  }
>  
> -void i915_gem_reset(struct drm_device *dev)
> +void i915_gem_set_wedged(struct drm_i915_private *dev_priv)
>  {
> -	struct drm_i915_private *dev_priv = to_i915(dev);
>  	struct intel_engine_cs *engine;
>  
> -	/*
> -	 * Before we free the objects from the requests, we need to inspect
> -	 * them for finding the guilty party. As the requests only borrow
> -	 * their reference to the objects, the inspection must be done first.
> -	 */
> -	for_each_engine(engine, dev_priv)
> -		i915_gem_reset_engine_status(engine);
> +	lockdep_assert_held(&dev_priv->drm.struct_mutex);
> +	set_bit(I915_WEDGED, &dev_priv->gpu_error.flags);
>  
> +	i915_gem_context_lost(dev_priv);
>  	for_each_engine(engine, dev_priv)
> -		i915_gem_reset_engine_cleanup(engine);
> +		i915_gem_cleanup_engine(engine);
>  	mod_delayed_work(dev_priv->wq, &dev_priv->gt.idle_work, 0);
>  
> -	i915_gem_context_reset(dev);
> -
> -	i915_gem_restore_fences(dev);
> +	i915_gem_retire_requests(dev_priv);
>  }
>  
>  static void
> @@ -4343,8 +4365,7 @@ void i915_gem_resume(struct drm_device *dev)
>  	 * guarantee that the context image is complete. So let's just reset
>  	 * it and start again.
>  	 */
> -	if (i915.enable_execlists)
> -		intel_lr_context_reset(dev_priv, dev_priv->kernel_context);
> +	dev_priv->gt.resume(dev_priv);
>  
>  	mutex_unlock(&dev->struct_mutex);
>  }
> @@ -4496,8 +4517,10 @@ int i915_gem_init(struct drm_device *dev)
>  	mutex_lock(&dev->struct_mutex);
>  
>  	if (!i915.enable_execlists) {
> +		dev_priv->gt.resume = intel_legacy_submission_resume;
>  		dev_priv->gt.cleanup_engine = intel_engine_cleanup;
>  	} else {
> +		dev_priv->gt.resume = intel_lr_context_resume;
>  		dev_priv->gt.cleanup_engine = intel_logical_ring_cleanup;
>  	}
>  
> @@ -4530,7 +4553,7 @@ int i915_gem_init(struct drm_device *dev)
>  		 * for all other failure, such as an allocation failure, bail.
>  		 */
>  		DRM_ERROR("Failed to initialize GPU, declaring it wedged\n");
> -		set_bit(I915_WEDGED, &dev_priv->gpu_error.flags);
> +		i915_gem_set_wedged(dev_priv);
>  		ret = 0;
>  	}
>  
> diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
> index 35950ee46a1d..df10f4e95736 100644
> --- a/drivers/gpu/drm/i915/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/i915_gem_context.c
> @@ -420,22 +420,6 @@ static void i915_gem_context_unpin(struct i915_gem_context *ctx,
>  	}
>  }
>  
> -void i915_gem_context_reset(struct drm_device *dev)
> -{
> -	struct drm_i915_private *dev_priv = to_i915(dev);
> -
> -	lockdep_assert_held(&dev->struct_mutex);
> -
> -	if (i915.enable_execlists) {
> -		struct i915_gem_context *ctx;
> -
> -		list_for_each_entry(ctx, &dev_priv->context_list, link)
> -			intel_lr_context_reset(dev_priv, ctx);
> -	}
> -
> -	i915_gem_context_lost(dev_priv);
> -}
> -
>  int i915_gem_context_init(struct drm_device *dev)
>  {
>  	struct drm_i915_private *dev_priv = to_i915(dev);
> diff --git a/drivers/gpu/drm/i915/i915_guc_submission.c b/drivers/gpu/drm/i915/i915_guc_submission.c
> index 77526d7f41f8..d5a4e9edccc5 100644
> --- a/drivers/gpu/drm/i915/i915_guc_submission.c
> +++ b/drivers/gpu/drm/i915/i915_guc_submission.c
> @@ -994,6 +994,7 @@ int i915_guc_submission_enable(struct drm_i915_private *dev_priv)
>  	struct intel_guc *guc = &dev_priv->guc;
>  	struct i915_guc_client *client;
>  	struct intel_engine_cs *engine;
> +	struct drm_i915_gem_request *request;
>  
>  	/* client for execbuf submission */
>  	client = guc_client_alloc(dev_priv,
> @@ -1010,9 +1011,14 @@ int i915_guc_submission_enable(struct drm_i915_private *dev_priv)
>  	guc_init_doorbell_hw(guc);
>  
>  	/* Take over from manual control of ELSP (execlists) */
> -	for_each_engine(engine, dev_priv)
> +	for_each_engine(engine, dev_priv) {
>  		engine->submit_request = i915_guc_submit;
>  
> +		/* Replay the current set of previously submitted requests */
> +		list_for_each_entry(request, &engine->request_list, link)
> +			i915_guc_submit(request);
> +	}
> +
>  	return 0;
>  }
>  
> diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c
> index 2e96a86105c2..e405f1080296 100644
> --- a/drivers/gpu/drm/i915/intel_engine_cs.c
> +++ b/drivers/gpu/drm/i915/intel_engine_cs.c
> @@ -211,6 +211,8 @@ void intel_engine_init_hangcheck(struct intel_engine_cs *engine)
>  {
>  	memset(&engine->hangcheck, 0, sizeof(engine->hangcheck));
>  	clear_bit(engine->id, &engine->i915->gpu_error.missed_irq_rings);
> +	if (intel_engine_has_waiter(engine))
> +		i915_queue_hangcheck(engine->i915);
>  }
>  
>  static void intel_engine_init_requests(struct intel_engine_cs *engine)
> @@ -230,7 +232,6 @@ static void intel_engine_init_requests(struct intel_engine_cs *engine)
>   */
>  void intel_engine_setup_common(struct intel_engine_cs *engine)
>  {
> -	INIT_LIST_HEAD(&engine->buffers);
>  	INIT_LIST_HEAD(&engine->execlist_queue);
>  	spin_lock_init(&engine->execlist_lock);
>  
> @@ -306,6 +307,18 @@ int intel_engine_init_common(struct intel_engine_cs *engine)
>  	return 0;
>  }
>  
> +void intel_engine_reset_irq(struct intel_engine_cs *engine)
> +{
> +	struct drm_i915_private *dev_priv = engine->i915;
> +
> +	spin_lock_irq(&dev_priv->irq_lock);
> +	if (intel_engine_has_waiter(engine))
> +		engine->irq_enable(engine);
> +	else
> +		engine->irq_disable(engine);
> +	spin_unlock_irq(&dev_priv->irq_lock);
> +}
> +
>  /**
>   * intel_engines_cleanup_common - cleans up the engine state created by
>   *                                the common initiailizers.
> diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
> index a33687d294b5..61549a623e2c 100644
> --- a/drivers/gpu/drm/i915/intel_lrc.c
> +++ b/drivers/gpu/drm/i915/intel_lrc.c
> @@ -1222,11 +1222,16 @@ static void lrc_init_hws(struct intel_engine_cs *engine)
>  static int gen8_init_common_ring(struct intel_engine_cs *engine)
>  {
>  	struct drm_i915_private *dev_priv = engine->i915;
> +	int ret;
> +
> +	ret = intel_mocs_init_engine(engine);
> +	if (ret)
> +		return ret;
>  
>  	lrc_init_hws(engine);
>  
> -	I915_WRITE_IMR(engine,
> -		       ~(engine->irq_enable_mask | engine->irq_keep_mask));
> +	intel_engine_reset_irq(engine);
> +
>  	I915_WRITE(RING_HWSTAM(engine->mmio_base), 0xffffffff);
>  
>  	I915_WRITE(RING_MODE_GEN7(engine),
> @@ -1237,7 +1242,10 @@ static int gen8_init_common_ring(struct intel_engine_cs *engine)
>  
>  	intel_engine_init_hangcheck(engine);
>  
> -	return intel_mocs_init_engine(engine);
> +	if (!execlists_elsp_idle(engine))
> +		execlists_submit_ports(engine);
> +
> +	return 0;
>  }
>  
>  static int gen8_init_render_ring(struct intel_engine_cs *engine)
> @@ -1273,6 +1281,36 @@ static int gen9_init_render_ring(struct intel_engine_cs *engine)
>  	return init_workarounds_ring(engine);
>  }
>  
> +static void reset_common_ring(struct intel_engine_cs *engine,
> +			      struct drm_i915_gem_request *request)
> +{
> +	struct drm_i915_private *dev_priv = engine->i915;
> +	struct execlist_port *port = engine->execlist_port;
> +	struct intel_context *ce = &request->ctx->engine[engine->id];
> +
> +	/* Move the RING_HEAD onto the breadcrumb, past the hanging batch */
> +	ce->lrc_reg_state[CTX_RING_HEAD+1] = request->postfix;
> +	request->ring->head = request->postfix;
> +	request->ring->last_retired_head = -1;
> +	intel_ring_update_space(request->ring);
> +
> +	if (i915.enable_guc_submission)
> +		return;
> +
> +	/* Catch up with any missed context-switch interrupts */
> +	I915_WRITE(RING_CONTEXT_STATUS_PTR(engine), _MASKED_FIELD(0xffff, 0));
> +	if (request->ctx != port[0].request->ctx) {
> +		i915_gem_request_put(port[0].request);
> +		port[0] = port[1];
> +		memset(&port[1], 0, sizeof(port[1]));
> +	}
> +
> +	/* CS is stopped, and we will resubmit both ports on resume */
> +	GEM_BUG_ON(request->ctx != port[0].request->ctx);
> +	port[0].count = 0;
> +	port[1].count = 0;
> +}
> +
>  static int intel_logical_ring_emit_pdps(struct drm_i915_gem_request *req)
>  {
>  	struct i915_hw_ppgtt *ppgtt = req->ctx->ppgtt;
> @@ -1635,6 +1673,7 @@ logical_ring_default_vfuncs(struct intel_engine_cs *engine)
>  {
>  	/* Default vfuncs which can be overriden by each engine. */
>  	engine->init_hw = gen8_init_common_ring;
> +	engine->reset_hw = reset_common_ring;
>  	engine->emit_flush = gen8_emit_flush;
>  	engine->emit_request = gen8_emit_request;
>  	engine->submit_request = execlists_submit_request;
> @@ -2087,9 +2126,9 @@ error_deref_obj:
>  	return ret;
>  }
>  
> -void intel_lr_context_reset(struct drm_i915_private *dev_priv,
> -			    struct i915_gem_context *ctx)
> +void intel_lr_context_resume(struct drm_i915_private *dev_priv)
>  {
> +	struct i915_gem_context *ctx = dev_priv->kernel_context;
>  	struct intel_engine_cs *engine;
>  
>  	for_each_engine(engine, dev_priv) {
> diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h
> index 4d70346500c2..4fed8165f98a 100644
> --- a/drivers/gpu/drm/i915/intel_lrc.h
> +++ b/drivers/gpu/drm/i915/intel_lrc.h
> @@ -87,8 +87,7 @@ void intel_lr_context_unpin(struct i915_gem_context *ctx,
>  
>  struct drm_i915_private;
>  
> -void intel_lr_context_reset(struct drm_i915_private *dev_priv,
> -			    struct i915_gem_context *ctx);
> +void intel_lr_context_resume(struct drm_i915_private *dev_priv);
>  uint64_t intel_lr_context_descriptor(struct i915_gem_context *ctx,
>  				     struct intel_engine_cs *engine);
>  
> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
> index e04b58a8aa0a..7f38a3e4239d 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.c
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
> @@ -564,6 +564,8 @@ static int init_ring_common(struct intel_engine_cs *engine)
>  	else
>  		ring_setup_phys_status_page(engine);
>  
> +	intel_engine_reset_irq(engine);
> +
>  	/* Enforce ordering by reading HEAD register back */
>  	I915_READ_HEAD(engine);
>  
> @@ -577,34 +579,33 @@ static int init_ring_common(struct intel_engine_cs *engine)
>  	if (I915_READ_HEAD(engine))
>  		DRM_DEBUG("%s initialization failed [head=%08x], fudging\n",
>  			  engine->name, I915_READ_HEAD(engine));
> -	I915_WRITE_HEAD(engine, 0);
> -	(void)I915_READ_HEAD(engine);
> +
> +	intel_ring_update_space(ring);
> +	I915_WRITE_HEAD(engine, ring->head);
> +	I915_WRITE_TAIL(engine, ring->tail);
> +	(void)I915_READ_TAIL(engine);
>  
>  	I915_WRITE_CTL(engine,
>  			((ring->size - PAGE_SIZE) & RING_NR_PAGES)
>  			| RING_VALID);
>  
>  	/* If the head is still not zero, the ring is dead */
> -	if (wait_for((I915_READ_CTL(engine) & RING_VALID) != 0 &&
> -		     I915_READ_START(engine) == i915_ggtt_offset(ring->vma) &&
> -		     (I915_READ_HEAD(engine) & HEAD_ADDR) == 0, 50)) {
> +	if (intel_wait_for_register_fw(dev_priv, RING_CTL(engine->mmio_base),
> +				       RING_VALID, RING_VALID,
> +				       50)) {
>  		DRM_ERROR("%s initialization failed "
> -			  "ctl %08x (valid? %d) head %08x tail %08x start %08x [expected %08x]\n",
> +			  "ctl %08x (valid? %d) head %08x [%08x] tail %08x [%08x] start %08x [expected %08x]\n",
>  			  engine->name,
>  			  I915_READ_CTL(engine),
>  			  I915_READ_CTL(engine) & RING_VALID,
> -			  I915_READ_HEAD(engine), I915_READ_TAIL(engine),
> +			  I915_READ_HEAD(engine), ring->head,
> +			  I915_READ_TAIL(engine), ring->tail,
>  			  I915_READ_START(engine),
>  			  i915_ggtt_offset(ring->vma));
>  		ret = -EIO;
>  		goto out;
>  	}
>  
> -	ring->last_retired_head = -1;
> -	ring->head = I915_READ_HEAD(engine);
> -	ring->tail = I915_READ_TAIL(engine) & TAIL_ADDR;
> -	intel_ring_update_space(ring);
> -
>  	intel_engine_init_hangcheck(engine);
>  
>  out:
> @@ -613,6 +614,15 @@ out:
>  	return ret;
>  }
>  
> +static void reset_ring_common(struct intel_engine_cs *engine,
> +			      struct drm_i915_gem_request *request)
> +{
> +	struct intel_ring *ring = request->ring;
> +
> +	ring->head = request->postfix;
> +	ring->last_retired_head = -1;
> +}
> +
>  static int intel_ring_workarounds_emit(struct drm_i915_gem_request *req)
>  {
>  	struct intel_ring *ring = req->ring;
> @@ -2007,7 +2017,6 @@ intel_engine_create_ring(struct intel_engine_cs *engine, int size)
>  	}
>  	ring->vma = vma;
>  
> -	list_add(&ring->link, &engine->buffers);
>  	return ring;
>  }
>  
> @@ -2015,7 +2024,6 @@ void
>  intel_ring_free(struct intel_ring *ring)
>  {
>  	i915_vma_put(ring->vma);
> -	list_del(&ring->link);
>  	kfree(ring);
>  }
>  
> @@ -2169,6 +2177,16 @@ void intel_engine_cleanup(struct intel_engine_cs *engine)
>  	engine->i915 = NULL;
>  }
>  
> +void intel_legacy_submission_resume(struct drm_i915_private *dev_priv)
> +{
> +	struct intel_engine_cs *engine;
> +
> +	for_each_engine(engine, dev_priv) {
> +		engine->buffer->head = engine->buffer->tail;
> +		engine->buffer->last_retired_head = -1;
> +	}
> +}
> +
>  int intel_ring_alloc_request_extras(struct drm_i915_gem_request *request)
>  {
>  	int ret;
> @@ -2654,6 +2672,7 @@ static void intel_ring_default_vfuncs(struct drm_i915_private *dev_priv,
>  	intel_ring_init_semaphores(dev_priv, engine);
>  
>  	engine->init_hw = init_ring_common;
> +	engine->reset_hw = reset_ring_common;
>  
>  	engine->emit_request = i9xx_emit_request;
>  	if (i915.semaphores)
> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
> index 18848acf5e74..32f527447310 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.h
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
> @@ -87,7 +87,6 @@ struct intel_ring {
>  	void *vaddr;
>  
>  	struct intel_engine_cs *engine;
> -	struct list_head link;
>  
>  	struct list_head request_list;
>  
> @@ -157,7 +156,6 @@ struct intel_engine_cs {
>  	u32		mmio_base;
>  	unsigned int irq_shift;
>  	struct intel_ring *buffer;
> -	struct list_head buffers;
>  
>  	/* Rather than have every client wait upon all user interrupts,
>  	 * with the herd waking after every interrupt and each doing the
> @@ -211,6 +209,8 @@ struct intel_engine_cs {
>  	void		(*irq_disable)(struct intel_engine_cs *engine);
>  
>  	int		(*init_hw)(struct intel_engine_cs *engine);
> +	void		(*reset_hw)(struct intel_engine_cs *engine,
> +				    struct drm_i915_gem_request *req);
>  
>  	int		(*init_context)(struct drm_i915_gem_request *req);
>  
> @@ -444,6 +444,8 @@ void intel_ring_free(struct intel_ring *ring);
>  void intel_engine_stop(struct intel_engine_cs *engine);
>  void intel_engine_cleanup(struct intel_engine_cs *engine);
>  
> +void intel_legacy_submission_resume(struct drm_i915_private *dev_priv);
> +
>  int intel_ring_alloc_request_extras(struct drm_i915_gem_request *request);
>  
>  int __must_check intel_ring_begin(struct drm_i915_gem_request *req, int n);
> @@ -482,6 +484,7 @@ int __intel_ring_space(int head, int tail, int size);
>  void intel_ring_update_space(struct intel_ring *ring);
>  
>  void intel_engine_init_seqno(struct intel_engine_cs *engine, u32 seqno);
> +void intel_engine_reset_irq(struct intel_engine_cs *engine);
>  
>  void intel_engine_setup_common(struct intel_engine_cs *engine);
>  int intel_engine_init_common(struct intel_engine_cs *engine);
> -- 
> 2.9.3


More information about the Intel-gfx mailing list