diff options
Diffstat (limited to 'drivers/gpu/drm/i915/i915_drv.c')
| -rw-r--r-- | drivers/gpu/drm/i915/i915_drv.c | 30 |
1 files changed, 25 insertions, 5 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 8039cec71fc2..cc6ea53d2b81 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c | |||
| @@ -622,7 +622,7 @@ static int i915_drm_suspend(struct drm_device *dev) | |||
| 622 | return 0; | 622 | return 0; |
| 623 | } | 623 | } |
| 624 | 624 | ||
| 625 | static int i915_drm_suspend_late(struct drm_device *drm_dev) | 625 | static int i915_drm_suspend_late(struct drm_device *drm_dev, bool hibernation) |
| 626 | { | 626 | { |
| 627 | struct drm_i915_private *dev_priv = drm_dev->dev_private; | 627 | struct drm_i915_private *dev_priv = drm_dev->dev_private; |
| 628 | int ret; | 628 | int ret; |
| @@ -636,7 +636,17 @@ static int i915_drm_suspend_late(struct drm_device *drm_dev) | |||
| 636 | } | 636 | } |
| 637 | 637 | ||
| 638 | pci_disable_device(drm_dev->pdev); | 638 | pci_disable_device(drm_dev->pdev); |
| 639 | pci_set_power_state(drm_dev->pdev, PCI_D3hot); | 639 | /* |
| 640 | * During hibernation on some GEN4 platforms the BIOS may try to access | ||
| 641 | * the device even though it's already in D3 and hang the machine. So | ||
| 642 | * leave the device in D0 on those platforms and hope the BIOS will | ||
| 643 | * power down the device properly. Platforms where this was seen: | ||
| 644 | * Lenovo Thinkpad X301, X61s | ||
| 645 | */ | ||
| 646 | if (!(hibernation && | ||
| 647 | drm_dev->pdev->subsystem_vendor == PCI_VENDOR_ID_LENOVO && | ||
| 648 | INTEL_INFO(dev_priv)->gen == 4)) | ||
| 649 | pci_set_power_state(drm_dev->pdev, PCI_D3hot); | ||
| 640 | 650 | ||
| 641 | return 0; | 651 | return 0; |
| 642 | } | 652 | } |
| @@ -662,7 +672,7 @@ int i915_suspend_legacy(struct drm_device *dev, pm_message_t state) | |||
| 662 | if (error) | 672 | if (error) |
| 663 | return error; | 673 | return error; |
| 664 | 674 | ||
| 665 | return i915_drm_suspend_late(dev); | 675 | return i915_drm_suspend_late(dev, false); |
| 666 | } | 676 | } |
| 667 | 677 | ||
| 668 | static int i915_drm_resume(struct drm_device *dev) | 678 | static int i915_drm_resume(struct drm_device *dev) |
| @@ -950,7 +960,17 @@ static int i915_pm_suspend_late(struct device *dev) | |||
| 950 | if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF) | 960 | if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF) |
| 951 | return 0; | 961 | return 0; |
| 952 | 962 | ||
| 953 | return i915_drm_suspend_late(drm_dev); | 963 | return i915_drm_suspend_late(drm_dev, false); |
| 964 | } | ||
| 965 | |||
| 966 | static int i915_pm_poweroff_late(struct device *dev) | ||
| 967 | { | ||
| 968 | struct drm_device *drm_dev = dev_to_i915(dev)->dev; | ||
| 969 | |||
| 970 | if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF) | ||
| 971 | return 0; | ||
| 972 | |||
| 973 | return i915_drm_suspend_late(drm_dev, true); | ||
| 954 | } | 974 | } |
| 955 | 975 | ||
| 956 | static int i915_pm_resume_early(struct device *dev) | 976 | static int i915_pm_resume_early(struct device *dev) |
| @@ -1520,7 +1540,7 @@ static const struct dev_pm_ops i915_pm_ops = { | |||
| 1520 | .thaw_early = i915_pm_resume_early, | 1540 | .thaw_early = i915_pm_resume_early, |
| 1521 | .thaw = i915_pm_resume, | 1541 | .thaw = i915_pm_resume, |
| 1522 | .poweroff = i915_pm_suspend, | 1542 | .poweroff = i915_pm_suspend, |
| 1523 | .poweroff_late = i915_pm_suspend_late, | 1543 | .poweroff_late = i915_pm_poweroff_late, |
| 1524 | .restore_early = i915_pm_resume_early, | 1544 | .restore_early = i915_pm_resume_early, |
| 1525 | .restore = i915_pm_resume, | 1545 | .restore = i915_pm_resume, |
| 1526 | 1546 | ||
