Commit 76c4b250 authored by Imre Deak's avatar Imre Deak Committed by Daniel Vetter

drm/i915: move power domain init earlier during system resume

During resume the intel hda audio driver depends on the i915 driver
reinitializing the audio power domain. Since the order of calling the
i915 resume handler wrt. that of the audio driver is not guaranteed,
move the power domain reinitialization step to the resume_early
handler. This is guaranteed to run before the resume handler of any
other driver.

The power domain initialization in turn requires us to enable the i915
pci device first, so move that part earlier too.

Accordingly disabling of the i915 pci device should happen after the
audio suspend handler ran. So move the disabling later from the i915
resume handler to the resume_late handler.

v2:
- move intel_uncore_sanitize/early_sanitize earlier too, so they don't
  get reordered wrt. intel_power_domains_init_hw()

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=76152Signed-off-by: default avatarImre Deak <imre.deak@intel.com>
Reviewed-by: default avatarTakashi Iwai <tiwai@suse.de>
Cc: stable@vger.kernel.org
[danvet: Add cc: stable and loud comments that this is just a hack.]
[danvet: Fix "Should it be static?" sparse warning reported by Wu
Fengguang's kbuilder.]
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent bc104d1f
...@@ -537,14 +537,21 @@ static void intel_resume_hotplug(struct drm_device *dev) ...@@ -537,14 +537,21 @@ static void intel_resume_hotplug(struct drm_device *dev)
drm_helper_hpd_irq_event(dev); drm_helper_hpd_irq_event(dev);
} }
static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings) static int i915_drm_thaw_early(struct drm_device *dev)
{ {
struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_private *dev_priv = dev->dev_private;
int error = 0;
intel_uncore_early_sanitize(dev); intel_uncore_early_sanitize(dev);
intel_uncore_sanitize(dev); intel_uncore_sanitize(dev);
intel_power_domains_init_hw(dev_priv);
return 0;
}
static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings)
{
struct drm_i915_private *dev_priv = dev->dev_private;
int error = 0;
if (drm_core_check_feature(dev, DRIVER_MODESET) && if (drm_core_check_feature(dev, DRIVER_MODESET) &&
restore_gtt_mappings) { restore_gtt_mappings) {
...@@ -553,8 +560,6 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings) ...@@ -553,8 +560,6 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings)
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
} }
intel_power_domains_init_hw(dev_priv);
i915_restore_state(dev); i915_restore_state(dev);
intel_opregion_setup(dev); intel_opregion_setup(dev);
...@@ -619,19 +624,33 @@ static int i915_drm_thaw(struct drm_device *dev) ...@@ -619,19 +624,33 @@ static int i915_drm_thaw(struct drm_device *dev)
return __i915_drm_thaw(dev, true); return __i915_drm_thaw(dev, true);
} }
int i915_resume(struct drm_device *dev) static int i915_resume_early(struct drm_device *dev)
{ {
struct drm_i915_private *dev_priv = dev->dev_private;
int ret;
if (dev->switch_power_state == DRM_SWITCH_POWER_OFF) if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
return 0; return 0;
/*
* We have a resume ordering issue with the snd-hda driver also
* requiring our device to be power up. Due to the lack of a
* parent/child relationship we currently solve this with an early
* resume hook.
*
* FIXME: This should be solved with a special hdmi sink device or
* similar so that power domains can be employed.
*/
if (pci_enable_device(dev->pdev)) if (pci_enable_device(dev->pdev))
return -EIO; return -EIO;
pci_set_master(dev->pdev); pci_set_master(dev->pdev);
return i915_drm_thaw_early(dev);
}
int i915_resume(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
int ret;
/* /*
* Platforms with opregion should have sane BIOS, older ones (gen3 and * Platforms with opregion should have sane BIOS, older ones (gen3 and
* earlier) need to restore the GTT mappings since the BIOS might clear * earlier) need to restore the GTT mappings since the BIOS might clear
...@@ -645,6 +664,14 @@ int i915_resume(struct drm_device *dev) ...@@ -645,6 +664,14 @@ int i915_resume(struct drm_device *dev)
return 0; return 0;
} }
static int i915_resume_legacy(struct drm_device *dev)
{
i915_resume_early(dev);
i915_resume(dev);
return 0;
}
/** /**
* i915_reset - reset chip after a hang * i915_reset - reset chip after a hang
* @dev: drm device to reset * @dev: drm device to reset
...@@ -776,7 +803,6 @@ static int i915_pm_suspend(struct device *dev) ...@@ -776,7 +803,6 @@ static int i915_pm_suspend(struct device *dev)
{ {
struct pci_dev *pdev = to_pci_dev(dev); struct pci_dev *pdev = to_pci_dev(dev);
struct drm_device *drm_dev = pci_get_drvdata(pdev); struct drm_device *drm_dev = pci_get_drvdata(pdev);
int error;
if (!drm_dev || !drm_dev->dev_private) { if (!drm_dev || !drm_dev->dev_private) {
dev_err(dev, "DRM not initialized, aborting suspend.\n"); dev_err(dev, "DRM not initialized, aborting suspend.\n");
...@@ -786,9 +812,25 @@ static int i915_pm_suspend(struct device *dev) ...@@ -786,9 +812,25 @@ static int i915_pm_suspend(struct device *dev)
if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF) if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
return 0; return 0;
error = i915_drm_freeze(drm_dev); return i915_drm_freeze(drm_dev);
if (error) }
return error;
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);
/*
* We have a suspedn ordering issue with the snd-hda driver also
* requiring our device to be power up. Due to the lack of a
* parent/child relationship we currently solve this with an late
* suspend hook.
*
* FIXME: This should be solved with a special hdmi sink device or
* similar so that power domains can be employed.
*/
if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
return 0;
pci_disable_device(pdev); pci_disable_device(pdev);
pci_set_power_state(pdev, PCI_D3hot); pci_set_power_state(pdev, PCI_D3hot);
...@@ -796,6 +838,14 @@ static int i915_pm_suspend(struct device *dev) ...@@ -796,6 +838,14 @@ static int i915_pm_suspend(struct device *dev)
return 0; return 0;
} }
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);
return i915_resume_early(drm_dev);
}
static int i915_pm_resume(struct device *dev) static int i915_pm_resume(struct device *dev)
{ {
struct pci_dev *pdev = to_pci_dev(dev); struct pci_dev *pdev = to_pci_dev(dev);
...@@ -817,6 +867,14 @@ static int i915_pm_freeze(struct device *dev) ...@@ -817,6 +867,14 @@ static int i915_pm_freeze(struct device *dev)
return i915_drm_freeze(drm_dev); return i915_drm_freeze(drm_dev);
} }
static int i915_pm_thaw_early(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct drm_device *drm_dev = pci_get_drvdata(pdev);
return i915_drm_thaw_early(drm_dev);
}
static int i915_pm_thaw(struct device *dev) static int i915_pm_thaw(struct device *dev)
{ {
struct pci_dev *pdev = to_pci_dev(dev); struct pci_dev *pdev = to_pci_dev(dev);
...@@ -887,10 +945,14 @@ static int i915_runtime_resume(struct device *device) ...@@ -887,10 +945,14 @@ static int i915_runtime_resume(struct device *device)
static const struct dev_pm_ops i915_pm_ops = { static const struct dev_pm_ops i915_pm_ops = {
.suspend = i915_pm_suspend, .suspend = i915_pm_suspend,
.suspend_late = i915_pm_suspend_late,
.resume_early = i915_pm_resume_early,
.resume = i915_pm_resume, .resume = i915_pm_resume,
.freeze = i915_pm_freeze, .freeze = i915_pm_freeze,
.thaw_early = i915_pm_thaw_early,
.thaw = i915_pm_thaw, .thaw = i915_pm_thaw,
.poweroff = i915_pm_poweroff, .poweroff = i915_pm_poweroff,
.restore_early = i915_pm_resume_early,
.restore = i915_pm_resume, .restore = i915_pm_resume,
.runtime_suspend = i915_runtime_suspend, .runtime_suspend = i915_runtime_suspend,
.runtime_resume = i915_runtime_resume, .runtime_resume = i915_runtime_resume,
...@@ -933,7 +995,7 @@ static struct drm_driver driver = { ...@@ -933,7 +995,7 @@ static struct drm_driver driver = {
/* Used in place of i915_pm_ops for non-DRIVER_MODESET */ /* Used in place of i915_pm_ops for non-DRIVER_MODESET */
.suspend = i915_suspend, .suspend = i915_suspend,
.resume = i915_resume, .resume = i915_resume_legacy,
.device_is_agp = i915_driver_device_is_agp, .device_is_agp = i915_driver_device_is_agp,
.master_create = i915_master_create, .master_create = i915_master_create,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment