drm/i915: Improve irq handling after gpu resets
[deliverable/linux.git] / drivers / gpu / drm / i915 / i915_drv.c
index 009d677a2385ca11a49a294c4fe647ab25f82ff8..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,18 +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);
-               for_each_crtc(dev, crtc)
+               drm_modeset_lock_all(dev);
+               for_each_crtc(dev, crtc) {
                        dev_priv->display.crtc_disable(crtc);
-               mutex_unlock(&dev->mode_config.mutex);
+               }
+               drm_modeset_unlock_all(dev);
 
                intel_modeset_suspend_hw(dev);
        }
@@ -597,24 +600,6 @@ void intel_console_resume(struct work_struct *work)
        console_unlock();
 }
 
-static void intel_resume_hotplug(struct drm_device *dev)
-{
-       struct drm_mode_config *mode_config = &dev->mode_config;
-       struct intel_encoder *encoder;
-
-       mutex_lock(&mode_config->mutex);
-       DRM_DEBUG_KMS("running encoder hotplug functions\n");
-
-       list_for_each_entry(encoder, &mode_config->encoder_list, base.head)
-               if (encoder->hot_plug)
-                       encoder->hot_plug(encoder);
-
-       mutex_unlock(&mode_config->mutex);
-
-       /* Just fire off a uevent and let userspace tell us what to do */
-       drm_helper_hpd_irq_event(dev);
-}
-
 static int i915_drm_thaw_early(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -670,7 +655,7 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings)
                intel_hpd_init(dev);
                dev_priv->enable_hotplug_processing = true;
                /* Config may have changed between suspend and resume */
-               intel_resume_hotplug(dev);
+               drm_helper_hpd_irq_event(dev);
        }
 
        intel_opregion_init(dev);
@@ -826,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);
 
@@ -1370,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
@@ -1396,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.02616 seconds and 5 git commands to generate.