diff options
author | Thomas Hellstrom <thellstrom@vmware.com> | 2010-01-13 16:28:43 -0500 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2010-01-13 21:19:57 -0500 |
commit | d9f36a0051b7c0382107cb0342af1126a6eb627d (patch) | |
tree | e39118bbf806914b7124ee9ab4b0b51a585d493c /drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | |
parent | e99e1e7893ac80fe769477cb1ddd4b482cef8902 (diff) |
drm/vmwgfx: Implement basic pm operations.
Currently we really only support S3, since the device doesn't support
saving of the 3D state.
On S3/S4, move all buffer objects to swappable memory and take down
GMR bindings. We need to do that from a PM notifier since we can't
do persistant memory allocations from the standard PM callbacks.
Signed-off-by: Thomas Hellstrom <thellstrom@vmware.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_drv.c')
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 62 |
1 files changed, 61 insertions, 1 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 70e4f5f0c122..dedd121d8fe7 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | |||
@@ -147,6 +147,8 @@ static char *vmw_devname = "vmwgfx"; | |||
147 | 147 | ||
148 | static int vmw_probe(struct pci_dev *, const struct pci_device_id *); | 148 | static int vmw_probe(struct pci_dev *, const struct pci_device_id *); |
149 | static void vmw_master_init(struct vmw_master *); | 149 | static void vmw_master_init(struct vmw_master *); |
150 | static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val, | ||
151 | void *ptr); | ||
150 | 152 | ||
151 | static void vmw_print_capabilities(uint32_t capabilities) | 153 | static void vmw_print_capabilities(uint32_t capabilities) |
152 | { | 154 | { |
@@ -352,6 +354,9 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) | |||
352 | vmw_fb_init(dev_priv); | 354 | vmw_fb_init(dev_priv); |
353 | } | 355 | } |
354 | 356 | ||
357 | dev_priv->pm_nb.notifier_call = vmwgfx_pm_notifier; | ||
358 | register_pm_notifier(&dev_priv->pm_nb); | ||
359 | |||
355 | return 0; | 360 | return 0; |
356 | 361 | ||
357 | out_no_device: | 362 | out_no_device: |
@@ -386,6 +391,8 @@ static int vmw_driver_unload(struct drm_device *dev) | |||
386 | 391 | ||
387 | DRM_INFO(VMWGFX_DRIVER_NAME " unload.\n"); | 392 | DRM_INFO(VMWGFX_DRIVER_NAME " unload.\n"); |
388 | 393 | ||
394 | unregister_pm_notifier(&dev_priv->pm_nb); | ||
395 | |||
389 | if (!dev_priv->stealth) { | 396 | if (!dev_priv->stealth) { |
390 | vmw_fb_close(dev_priv); | 397 | vmw_fb_close(dev_priv); |
391 | vmw_kms_close(dev_priv); | 398 | vmw_kms_close(dev_priv); |
@@ -651,6 +658,57 @@ static void vmw_remove(struct pci_dev *pdev) | |||
651 | drm_put_dev(dev); | 658 | drm_put_dev(dev); |
652 | } | 659 | } |
653 | 660 | ||
661 | static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val, | ||
662 | void *ptr) | ||
663 | { | ||
664 | struct vmw_private *dev_priv = | ||
665 | container_of(nb, struct vmw_private, pm_nb); | ||
666 | struct vmw_master *vmaster = dev_priv->active_master; | ||
667 | |||
668 | switch (val) { | ||
669 | case PM_HIBERNATION_PREPARE: | ||
670 | case PM_SUSPEND_PREPARE: | ||
671 | ttm_suspend_lock(&vmaster->lock); | ||
672 | |||
673 | /** | ||
674 | * This empties VRAM and unbinds all GMR bindings. | ||
675 | * Buffer contents is moved to swappable memory. | ||
676 | */ | ||
677 | ttm_bo_swapout_all(&dev_priv->bdev); | ||
678 | break; | ||
679 | case PM_POST_HIBERNATION: | ||
680 | case PM_POST_SUSPEND: | ||
681 | ttm_suspend_unlock(&vmaster->lock); | ||
682 | break; | ||
683 | case PM_RESTORE_PREPARE: | ||
684 | break; | ||
685 | case PM_POST_RESTORE: | ||
686 | break; | ||
687 | default: | ||
688 | break; | ||
689 | } | ||
690 | return 0; | ||
691 | } | ||
692 | |||
693 | /** | ||
694 | * These might not be needed with the virtual SVGA device. | ||
695 | */ | ||
696 | |||
697 | int vmw_pci_suspend(struct pci_dev *pdev, pm_message_t state) | ||
698 | { | ||
699 | pci_save_state(pdev); | ||
700 | pci_disable_device(pdev); | ||
701 | pci_set_power_state(pdev, PCI_D3hot); | ||
702 | return 0; | ||
703 | } | ||
704 | |||
705 | int vmw_pci_resume(struct pci_dev *pdev) | ||
706 | { | ||
707 | pci_set_power_state(pdev, PCI_D0); | ||
708 | pci_restore_state(pdev); | ||
709 | return pci_enable_device(pdev); | ||
710 | } | ||
711 | |||
654 | static struct drm_driver driver = { | 712 | static struct drm_driver driver = { |
655 | .driver_features = DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | | 713 | .driver_features = DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | |
656 | DRIVER_MODESET, | 714 | DRIVER_MODESET, |
@@ -690,7 +748,9 @@ static struct drm_driver driver = { | |||
690 | .name = VMWGFX_DRIVER_NAME, | 748 | .name = VMWGFX_DRIVER_NAME, |
691 | .id_table = vmw_pci_id_list, | 749 | .id_table = vmw_pci_id_list, |
692 | .probe = vmw_probe, | 750 | .probe = vmw_probe, |
693 | .remove = vmw_remove | 751 | .remove = vmw_remove, |
752 | .suspend = vmw_pci_suspend, | ||
753 | .resume = vmw_pci_resume | ||
694 | }, | 754 | }, |
695 | .name = VMWGFX_DRIVER_NAME, | 755 | .name = VMWGFX_DRIVER_NAME, |
696 | .desc = VMWGFX_DRIVER_DESC, | 756 | .desc = VMWGFX_DRIVER_DESC, |