aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/i915_drv.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915/i915_drv.c')
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c63
1 files changed, 47 insertions, 16 deletions
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 7643300828c3..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)
return 0;
}
-static int i915_drm_suspend_late(struct drm_device *drm_dev)
+static int i915_drm_suspend_late(struct drm_device *drm_dev, bool hibernation)
{
struct drm_i915_private *dev_priv = drm_dev->dev_private;
int ret;
@@ -636,7 +636,17 @@ static int i915_drm_suspend_late(struct drm_device *drm_dev)
}
pci_disable_device(drm_dev->pdev);
- pci_set_power_state(drm_dev->pdev, PCI_D3hot);
+ /*
+ * During hibernation on some GEN4 platforms the BIOS may try to access
+ * the device even though it's already in D3 and hang the machine. So
+ * leave the device in D0 on those platforms and hope the BIOS will
+ * power down the device properly. Platforms where this was seen:
+ * Lenovo Thinkpad X301, X61s
+ */
+ if (!(hibernation &&
+ drm_dev->pdev->subsystem_vendor == PCI_VENDOR_ID_LENOVO &&
+ INTEL_INFO(dev_priv)->gen == 4))
+ pci_set_power_state(drm_dev->pdev, PCI_D3hot);
return 0;
}
@@ -662,7 +672,7 @@ int i915_suspend_legacy(struct drm_device *dev, pm_message_t state)
if (error)
return error;
- return i915_drm_suspend_late(dev);
+ return i915_drm_suspend_late(dev, false);
}
static int i915_drm_resume(struct drm_device *dev)
@@ -835,6 +845,8 @@ int i915_reset(struct drm_device *dev)
return ret;
}
+ intel_overlay_reset(dev_priv);
+
/* Ok, now get things going again... */
/*
@@ -934,8 +946,7 @@ static int i915_pm_suspend(struct device *dev)
static int i915_pm_suspend_late(struct device *dev)
{
- struct pci_dev *pdev = to_pci_dev(dev);
- struct drm_device *drm_dev = pci_get_drvdata(pdev);
+ struct drm_device *drm_dev = dev_to_i915(dev)->dev;
/*
* We have a suspedn ordering issue with the snd-hda driver also
@@ -949,13 +960,22 @@ static int i915_pm_suspend_late(struct device *dev)
if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
return 0;
- return i915_drm_suspend_late(drm_dev);
+ return i915_drm_suspend_late(drm_dev, false);
+}
+
+static int i915_pm_poweroff_late(struct device *dev)
+{
+ struct drm_device *drm_dev = dev_to_i915(dev)->dev;
+
+ if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
+ return 0;
+
+ return i915_drm_suspend_late(drm_dev, true);
}
static int i915_pm_resume_early(struct device *dev)
{
- struct pci_dev *pdev = to_pci_dev(dev);
- struct drm_device *drm_dev = pci_get_drvdata(pdev);
+ struct drm_device *drm_dev = dev_to_i915(dev)->dev;
if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
return 0;
@@ -965,8 +985,7 @@ static int i915_pm_resume_early(struct device *dev)
static int i915_pm_resume(struct device *dev)
{
- struct pci_dev *pdev = to_pci_dev(dev);
- struct drm_device *drm_dev = pci_get_drvdata(pdev);
+ struct drm_device *drm_dev = dev_to_i915(dev)->dev;
if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
return 0;
@@ -1293,7 +1312,9 @@ static int vlv_suspend_complete(struct drm_i915_private *dev_priv)
err = vlv_allow_gt_wake(dev_priv, false);
if (err)
goto err2;
- vlv_save_gunit_s0ix_state(dev_priv);
+
+ if (!IS_CHERRYVIEW(dev_priv->dev))
+ vlv_save_gunit_s0ix_state(dev_priv);
err = vlv_force_gfx_clock(dev_priv, false);
if (err)
@@ -1324,7 +1345,8 @@ static int vlv_resume_prepare(struct drm_i915_private *dev_priv,
*/
ret = vlv_force_gfx_clock(dev_priv, true);
- vlv_restore_gunit_s0ix_state(dev_priv);
+ if (!IS_CHERRYVIEW(dev_priv->dev))
+ vlv_restore_gunit_s0ix_state(dev_priv);
err = vlv_allow_gt_wake(dev_priv, true);
if (!ret)
@@ -1357,8 +1379,6 @@ static int intel_runtime_suspend(struct device *device)
if (WARN_ON_ONCE(!HAS_RUNTIME_PM(dev)))
return -ENODEV;
- assert_force_wake_inactive(dev_priv);
-
DRM_DEBUG_KMS("Suspending device\n");
/*
@@ -1396,7 +1416,8 @@ static int intel_runtime_suspend(struct device *device)
return ret;
}
- del_timer_sync(&dev_priv->gpu_error.hangcheck_timer);
+ cancel_delayed_work_sync(&dev_priv->gpu_error.hangcheck_work);
+ intel_uncore_forcewake_reset(dev, false);
dev_priv->pm.suspended = true;
/*
@@ -1424,6 +1445,8 @@ static int intel_runtime_suspend(struct device *device)
intel_opregion_notify_adapter(dev, PCI_D3hot);
}
+ assert_forcewakes_inactive(dev_priv);
+
DRM_DEBUG_KMS("Device suspended\n");
return 0;
}
@@ -1517,7 +1540,7 @@ static const struct dev_pm_ops i915_pm_ops = {
.thaw_early = i915_pm_resume_early,
.thaw = i915_pm_resume,
.poweroff = i915_pm_suspend,
- .poweroff_late = i915_pm_suspend_late,
+ .poweroff_late = i915_pm_poweroff_late,
.restore_early = i915_pm_resume_early,
.restore = i915_pm_resume,
@@ -1634,6 +1657,14 @@ static int __init i915_init(void)
#endif
}
+ /*
+ * FIXME: Note that we're lying to the DRM core here so that we can get access
+ * to the atomic ioctl and the atomic properties. Only plane operations on
+ * a single CRTC will actually work.
+ */
+ if (i915.nuclear_pageflip)
+ driver.driver_features |= DRIVER_ATOMIC;
+
return drm_pci_init(&driver, &i915_pci_driver);
}