diff options
Diffstat (limited to 'drivers/gpu/drm/i915/i915_irq.c')
-rw-r--r-- | drivers/gpu/drm/i915/i915_irq.c | 38 |
1 files changed, 38 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 8e9f4378b5a7..f25e73fe567c 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2715,6 +2715,8 @@ void i915_handle_error(struct drm_i915_private *dev_priv, u32 engine_mask, const char *fmt, ...) { + struct intel_engine_cs *engine; + unsigned int tmp; va_list args; char error_msg[80]; @@ -2734,9 +2736,31 @@ void i915_handle_error(struct drm_i915_private *dev_priv, i915_capture_error_state(dev_priv, engine_mask, error_msg); i915_clear_error_registers(dev_priv); + /* + * Try engine reset when available. We fall back to full reset if + * single reset fails. + */ + if (intel_has_reset_engine(dev_priv)) { + for_each_engine_masked(engine, dev_priv, engine_mask, tmp) { + BUILD_BUG_ON(I915_RESET_HANDOFF >= I915_RESET_ENGINE); + if (test_and_set_bit(I915_RESET_ENGINE + engine->id, + &dev_priv->gpu_error.flags)) + continue; + + if (i915_reset_engine(engine) == 0) + engine_mask &= ~intel_engine_flag(engine); + + clear_bit(I915_RESET_ENGINE + engine->id, + &dev_priv->gpu_error.flags); + wake_up_bit(&dev_priv->gpu_error.flags, + I915_RESET_ENGINE + engine->id); + } + } + if (!engine_mask) goto out; + /* Full reset needs the mutex, stop any other user trying to do so. */ if (test_and_set_bit(I915_RESET_BACKOFF, &dev_priv->gpu_error.flags)) { wait_event(dev_priv->gpu_error.reset_queue, !test_bit(I915_RESET_BACKOFF, @@ -2744,8 +2768,22 @@ void i915_handle_error(struct drm_i915_private *dev_priv, goto out; } + /* Prevent any other reset-engine attempt. */ + for_each_engine(engine, dev_priv, tmp) { + while (test_and_set_bit(I915_RESET_ENGINE + engine->id, + &dev_priv->gpu_error.flags)) + wait_on_bit(&dev_priv->gpu_error.flags, + I915_RESET_ENGINE + engine->id, + TASK_UNINTERRUPTIBLE); + } + i915_reset_device(dev_priv); + for_each_engine(engine, dev_priv, tmp) { + clear_bit(I915_RESET_ENGINE + engine->id, + &dev_priv->gpu_error.flags); + } + clear_bit(I915_RESET_BACKOFF, &dev_priv->gpu_error.flags); wake_up_all(&dev_priv->gpu_error.reset_queue); |