Commit fb6f0b64 authored by Chris Wilson's avatar Chris Wilson

drm/i915: Prevent machine hang from Broxton's vtd w/a and error capture

Since capturing the error state requires fiddling around with the GGTT
to read arbitrary buffers and is itself run under stop_machine(), it
deadlocks the machine (effectively a hard hang) when run in conjunction
with Broxton's VTd workaround to serialize GGTT access.

v2: Store the ERR_PTR in first_error so that the error can be reported
to the user via sysfs.
v3: Mention the quirk in dmesg (using info as per usual)

Fixes: 0ef34ad6 ("drm/i915: Serialize GTT/Aperture accesses on BXT")
Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Cc: Jon Bloomfield <jon.bloomfield@intel.com>
Cc: John Harrison <john.C.Harrison@intel.com>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Cc: Daniel Vetter <daniel.vetter@ffwll.ch>
Reviewed-by: default avatarJoonas Lahtinen <joonas.lahtinen@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20181102161232.17742-5-chris@chris-wilson.co.uk
parent 31579ba2
...@@ -3360,6 +3360,11 @@ static int gen8_gmch_probe(struct i915_ggtt *ggtt) ...@@ -3360,6 +3360,11 @@ static int gen8_gmch_probe(struct i915_ggtt *ggtt)
ggtt->vm.insert_page = bxt_vtd_ggtt_insert_page__BKL; ggtt->vm.insert_page = bxt_vtd_ggtt_insert_page__BKL;
if (ggtt->vm.clear_range != nop_clear_range) if (ggtt->vm.clear_range != nop_clear_range)
ggtt->vm.clear_range = bxt_vtd_ggtt_clear_range__BKL; ggtt->vm.clear_range = bxt_vtd_ggtt_clear_range__BKL;
/* Prevent recursively calling stop_machine() and deadlocks. */
dev_info(dev_priv->drm.dev,
"Disabling error capture for VT-d workaround\n");
i915_disable_error_state(dev_priv, -ENODEV);
} }
ggtt->invalidate = gen6_ggtt_invalidate; ggtt->invalidate = gen6_ggtt_invalidate;
......
...@@ -648,6 +648,9 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m, ...@@ -648,6 +648,9 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
return 0; return 0;
} }
if (IS_ERR(error))
return PTR_ERR(error);
if (*error->error_msg) if (*error->error_msg)
err_printf(m, "%s\n", error->error_msg); err_printf(m, "%s\n", error->error_msg);
err_printf(m, "Kernel: " UTS_RELEASE "\n"); err_printf(m, "Kernel: " UTS_RELEASE "\n");
...@@ -1867,6 +1870,7 @@ void i915_capture_error_state(struct drm_i915_private *i915, ...@@ -1867,6 +1870,7 @@ void i915_capture_error_state(struct drm_i915_private *i915,
error = i915_capture_gpu_state(i915); error = i915_capture_gpu_state(i915);
if (!error) { if (!error) {
DRM_DEBUG_DRIVER("out of memory, not capturing error state\n"); DRM_DEBUG_DRIVER("out of memory, not capturing error state\n");
i915_disable_error_state(i915, -ENOMEM);
return; return;
} }
...@@ -1922,5 +1926,14 @@ void i915_reset_error_state(struct drm_i915_private *i915) ...@@ -1922,5 +1926,14 @@ void i915_reset_error_state(struct drm_i915_private *i915)
i915->gpu_error.first_error = NULL; i915->gpu_error.first_error = NULL;
spin_unlock_irq(&i915->gpu_error.lock); spin_unlock_irq(&i915->gpu_error.lock);
i915_gpu_state_put(error); if (!IS_ERR(error))
i915_gpu_state_put(error);
}
void i915_disable_error_state(struct drm_i915_private *i915, int err)
{
spin_lock_irq(&i915->gpu_error.lock);
if (!i915->gpu_error.first_error)
i915->gpu_error.first_error = ERR_PTR(err);
spin_unlock_irq(&i915->gpu_error.lock);
} }
...@@ -343,6 +343,7 @@ static inline void i915_gpu_state_put(struct i915_gpu_state *gpu) ...@@ -343,6 +343,7 @@ static inline void i915_gpu_state_put(struct i915_gpu_state *gpu)
struct i915_gpu_state *i915_first_error_state(struct drm_i915_private *i915); struct i915_gpu_state *i915_first_error_state(struct drm_i915_private *i915);
void i915_reset_error_state(struct drm_i915_private *i915); void i915_reset_error_state(struct drm_i915_private *i915);
void i915_disable_error_state(struct drm_i915_private *i915, int err);
#else #else
...@@ -355,13 +356,18 @@ static inline void i915_capture_error_state(struct drm_i915_private *dev_priv, ...@@ -355,13 +356,18 @@ static inline void i915_capture_error_state(struct drm_i915_private *dev_priv,
static inline struct i915_gpu_state * static inline struct i915_gpu_state *
i915_first_error_state(struct drm_i915_private *i915) i915_first_error_state(struct drm_i915_private *i915)
{ {
return NULL; return ERR_PTR(-ENODEV);
} }
static inline void i915_reset_error_state(struct drm_i915_private *i915) static inline void i915_reset_error_state(struct drm_i915_private *i915)
{ {
} }
static inline void i915_disable_error_state(struct drm_i915_private *i915,
int err)
{
}
#endif /* IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR) */ #endif /* IS_ENABLED(CONFIG_DRM_I915_CAPTURE_ERROR) */
#endif /* _I915_GPU_ERROR_H_ */ #endif /* _I915_GPU_ERROR_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment