|
@@ -2715,6 +2715,8 @@ void i915_handle_error(struct drm_i915_private *dev_priv,
|
|
u32 engine_mask,
|
|
u32 engine_mask,
|
|
const char *fmt, ...)
|
|
const char *fmt, ...)
|
|
{
|
|
{
|
|
|
|
+ struct intel_engine_cs *engine;
|
|
|
|
+ unsigned int tmp;
|
|
va_list args;
|
|
va_list args;
|
|
char error_msg[80];
|
|
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_capture_error_state(dev_priv, engine_mask, error_msg);
|
|
i915_clear_error_registers(dev_priv);
|
|
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)
|
|
if (!engine_mask)
|
|
goto out;
|
|
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)) {
|
|
if (test_and_set_bit(I915_RESET_BACKOFF, &dev_priv->gpu_error.flags)) {
|
|
wait_event(dev_priv->gpu_error.reset_queue,
|
|
wait_event(dev_priv->gpu_error.reset_queue,
|
|
!test_bit(I915_RESET_BACKOFF,
|
|
!test_bit(I915_RESET_BACKOFF,
|
|
@@ -2744,8 +2768,22 @@ void i915_handle_error(struct drm_i915_private *dev_priv,
|
|
goto out;
|
|
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);
|
|
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);
|
|
clear_bit(I915_RESET_BACKOFF, &dev_priv->gpu_error.flags);
|
|
wake_up_all(&dev_priv->gpu_error.reset_queue);
|
|
wake_up_all(&dev_priv->gpu_error.reset_queue);
|
|
|
|
|