drm/vmwgfx: Add new-style PM hooks to improve hibernation behavior
authorThomas Hellstrom <thellstrom@vmware.com>
Tue, 5 Oct 2010 10:43:01 +0000 (12:43 +0200)
committerDave Airlie <airlied@redhat.com>
Wed, 6 Oct 2010 01:29:37 +0000 (11:29 +1000)
Add the new-style PM hooks prepare and complete. This allows us to
power up the device again after the hibernation image has been created, and
display output will thus be active until the VM is finally powered off.

Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c

index 91eeade92124aabd7484301b610752eca906866e..f3e481f9aa86562052ad85f017ec1a46e27b71b1 100644 (file)
@@ -752,34 +752,10 @@ static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val,
                 */
                ttm_bo_swapout_all(&dev_priv->bdev);
 
-               /**
-                * Release 3d reference held by fbdev and potentially
-                * stop fifo.
-                */
-               dev_priv->suspended = true;
-               if (dev_priv->enable_fb)
-                       vmw_3d_resource_dec(dev_priv);
-
                break;
        case PM_POST_HIBERNATION:
        case PM_POST_SUSPEND:
        case PM_POST_RESTORE:
-               if (!dev_priv->suspended) {
-                       printk(KERN_WARNING
-                              "[%s] Driver is not suspended at resume"
-                              " point.\n", VMWGFX_DRIVER_NAME);
-
-                       break;
-               }
-
-               /**
-                * Reclaim 3d reference held by fbdev and potentially
-                * start fifo.
-                */
-               if (dev_priv->enable_fb)
-                       vmw_3d_resource_inc(dev_priv);
-
-               dev_priv->suspended = false;
                ttm_suspend_unlock(&vmaster->lock);
 
                break;
@@ -795,7 +771,7 @@ static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val,
  * These might not be needed with the virtual SVGA device.
  */
 
-int vmw_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+static int vmw_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct drm_device *dev = pci_get_drvdata(pdev);
        struct vmw_private *dev_priv = vmw_priv(dev);
@@ -812,13 +788,81 @@ int vmw_pci_suspend(struct pci_dev *pdev, pm_message_t state)
        return 0;
 }
 
-int vmw_pci_resume(struct pci_dev *pdev)
+static int vmw_pci_resume(struct pci_dev *pdev)
 {
        pci_set_power_state(pdev, PCI_D0);
        pci_restore_state(pdev);
        return pci_enable_device(pdev);
 }
 
+static int vmw_pm_suspend(struct device *kdev)
+{
+       struct pci_dev *pdev = to_pci_dev(kdev);
+       struct pm_message dummy;
+
+       dummy.event = 0;
+
+       return vmw_pci_suspend(pdev, dummy);
+}
+
+static int vmw_pm_resume(struct device *kdev)
+{
+       struct pci_dev *pdev = to_pci_dev(kdev);
+
+       return vmw_pci_resume(pdev);
+}
+
+static int vmw_pm_prepare(struct device *kdev)
+{
+       struct pci_dev *pdev = to_pci_dev(kdev);
+       struct drm_device *dev = pci_get_drvdata(pdev);
+       struct vmw_private *dev_priv = vmw_priv(dev);
+
+       /**
+        * Release 3d reference held by fbdev and potentially
+        * stop fifo.
+        */
+       dev_priv->suspended = true;
+       if (dev_priv->enable_fb)
+               vmw_3d_resource_dec(dev_priv);
+
+       if (dev_priv->num_3d_resources != 0) {
+
+               DRM_INFO("Can't suspend or hibernate "
+                        "while 3D resources are active.\n");
+
+               if (dev_priv->enable_fb)
+                       vmw_3d_resource_inc(dev_priv);
+               dev_priv->suspended = false;
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+static void vmw_pm_complete(struct device *kdev)
+{
+       struct pci_dev *pdev = to_pci_dev(kdev);
+       struct drm_device *dev = pci_get_drvdata(pdev);
+       struct vmw_private *dev_priv = vmw_priv(dev);
+
+       /**
+        * Reclaim 3d reference held by fbdev and potentially
+        * start fifo.
+        */
+       if (dev_priv->enable_fb)
+               vmw_3d_resource_inc(dev_priv);
+
+       dev_priv->suspended = false;
+}
+
+static const struct dev_pm_ops vmw_pm_ops = {
+       .prepare = vmw_pm_prepare,
+       .complete = vmw_pm_complete,
+       .suspend = vmw_pm_suspend,
+       .resume = vmw_pm_resume,
+};
+
 static struct drm_driver driver = {
        .driver_features = DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
        DRIVER_MODESET,
@@ -852,15 +896,16 @@ static struct drm_driver driver = {
 #if defined(CONFIG_COMPAT)
                 .compat_ioctl = drm_compat_ioctl,
 #endif
-                },
+       },
        .pci_driver = {
-                      .name = VMWGFX_DRIVER_NAME,
-                      .id_table = vmw_pci_id_list,
-                      .probe = vmw_probe,
-                      .remove = vmw_remove,
-                      .suspend = vmw_pci_suspend,
-                      .resume = vmw_pci_resume
-                      },
+                .name = VMWGFX_DRIVER_NAME,
+                .id_table = vmw_pci_id_list,
+                .probe = vmw_probe,
+                .remove = vmw_remove,
+                .driver = {
+                        .pm = &vmw_pm_ops
+                }
+        },
        .name = VMWGFX_DRIVER_NAME,
        .desc = VMWGFX_DRIVER_DESC,
        .date = VMWGFX_DRIVER_DATE,