[PATCH 05/17] drm/i915: Cancel outstanding modeset workers before suspend

Rodrigo Vivi
2013-08-26T22:51:30Z

From: Chris Wilson <chris@chris-wilson.co.uk>

Upon resume we will do a complete restoration of the mode and so reset
all tasks, but during suspend (and unload) we need to make sure that no
workers run concurrently with our suspend code. Or worse just after.

The issue was first raised whilst tackling a suspend issue with Takashi
Iwai (http://lists.freedesktop.org/archives/intel-gfx/2012-April/016738.html)
and then it was independently rediscovered by Chuanshen Lui.

v2: Rebase for the lost year.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Acked-by: Takashi Iwai <tiwai@suse.de>
Cc: "Liu, Chuansheng" <chuansheng.liu@intel.com>
---
drivers/gpu/drm/i915/i915_drv.h | 1 +
drivers/gpu/drm/i915/intel_display.c | 21 ++++++++++++++++-----
2 files changed, 17 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 8ee15b4..7ac5ca5 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2199,6 +2199,7 @@ extern void intel_modeset_init_hw(struct drm_device *dev);
extern void intel_modeset_suspend_hw(struct drm_device *dev);
extern void intel_modeset_init(struct drm_device *dev);
extern void intel_modeset_gem_init(struct drm_device *dev);
+extern void intel_modeset_quiesce(struct drm_device *dev);
extern void intel_modeset_cleanup(struct drm_device *dev);
extern int intel_modeset_vga_set_state(struct drm_device *dev, bool state);
extern void intel_modeset_setup_hw_state(struct drm_device *dev,
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index bcb62fe..74dbc68 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -10030,6 +10030,7 @@ void intel_modeset_init_hw(struct drm_device *dev)

void intel_modeset_suspend_hw(struct drm_device *dev)
{
+ intel_modeset_quiesce(dev);
intel_suspend_hw(dev);
}

@@ -10474,9 +10475,19 @@ void intel_modeset_gem_init(struct drm_device *dev)
intel_modeset_setup_hw_state(dev, false);
}

-void intel_modeset_cleanup(struct drm_device *dev)
+void intel_modeset_quiesce(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
+
+ cancel_work_sync(&dev_priv->hotplug_work);
+ cancel_work_sync(&dev_priv->rps.work);
+
+ /* catch all required for dev_priv->wq */
+ flush_scheduled_work();
+}
+
+void intel_modeset_cleanup(struct drm_device *dev)
+{
struct drm_crtc *crtc;

/*
@@ -10485,7 +10496,10 @@ void intel_modeset_cleanup(struct drm_device *dev)
* experience fancy races otherwise.
*/
drm_irq_uninstall(dev);
- cancel_work_sync(&dev_priv->hotplug_work);
+
+ /* flush any delayed tasks or pending work */
+ intel_modeset_quiesce(dev);
+
/*
* Due to the hpd irq storm handling the hotplug work can re-arm the
* poll handlers. Hence disable polling after hpd handling is shut down.
@@ -10512,9 +10526,6 @@ void intel_modeset_cleanup(struct drm_device *dev)

mutex_unlock(&dev->struct_mutex);

- /* flush any delayed tasks or pending work */
- flush_scheduled_work();
-
/* destroy backlight, if any, before the connectors */
intel_panel_destroy_backlight(dev);

--
1.8.1.4