#include <linux/console.h>
#include <linux/module.h>
+#include <linux/pm_runtime.h>
#include <drm/drm_crtc_helper.h>
static struct drm_driver driver;
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);
}
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;
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);
}
/*
- * 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);
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
return ret;
}
- i915_gem_release_all_mmaps(dev_priv);
-
del_timer_sync(&dev_priv->gpu_error.hangcheck_timer);
dev_priv->pm.suspended = true;