diff options
Diffstat (limited to 'drivers/gpu/drm/vmwgfx/vmwgfx_drv.c')
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 125 |
1 files changed, 91 insertions, 34 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 1db1ef30be2b..0c9c0811f42d 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 | { |
@@ -207,6 +209,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) | |||
207 | { | 209 | { |
208 | struct vmw_private *dev_priv; | 210 | struct vmw_private *dev_priv; |
209 | int ret; | 211 | int ret; |
212 | uint32_t svga_id; | ||
210 | 213 | ||
211 | dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL); | 214 | dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL); |
212 | if (unlikely(dev_priv == NULL)) { | 215 | if (unlikely(dev_priv == NULL)) { |
@@ -217,6 +220,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) | |||
217 | 220 | ||
218 | dev_priv->dev = dev; | 221 | dev_priv->dev = dev; |
219 | dev_priv->vmw_chipset = chipset; | 222 | dev_priv->vmw_chipset = chipset; |
223 | dev_priv->last_read_sequence = (uint32_t) -100; | ||
220 | mutex_init(&dev_priv->hw_mutex); | 224 | mutex_init(&dev_priv->hw_mutex); |
221 | mutex_init(&dev_priv->cmdbuf_mutex); | 225 | mutex_init(&dev_priv->cmdbuf_mutex); |
222 | rwlock_init(&dev_priv->resource_lock); | 226 | rwlock_init(&dev_priv->resource_lock); |
@@ -236,6 +240,16 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) | |||
236 | dev_priv->mmio_start = pci_resource_start(dev->pdev, 2); | 240 | dev_priv->mmio_start = pci_resource_start(dev->pdev, 2); |
237 | 241 | ||
238 | mutex_lock(&dev_priv->hw_mutex); | 242 | mutex_lock(&dev_priv->hw_mutex); |
243 | |||
244 | vmw_write(dev_priv, SVGA_REG_ID, SVGA_ID_2); | ||
245 | svga_id = vmw_read(dev_priv, SVGA_REG_ID); | ||
246 | if (svga_id != SVGA_ID_2) { | ||
247 | ret = -ENOSYS; | ||
248 | DRM_ERROR("Unsuported SVGA ID 0x%x\n", svga_id); | ||
249 | mutex_unlock(&dev_priv->hw_mutex); | ||
250 | goto out_err0; | ||
251 | } | ||
252 | |||
239 | dev_priv->capabilities = vmw_read(dev_priv, SVGA_REG_CAPABILITIES); | 253 | dev_priv->capabilities = vmw_read(dev_priv, SVGA_REG_CAPABILITIES); |
240 | 254 | ||
241 | if (dev_priv->capabilities & SVGA_CAP_GMR) { | 255 | if (dev_priv->capabilities & SVGA_CAP_GMR) { |
@@ -334,22 +348,24 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) | |||
334 | */ | 348 | */ |
335 | 349 | ||
336 | DRM_INFO("It appears like vesafb is loaded. " | 350 | DRM_INFO("It appears like vesafb is loaded. " |
337 | "Ignore above error if any. Entering stealth mode.\n"); | 351 | "Ignore above error if any.\n"); |
338 | ret = pci_request_region(dev->pdev, 2, "vmwgfx stealth probe"); | 352 | ret = pci_request_region(dev->pdev, 2, "vmwgfx stealth probe"); |
339 | if (unlikely(ret != 0)) { | 353 | if (unlikely(ret != 0)) { |
340 | DRM_ERROR("Failed reserving the SVGA MMIO resource.\n"); | 354 | DRM_ERROR("Failed reserving the SVGA MMIO resource.\n"); |
341 | goto out_no_device; | 355 | goto out_no_device; |
342 | } | 356 | } |
343 | vmw_kms_init(dev_priv); | ||
344 | vmw_overlay_init(dev_priv); | ||
345 | } else { | ||
346 | ret = vmw_request_device(dev_priv); | ||
347 | if (unlikely(ret != 0)) | ||
348 | goto out_no_device; | ||
349 | vmw_kms_init(dev_priv); | ||
350 | vmw_overlay_init(dev_priv); | ||
351 | vmw_fb_init(dev_priv); | ||
352 | } | 357 | } |
358 | ret = vmw_request_device(dev_priv); | ||
359 | if (unlikely(ret != 0)) | ||
360 | goto out_no_device; | ||
361 | vmw_kms_init(dev_priv); | ||
362 | vmw_overlay_init(dev_priv); | ||
363 | vmw_fb_init(dev_priv); | ||
364 | |||
365 | dev_priv->pm_nb.notifier_call = vmwgfx_pm_notifier; | ||
366 | register_pm_notifier(&dev_priv->pm_nb); | ||
367 | |||
368 | DRM_INFO("%s", vmw_fifo_have_3d(dev_priv) ? "Have 3D\n" : "No 3D\n"); | ||
353 | 369 | ||
354 | return 0; | 370 | return 0; |
355 | 371 | ||
@@ -385,17 +401,17 @@ static int vmw_driver_unload(struct drm_device *dev) | |||
385 | 401 | ||
386 | DRM_INFO(VMWGFX_DRIVER_NAME " unload.\n"); | 402 | DRM_INFO(VMWGFX_DRIVER_NAME " unload.\n"); |
387 | 403 | ||
388 | if (!dev_priv->stealth) { | 404 | unregister_pm_notifier(&dev_priv->pm_nb); |
389 | vmw_fb_close(dev_priv); | 405 | |
390 | vmw_kms_close(dev_priv); | 406 | vmw_fb_close(dev_priv); |
391 | vmw_overlay_close(dev_priv); | 407 | vmw_kms_close(dev_priv); |
392 | vmw_release_device(dev_priv); | 408 | vmw_overlay_close(dev_priv); |
393 | pci_release_regions(dev->pdev); | 409 | vmw_release_device(dev_priv); |
394 | } else { | 410 | if (dev_priv->stealth) |
395 | vmw_kms_close(dev_priv); | ||
396 | vmw_overlay_close(dev_priv); | ||
397 | pci_release_region(dev->pdev, 2); | 411 | pci_release_region(dev->pdev, 2); |
398 | } | 412 | else |
413 | pci_release_regions(dev->pdev); | ||
414 | |||
399 | if (dev_priv->capabilities & SVGA_CAP_IRQMASK) | 415 | if (dev_priv->capabilities & SVGA_CAP_IRQMASK) |
400 | drm_irq_uninstall(dev_priv->dev); | 416 | drm_irq_uninstall(dev_priv->dev); |
401 | if (dev->devname == vmw_devname) | 417 | if (dev->devname == vmw_devname) |
@@ -564,11 +580,6 @@ static int vmw_master_set(struct drm_device *dev, | |||
564 | int ret = 0; | 580 | int ret = 0; |
565 | 581 | ||
566 | DRM_INFO("Master set.\n"); | 582 | DRM_INFO("Master set.\n"); |
567 | if (dev_priv->stealth) { | ||
568 | ret = vmw_request_device(dev_priv); | ||
569 | if (unlikely(ret != 0)) | ||
570 | return ret; | ||
571 | } | ||
572 | 583 | ||
573 | if (active) { | 584 | if (active) { |
574 | BUG_ON(active != &dev_priv->fbdev_master); | 585 | BUG_ON(active != &dev_priv->fbdev_master); |
@@ -628,18 +639,11 @@ static void vmw_master_drop(struct drm_device *dev, | |||
628 | 639 | ||
629 | ttm_lock_set_kill(&vmaster->lock, true, SIGTERM); | 640 | ttm_lock_set_kill(&vmaster->lock, true, SIGTERM); |
630 | 641 | ||
631 | if (dev_priv->stealth) { | ||
632 | ret = ttm_bo_evict_mm(&dev_priv->bdev, TTM_PL_VRAM); | ||
633 | if (unlikely(ret != 0)) | ||
634 | DRM_ERROR("Unable to clean VRAM on master drop.\n"); | ||
635 | vmw_release_device(dev_priv); | ||
636 | } | ||
637 | dev_priv->active_master = &dev_priv->fbdev_master; | 642 | dev_priv->active_master = &dev_priv->fbdev_master; |
638 | ttm_lock_set_kill(&dev_priv->fbdev_master.lock, false, SIGTERM); | 643 | ttm_lock_set_kill(&dev_priv->fbdev_master.lock, false, SIGTERM); |
639 | ttm_vt_unlock(&dev_priv->fbdev_master.lock); | 644 | ttm_vt_unlock(&dev_priv->fbdev_master.lock); |
640 | 645 | ||
641 | if (!dev_priv->stealth) | 646 | vmw_fb_on(dev_priv); |
642 | vmw_fb_on(dev_priv); | ||
643 | } | 647 | } |
644 | 648 | ||
645 | 649 | ||
@@ -650,6 +654,57 @@ static void vmw_remove(struct pci_dev *pdev) | |||
650 | drm_put_dev(dev); | 654 | drm_put_dev(dev); |
651 | } | 655 | } |
652 | 656 | ||
657 | static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val, | ||
658 | void *ptr) | ||
659 | { | ||
660 | struct vmw_private *dev_priv = | ||
661 | container_of(nb, struct vmw_private, pm_nb); | ||
662 | struct vmw_master *vmaster = dev_priv->active_master; | ||
663 | |||
664 | switch (val) { | ||
665 | case PM_HIBERNATION_PREPARE: | ||
666 | case PM_SUSPEND_PREPARE: | ||
667 | ttm_suspend_lock(&vmaster->lock); | ||
668 | |||
669 | /** | ||
670 | * This empties VRAM and unbinds all GMR bindings. | ||
671 | * Buffer contents is moved to swappable memory. | ||
672 | */ | ||
673 | ttm_bo_swapout_all(&dev_priv->bdev); | ||
674 | break; | ||
675 | case PM_POST_HIBERNATION: | ||
676 | case PM_POST_SUSPEND: | ||
677 | ttm_suspend_unlock(&vmaster->lock); | ||
678 | break; | ||
679 | case PM_RESTORE_PREPARE: | ||
680 | break; | ||
681 | case PM_POST_RESTORE: | ||
682 | break; | ||
683 | default: | ||
684 | break; | ||
685 | } | ||
686 | return 0; | ||
687 | } | ||
688 | |||
689 | /** | ||
690 | * These might not be needed with the virtual SVGA device. | ||
691 | */ | ||
692 | |||
693 | int vmw_pci_suspend(struct pci_dev *pdev, pm_message_t state) | ||
694 | { | ||
695 | pci_save_state(pdev); | ||
696 | pci_disable_device(pdev); | ||
697 | pci_set_power_state(pdev, PCI_D3hot); | ||
698 | return 0; | ||
699 | } | ||
700 | |||
701 | int vmw_pci_resume(struct pci_dev *pdev) | ||
702 | { | ||
703 | pci_set_power_state(pdev, PCI_D0); | ||
704 | pci_restore_state(pdev); | ||
705 | return pci_enable_device(pdev); | ||
706 | } | ||
707 | |||
653 | static struct drm_driver driver = { | 708 | static struct drm_driver driver = { |
654 | .driver_features = DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | | 709 | .driver_features = DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | |
655 | DRIVER_MODESET, | 710 | DRIVER_MODESET, |
@@ -689,7 +744,9 @@ static struct drm_driver driver = { | |||
689 | .name = VMWGFX_DRIVER_NAME, | 744 | .name = VMWGFX_DRIVER_NAME, |
690 | .id_table = vmw_pci_id_list, | 745 | .id_table = vmw_pci_id_list, |
691 | .probe = vmw_probe, | 746 | .probe = vmw_probe, |
692 | .remove = vmw_remove | 747 | .remove = vmw_remove, |
748 | .suspend = vmw_pci_suspend, | ||
749 | .resume = vmw_pci_resume | ||
693 | }, | 750 | }, |
694 | .name = VMWGFX_DRIVER_NAME, | 751 | .name = VMWGFX_DRIVER_NAME, |
695 | .desc = VMWGFX_DRIVER_DESC, | 752 | .desc = VMWGFX_DRIVER_DESC, |