drm/i915: Improve irq handling after gpu resets
[deliverable/linux.git] / drivers / gpu / drm / i915 / i915_drv.c
index c83c83b74bf4471c19070bde3488549b577e2330..481d2a14cdc697de5ac79e3f850994a920d78025 100644 (file)
@@ -36,6 +36,7 @@
 
 #include <linux/console.h>
 #include <linux/module.h>
+#include <linux/pm_runtime.h>
 #include <drm/drm_crtc_helper.h>
 
 static struct drm_driver driver;
@@ -523,21 +524,20 @@ static int i915_drm_freeze(struct drm_device *dev)
                        return error;
                }
 
-               cancel_delayed_work_sync(&dev_priv->rps.delayed_resume_work);
-
                drm_irq_uninstall(dev);
                dev_priv->enable_hotplug_processing = false;
+
+               intel_disable_gt_powersave(dev);
+
                /*
                 * Disable CRTCs directly since we want to preserve sw state
                 * for _thaw.
                 */
-               mutex_lock(&dev->mode_config.mutex);
+               drm_modeset_lock_all(dev);
                for_each_crtc(dev, crtc) {
-                       mutex_lock(&crtc->mutex);
                        dev_priv->display.crtc_disable(crtc);
-                       mutex_unlock(&crtc->mutex);
                }
-               mutex_unlock(&dev->mode_config.mutex);
+               drm_modeset_unlock_all(dev);
 
                intel_modeset_suspend_hw(dev);
        }
@@ -811,17 +811,17 @@ int i915_reset(struct drm_device *dev)
                }
 
                /*
-                * FIXME: This is horribly race against concurrent pageflip and
-                * vblank wait ioctls since they can observe dev->irqs_disabled
-                * being false when they shouldn't be able to.
+                * FIXME: This races pretty badly against concurrent holders of
+                * ring interrupts. This is possible since we've started to drop
+                * dev->struct_mutex in select places when waiting for the gpu.
                 */
-               drm_irq_uninstall(dev);
-               drm_irq_install(dev, dev->pdev->irq);
 
-               /* rps/rc6 re-init is necessary to restore state lost after the
-                * reset and the re-install of drm irq. Skip for ironlake per
+               /*
+                * rps/rc6 re-init is necessary to restore state lost after the
+                * reset and the re-install of gt irqs. Skip for ironlake per
                 * previous concerns that it doesn't respond well to some forms
-                * of re-init after reset. */
+                * of re-init after reset.
+                */
                if (INTEL_INFO(dev)->gen > 5)
                        intel_reset_gt_powersave(dev);
 
@@ -1355,6 +1355,30 @@ static int intel_runtime_suspend(struct device *device)
 
        DRM_DEBUG_KMS("Suspending device\n");
 
+       /*
+        * We could deadlock here in case another thread holding struct_mutex
+        * calls RPM suspend concurrently, since the RPM suspend will wait
+        * first for this RPM suspend to finish. In this case the concurrent
+        * RPM resume will be followed by its RPM suspend counterpart. Still
+        * for consistency return -EAGAIN, which will reschedule this suspend.
+        */
+       if (!mutex_trylock(&dev->struct_mutex)) {
+               DRM_DEBUG_KMS("device lock contention, deffering suspend\n");
+               /*
+                * Bump the expiration timestamp, otherwise the suspend won't
+                * be rescheduled.
+                */
+               pm_runtime_mark_last_busy(device);
+
+               return -EAGAIN;
+       }
+       /*
+        * We are safe here against re-faults, since the fault handler takes
+        * an RPM reference.
+        */
+       i915_gem_release_all_mmaps(dev_priv);
+       mutex_unlock(&dev->struct_mutex);
+
        /*
         * rps.work can't be rearmed here, since we get here only after making
         * sure the GPU is idle and the RPS freq is set to the minimum. See
@@ -1381,8 +1405,6 @@ static int intel_runtime_suspend(struct device *device)
                return ret;
        }
 
-       i915_gem_release_all_mmaps(dev_priv);
-
        del_timer_sync(&dev_priv->gpu_error.hangcheck_timer);
        dev_priv->pm.suspended = true;
 
This page took 0.050126 seconds and 5 git commands to generate.