drm/i915: don't block resume on fb console resume v2
authorJesse Barnes <jbarnes@virtuousgeek.org>
Fri, 2 Nov 2012 18:13:59 +0000 (11:13 -0700)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Sun, 11 Nov 2012 22:51:40 +0000 (23:51 +0100)
The console lock can be contended, so rather than prevent other drivers
after us from being held up, queue the console suspend into the global
work queue that can happen anytime.  I've measured this to take around
200ms on my T420.  Combined with the ring freq/turbo change, we should
save almost 1/2 a second on resume.

v2: use console_trylock() to try to resume the console immediately (Chris)

Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
[danvet: move dev_priv->console_resume_work next to the fbdev
pointer.]
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h

index e67080729746ef81ea52e9ffcd5a014fbe266516..530cf90d13b0ebd1b91670fdd4a8b6115073a728 100644 (file)
@@ -1329,6 +1329,8 @@ static int i915_load_modeset_init(struct drm_device *dev)
 
        intel_modeset_gem_init(dev);
 
+       INIT_WORK(&dev_priv->console_resume_work, intel_console_resume);
+
        ret = drm_irq_install(dev);
        if (ret)
                goto cleanup_gem;
@@ -1723,6 +1725,7 @@ int i915_driver_unload(struct drm_device *dev)
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
                intel_fbdev_fini(dev);
                intel_modeset_cleanup(dev);
+               cancel_work_sync(&dev_priv->console_resume_work);
 
                /*
                 * free the memory space allocated for the child device
index a08e9cafb7f29c04d5f04da79082517c7732b18d..cfd8920537c5d32a417335538722c595e0190162 100644 (file)
@@ -523,6 +523,18 @@ int i915_suspend(struct drm_device *dev, pm_message_t state)
        return 0;
 }
 
+void intel_console_resume(struct work_struct *work)
+{
+       struct drm_i915_private *dev_priv =
+               container_of(work, struct drm_i915_private,
+                            console_resume_work);
+       struct drm_device *dev = dev_priv->dev;
+
+       console_lock();
+       intel_fbdev_set_suspend(dev, 0);
+       console_unlock();
+}
+
 static int i915_drm_thaw(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -559,9 +571,18 @@ static int i915_drm_thaw(struct drm_device *dev)
 
        dev_priv->modeset_on_lid = 0;
 
-       console_lock();
-       intel_fbdev_set_suspend(dev, 0);
-       console_unlock();
+       /*
+        * The console lock can be pretty contented on resume due
+        * to all the printk activity.  Try to keep it out of the hot
+        * path of resume if possible.
+        */
+       if (console_trylock()) {
+               intel_fbdev_set_suspend(dev, 0);
+               console_unlock();
+       } else {
+               schedule_work(&dev_priv->console_resume_work);
+       }
+
        return error;
 }
 
index 135b9db552792352dd3af0c428b9b17f6fde2813..f8fa63deb92ca17864e5770d0e1b044f77d3d4d8 100644 (file)
@@ -887,6 +887,12 @@ typedef struct drm_i915_private {
        /* list of fbdev register on this device */
        struct intel_fbdev *fbdev;
 
+       /*
+        * The console may be contended at resume, but we don't
+        * want it to block on it.
+        */
+       struct work_struct console_resume_work;
+
        struct backlight_device *backlight;
 
        struct drm_property *broadcast_rgb_property;
@@ -1273,6 +1279,7 @@ extern unsigned long i915_mch_val(struct drm_i915_private *dev_priv);
 extern unsigned long i915_gfx_val(struct drm_i915_private *dev_priv);
 extern void i915_update_gfx_val(struct drm_i915_private *dev_priv);
 
+extern void intel_console_resume(struct work_struct *work);
 
 /* i915_irq.c */
 void i915_hangcheck_elapsed(unsigned long data);