Merge branch 'omap-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[sfrench/cifs-2.6.git] / drivers / gpu / drm / vmwgfx / vmwgfx_drv.c
index 1db1ef30be2b2b87fbef3ee08df4f98c345421bb..a6e8f687fa64cc14980600ecc2fa5c4f7486f8ad 100644 (file)
@@ -147,6 +147,8 @@ static char *vmw_devname = "vmwgfx";
 
 static int vmw_probe(struct pci_dev *, const struct pci_device_id *);
 static void vmw_master_init(struct vmw_master *);
+static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val,
+                             void *ptr);
 
 static void vmw_print_capabilities(uint32_t capabilities)
 {
@@ -207,6 +209,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
 {
        struct vmw_private *dev_priv;
        int ret;
+       uint32_t svga_id;
 
        dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL);
        if (unlikely(dev_priv == NULL)) {
@@ -217,6 +220,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
 
        dev_priv->dev = dev;
        dev_priv->vmw_chipset = chipset;
+       dev_priv->last_read_sequence = (uint32_t) -100;
        mutex_init(&dev_priv->hw_mutex);
        mutex_init(&dev_priv->cmdbuf_mutex);
        rwlock_init(&dev_priv->resource_lock);
@@ -236,6 +240,16 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
        dev_priv->mmio_start = pci_resource_start(dev->pdev, 2);
 
        mutex_lock(&dev_priv->hw_mutex);
+
+       vmw_write(dev_priv, SVGA_REG_ID, SVGA_ID_2);
+       svga_id = vmw_read(dev_priv, SVGA_REG_ID);
+       if (svga_id != SVGA_ID_2) {
+               ret = -ENOSYS;
+               DRM_ERROR("Unsuported SVGA ID 0x%x\n", svga_id);
+               mutex_unlock(&dev_priv->hw_mutex);
+               goto out_err0;
+       }
+
        dev_priv->capabilities = vmw_read(dev_priv, SVGA_REG_CAPABILITIES);
 
        if (dev_priv->capabilities & SVGA_CAP_GMR) {
@@ -351,6 +365,11 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
                vmw_fb_init(dev_priv);
        }
 
+       dev_priv->pm_nb.notifier_call = vmwgfx_pm_notifier;
+       register_pm_notifier(&dev_priv->pm_nb);
+
+       DRM_INFO("%s", vmw_fifo_have_3d(dev_priv) ? "Have 3D\n" : "No 3D\n");
+
        return 0;
 
 out_no_device:
@@ -385,6 +404,8 @@ static int vmw_driver_unload(struct drm_device *dev)
 
        DRM_INFO(VMWGFX_DRIVER_NAME " unload.\n");
 
+       unregister_pm_notifier(&dev_priv->pm_nb);
+
        if (!dev_priv->stealth) {
                vmw_fb_close(dev_priv);
                vmw_kms_close(dev_priv);
@@ -650,6 +671,57 @@ static void vmw_remove(struct pci_dev *pdev)
        drm_put_dev(dev);
 }
 
+static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val,
+                             void *ptr)
+{
+       struct vmw_private *dev_priv =
+               container_of(nb, struct vmw_private, pm_nb);
+       struct vmw_master *vmaster = dev_priv->active_master;
+
+       switch (val) {
+       case PM_HIBERNATION_PREPARE:
+       case PM_SUSPEND_PREPARE:
+               ttm_suspend_lock(&vmaster->lock);
+
+               /**
+                * This empties VRAM and unbinds all GMR bindings.
+                * Buffer contents is moved to swappable memory.
+                */
+               ttm_bo_swapout_all(&dev_priv->bdev);
+               break;
+       case PM_POST_HIBERNATION:
+       case PM_POST_SUSPEND:
+               ttm_suspend_unlock(&vmaster->lock);
+               break;
+       case PM_RESTORE_PREPARE:
+               break;
+       case PM_POST_RESTORE:
+               break;
+       default:
+               break;
+       }
+       return 0;
+}
+
+/**
+ * These might not be needed with the virtual SVGA device.
+ */
+
+int vmw_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       pci_save_state(pdev);
+       pci_disable_device(pdev);
+       pci_set_power_state(pdev, PCI_D3hot);
+       return 0;
+}
+
+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 struct drm_driver driver = {
        .driver_features = DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
        DRIVER_MODESET,
@@ -689,7 +761,9 @@ static struct drm_driver driver = {
                       .name = VMWGFX_DRIVER_NAME,
                       .id_table = vmw_pci_id_list,
                       .probe = vmw_probe,
-                      .remove = vmw_remove
+                      .remove = vmw_remove,
+                      .suspend = vmw_pci_suspend,
+                      .resume = vmw_pci_resume
                       },
        .name = VMWGFX_DRIVER_NAME,
        .desc = VMWGFX_DRIVER_DESC,