drm/i915/hsw: Fix GPU hang during resume from S3-devices state
authorImre Deak <imre.deak@intel.com>
Wed, 12 Oct 2016 14:46:37 +0000 (17:46 +0300)
committerImre Deak <imre.deak@intel.com>
Thu, 13 Oct 2016 09:11:31 +0000 (12:11 +0300)
Currently resuming on HSW from S3 pm_test/devices state leads to an
unrecoverable GPU hang. Resetting the GPU during suspend fixes this. For
a full S3 cycle this change only means the reset happens earlier (before
reaching S3). For S4 the reset will happen now both during the freeze
and quiesce phases, which is a benefit since it will guarantee that the
GPU is idle before creating and loading the hibernation image.

Cc: Mika Kuoppala <mika.kuoppala@intel.com>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Suggested-by: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Imre Deak <imre.deak@intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: http://patchwork.freedesktop.org/patch/msgid/1476283597-580-1-git-send-email-imre.deak@intel.com
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_gem.c

index 89d322215c8431011beeb2b863bc6cc9f4e97a2a..e9b3bfcb347a0fd1d66072de0d7453c500f6768e 100644 (file)
@@ -532,32 +532,6 @@ static const struct vga_switcheroo_client_ops i915_switcheroo_ops = {
 
 static void i915_gem_fini(struct drm_device *dev)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-
-       /*
-        * Neither the BIOS, ourselves or any other kernel
-        * expects the system to be in execlists mode on startup,
-        * so we need to reset the GPU back to legacy mode. And the only
-        * known way to disable logical contexts is through a GPU reset.
-        *
-        * So in order to leave the system in a known default configuration,
-        * always reset the GPU upon unload. Afterwards we then clean up the
-        * GEM state tracking, flushing off the requests and leaving the
-        * system in a known idle state.
-        *
-        * Note that is of the upmost importance that the GPU is idle and
-        * all stray writes are flushed *before* we dismantle the backing
-        * storage for the pinned objects.
-        *
-        * However, since we are uncertain that reseting the GPU on older
-        * machines is a good idea, we don't - just in case it leaves the
-        * machine in an unusable condition.
-        */
-       if (HAS_HW_CONTEXTS(dev)) {
-               int reset = intel_gpu_reset(dev_priv, ALL_ENGINES);
-               WARN_ON(reset && reset != -ENODEV);
-       }
-
        mutex_lock(&dev->struct_mutex);
        i915_gem_cleanup_engines(dev);
        i915_gem_context_fini(dev);
@@ -636,6 +610,8 @@ static int i915_load_modeset_init(struct drm_device *dev)
        return 0;
 
 cleanup_gem:
+       if (i915_gem_suspend(dev))
+               DRM_ERROR("failed to idle hardware; continuing to unload!\n");
        i915_gem_fini(dev);
 cleanup_irq:
        intel_guc_fini(dev);
index fdd496e6c081ca2d8bda6632e427f5cbdf861b66..830df36ca14cea69f25f3f8789c0dd586ee95fbf 100644 (file)
@@ -4273,6 +4273,30 @@ int i915_gem_suspend(struct drm_device *dev)
         */
        WARN_ON(dev_priv->gt.awake);
 
+       /*
+        * Neither the BIOS, ourselves or any other kernel
+        * expects the system to be in execlists mode on startup,
+        * so we need to reset the GPU back to legacy mode. And the only
+        * known way to disable logical contexts is through a GPU reset.
+        *
+        * So in order to leave the system in a known default configuration,
+        * always reset the GPU upon unload and suspend. Afterwards we then
+        * clean up the GEM state tracking, flushing off the requests and
+        * leaving the system in a known idle state.
+        *
+        * Note that is of the upmost importance that the GPU is idle and
+        * all stray writes are flushed *before* we dismantle the backing
+        * storage for the pinned objects.
+        *
+        * However, since we are uncertain that resetting the GPU on older
+        * machines is a good idea, we don't - just in case it leaves the
+        * machine in an unusable condition.
+        */
+       if (HAS_HW_CONTEXTS(dev)) {
+               int reset = intel_gpu_reset(dev_priv, ALL_ENGINES);
+               WARN_ON(reset && reset != -ENODEV);
+       }
+
        return 0;
 
 err: