@@ -1027,10 +1027,60 @@ error:
*/
int i915_reset_engine(struct intel_engine_cs *engine)
{
+ struct drm_device *dev = engine->i915->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_engine_cs_state state;
int ret;
- /* FIXME: replace me with engine reset sequence */
- ret = -ENODEV;
+ WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+
+ i915_gem_reset_engine_status(dev_priv, engine);
+
+ /*Take wake lock to prevent power saving mode */
+ intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
+
+ ret = intel_request_for_reset(engine);
+ if (ret) {
+ DRM_ERROR("Failed to disable %s\n", engine->name);
+ goto out;
+ }
+
+ ret = engine->save(engine, &state);
+ if (ret)
+ goto enable_engine;
+
+ ret = intel_gpu_reset(dev_priv, intel_engine_flag(engine));
+ if (ret) {
+ DRM_ERROR("Failed to reset %s, ret=%d\n", engine->name, ret);
+ goto enable_engine;
+ }
+
+ ret = engine->init_hw(engine);
+ if (ret)
+ goto out;
+
+ /*
+ * Restart the engine after reset.
+ * Engine state is first restored and the context is resubmitted.
+ */
+ engine->start(engine, &state);
+
+enable_engine:
+ /*
+ * we only need to enable engine if we cannot either save engine state
+ * or reset fails. If the reset is successful, engine gets enabled
+ * automatically so we can skip this step.
+ */
+ if (ret)
+ intel_clear_reset_request(engine);
+
+out:
+ if (state.req)
+ i915_gem_request_unreference(state.req);
+
+ /* Wake up anything waiting on this engine's queue */
+ wake_up_all(&engine->irq_queue);
+ intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
return ret;
}
@@ -2910,6 +2910,8 @@ extern int intel_gpu_reset(struct drm_i915_private *dev_priv, u32 engine_mask);
extern bool intel_has_gpu_reset(struct drm_i915_private *dev_priv);
extern int i915_reset(struct drm_i915_private *dev_priv);
extern bool intel_has_engine_reset(struct drm_i915_private *dev_priv);
+extern int intel_request_for_reset(struct intel_engine_cs *engine);
+extern int intel_clear_reset_request(struct intel_engine_cs *engine);
extern int i915_reset_engine(struct intel_engine_cs *engine);
extern int intel_guc_reset(struct drm_i915_private *dev_priv);
extern void intel_engine_init_hangcheck(struct intel_engine_cs *engine);
@@ -3331,6 +3333,8 @@ static inline bool i915_stop_ring_allow_warn(struct drm_i915_private *dev_priv)
}
void i915_gem_reset(struct drm_device *dev);
+void i915_gem_reset_engine_status(struct drm_i915_private *dev_priv,
+ struct intel_engine_cs *ring);
bool i915_gem_clflush_object(struct drm_i915_gem_object *obj, bool force);
int __must_check i915_gem_init(struct drm_device *dev);
int i915_gem_init_engines(struct drm_device *dev);
@@ -3082,8 +3082,8 @@ i915_gem_find_active_request(struct intel_engine_cs *engine)
return NULL;
}
-static void i915_gem_reset_engine_status(struct drm_i915_private *dev_priv,
- struct intel_engine_cs *engine)
+void i915_gem_reset_engine_status(struct drm_i915_private *dev_priv,
+ struct intel_engine_cs *engine)
{
struct drm_i915_gem_request *request;
bool ring_hung;
@@ -1734,6 +1734,39 @@ int intel_guc_reset(struct drm_i915_private *dev_priv)
return ret;
}
+/*
+ * On gen8+ a reset request has to be issued via the reset control register
+ * before a GPU engine can be reset in order to stop the command streamer
+ * and idle the engine. This replaces the legacy way of stopping an engine
+ * by writing to the stop ring bit in the MI_MODE register.
+ */
+int intel_request_for_reset(struct intel_engine_cs *engine)
+{
+ if (!intel_has_engine_reset(engine->i915)) {
+ DRM_ERROR("Engine Reset not supported on Gen%d\n",
+ INTEL_INFO(engine->i915)->gen);
+ return -EINVAL;
+ }
+
+ return gen8_request_engine_reset(engine);
+}
+
+/*
+ * It is possible to back off from a previously issued reset request by simply
+ * clearing the reset request bit in the reset control register.
+ */
+int intel_clear_reset_request(struct intel_engine_cs *engine)
+{
+ if (!intel_has_engine_reset(engine->i915)) {
+ DRM_ERROR("Request to clear reset not supported on Gen%d\n",
+ INTEL_INFO(engine->i915)->gen);
+ return -EINVAL;
+ }
+
+ gen8_unrequest_engine_reset(engine);
+ return 0;
+}
+
bool intel_uncore_unclaimed_mmio(struct drm_i915_private *dev_priv)
{
return check_for_unclaimed_mmio(dev_priv);