[Intel-gfx] [PATCH v2 11/22] drm/i915: Perform a direct reset of the GPU from the waiter
Mika Kuoppala
mika.kuoppala at linux.intel.com
Thu Sep 8 09:35:24 UTC 2016
Chris Wilson <chris at chris-wilson.co.uk> writes:
> If a waiter is holding the struct_mutex, then the reset worker cannot
> reset the GPU until the waiter returns. We do not want to return -EAGAIN
> form i915_wait_request as that breaks delicate operations like
> i915_vma_unbind() which often cannot be restarted easily, and returning
> -EIO is just as useless (and has in the past proven dangerous). The
> remaining WARN_ON(i915_wait_request) serve as a valuable reminder that
> handling errors from an indefinite wait are tricky.
>
> We can keep the current semantic that knowing after a reset is complete,
> so is the request, by performing the reset ourselves if we hold the
> mutex.
>
> uevent emission is still handled by the reset worker, so it may appear
> slightly out of order with respect to the actual reset (and concurrent
> use of the device).
>
> Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
> ---
> drivers/gpu/drm/i915/i915_drv.c | 11 ++++++-----
> drivers/gpu/drm/i915/i915_drv.h | 15 +++------------
> drivers/gpu/drm/i915/i915_gem_request.c | 29 +++++++++++++++++++++++++++++
> drivers/gpu/drm/i915/i915_irq.c | 2 ++
> drivers/gpu/drm/i915/intel_ringbuffer.c | 3 ---
> 5 files changed, 40 insertions(+), 20 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
> index 47a676d859db..ff4173e6e298 100644
> --- a/drivers/gpu/drm/i915/i915_drv.c
> +++ b/drivers/gpu/drm/i915/i915_drv.c
> @@ -1729,6 +1729,8 @@ int i915_resume_switcheroo(struct drm_device *dev)
> * Reset the chip. Useful if a hang is detected. Returns zero on successful
> * reset or otherwise an error code.
> *
> + * Caller must hold the struct_mutex.
> + *
> * Procedure is fairly simple:
> * - reset the chip using the reset reg
> * - re-init context state
> @@ -1743,7 +1745,10 @@ int i915_reset(struct drm_i915_private *dev_priv)
> struct i915_gpu_error *error = &dev_priv->gpu_error;
> int ret;
>
> - mutex_lock(&dev->struct_mutex);
> + lockdep_assert_held(&dev->struct_mutex);
> +
> + if (!test_and_clear_bit(I915_RESET_IN_PROGRESS, &error->flags))
> + return test_bit(I915_WEDGED, &error->flags) ? -EIO : 0;
>
> /* Clear any previous failed attempts at recovery. Time to try again. */
> __clear_bit(I915_WEDGED, &error->flags);
> @@ -1784,9 +1789,6 @@ int i915_reset(struct drm_i915_private *dev_priv)
> goto error;
> }
>
> - clear_bit(I915_RESET_IN_PROGRESS, &error->flags);
> - mutex_unlock(&dev->struct_mutex);
> -
> /*
> * rps/rc6 re-init is necessary to restore state lost after the
> * reset and the re-install of gt irqs. Skip for ironlake per
> @@ -1800,7 +1802,6 @@ int i915_reset(struct drm_i915_private *dev_priv)
>
> error:
> set_bit(I915_WEDGED, &error->flags);
> - mutex_unlock(&dev->struct_mutex);
> return ret;
> }
>
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index dd73c00cd774..2e2fd8a77233 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -3862,7 +3862,9 @@ wait_remaining_ms_from_jiffies(unsigned long timestamp_jiffies, int to_wait_ms)
> schedule_timeout_uninterruptible(remaining_jiffies);
> }
> }
> -static inline bool __i915_request_irq_complete(struct drm_i915_gem_request *req)
> +
> +static inline bool
> +__i915_request_irq_complete(struct drm_i915_gem_request *req)
> {
> struct intel_engine_cs *engine = req->engine;
>
> @@ -3924,17 +3926,6 @@ static inline bool __i915_request_irq_complete(struct drm_i915_gem_request *req)
> return true;
> }
>
> - /* We need to check whether any gpu reset happened in between
> - * the request being submitted and now. If a reset has occurred,
> - * the seqno will have been advance past ours and our request
> - * is complete. If we are in the process of handling a reset,
> - * the request is effectively complete as the rendering will
> - * be discarded, but we need to return in order to drop the
> - * struct_mutex.
> - */
> - if (i915_reset_in_progress(&req->i915->gpu_error))
> - return true;
> -
> return false;
> }
>
> diff --git a/drivers/gpu/drm/i915/i915_gem_request.c b/drivers/gpu/drm/i915/i915_gem_request.c
> index 5f89801e6a16..64c370681a81 100644
> --- a/drivers/gpu/drm/i915/i915_gem_request.c
> +++ b/drivers/gpu/drm/i915/i915_gem_request.c
> @@ -533,6 +533,16 @@ void __i915_add_request(struct drm_i915_gem_request *request, bool flush_caches)
> engine->submit_request(request);
> }
>
> +static void reset_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
> +{
> + unsigned long flags;
> +
> + spin_lock_irqsave(&q->lock, flags);
> + if (list_empty(&wait->task_list))
> + __add_wait_queue(q, wait);
> + spin_unlock_irqrestore(&q->lock, flags);
> +}
> +
> static unsigned long local_clock_us(unsigned int *cpu)
> {
> unsigned long t;
> @@ -710,6 +720,25 @@ wakeup:
> if (__i915_request_irq_complete(req))
> break;
>
> + /* If the GPU is hung, and we hold the lock, reset the GPU
> + * and then check for completion. On a full reset, the engine's
> + * HW seqno will be advanced passed us and we are complete.
> + * If we do a partial reset, we have to wait for the GPU to
> + * resume and update the breadcrumb.
> + *
> + * If we don't hold the mutex, we can just wait for the worker
> + * to come along and update the breadcrumb (either directly
> + * itself, or indirectly by recovering the GPU).
> + */
> + if (flags & I915_WAIT_LOCKED &&
> + i915_reset_in_progress(&req->i915->gpu_error)) {
> + __set_current_state(TASK_RUNNING);
> + i915_reset(req->i915);
> + reset_wait_queue(&req->i915->gpu_error.wait_queue,
> + &reset);
Comment here might be warranted that we are here due to reset wakeup,
which did clear the wait queue. Or perhap rename to
readd_to_reset_wait_queue.
Reviewed-by: Mika Kuoppala <mika.kuoppala at intel.com>
> + continue;
> + }
> +
> /* Only spin if we know the GPU is processing this request */
> if (i915_spin_request(req, state, 2))
> break;
> diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
> index ed172d7beecb..2c7cb5041511 100644
> --- a/drivers/gpu/drm/i915/i915_irq.c
> +++ b/drivers/gpu/drm/i915/i915_irq.c
> @@ -2521,7 +2521,9 @@ static void i915_reset_and_wakeup(struct drm_i915_private *dev_priv)
> * pending state and not properly drop locks, resulting in
> * deadlocks with the reset work.
> */
> + mutex_lock(&dev_priv->drm.struct_mutex);
> ret = i915_reset(dev_priv);
> + mutex_unlock(&dev_priv->drm.struct_mutex);
>
> intel_finish_reset(dev_priv);
>
> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
> index eae261e62b8b..e04b58a8aa0a 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.c
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
> @@ -2229,9 +2229,6 @@ static int wait_for_space(struct drm_i915_gem_request *req, int bytes)
> if (ret)
> return ret;
>
> - if (i915_reset_in_progress(&target->i915->gpu_error))
> - return -EAGAIN;
> -
> i915_gem_request_retire_upto(target);
>
> intel_ring_update_space(ring);
> --
> 2.9.3
More information about the Intel-gfx
mailing list