Skip to content

Commit

Permalink
drm/i915: Refactor intel_display_set_init_power() logic
Browse files Browse the repository at this point in the history
The device global init_power_on flag is somewhat arbitrary and makes
debugging power refcounting problems difficult. Instead arrange things
so that all display power domain get has a corresponding put call. After
this change we have the following sequences:

driver loading:
intel_power_domains_init_hw();
<other init steps>
intel_power_domains_enable();

driver unloading:
intel_power_domains_disable();
<other uninit steps>
intel_power_domains_fini_hw();

system suspend:
intel_power_domains_disable();
<other suspend steps>
intel_power_domains_suspend();

system resume:
intel_power_domains_resume();
<other resume steps>
intel_power_domains_enable();

at other times while the driver is loaded:
intel_display_power_get();
...
intel_display_power_put();

Suggested-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Chris Wilson <chris@chris-wilson.co.uk>
Signed-off-by: Imre Deak <imre.deak@intel.com>
Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
Link: https://patchwork.freedesktop.org/patch/msgid/20180816123757.3286-2-imre.deak@intel.com
  • Loading branch information
Imre Deak committed Aug 16, 2018
1 parent 07d8057 commit 2cd9a68
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 78 deletions.
65 changes: 30 additions & 35 deletions drivers/gpu/drm/i915/i915_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -1282,6 +1282,7 @@ static void i915_driver_register(struct drm_i915_private *dev_priv)
if (INTEL_INFO(dev_priv)->num_pipes)
drm_kms_helper_poll_init(dev);

intel_power_domains_enable(dev_priv);
intel_runtime_pm_enable(dev_priv);
}

Expand All @@ -1292,6 +1293,7 @@ static void i915_driver_register(struct drm_i915_private *dev_priv)
static void i915_driver_unregister(struct drm_i915_private *dev_priv)
{
intel_runtime_pm_disable(dev_priv);
intel_power_domains_disable(dev_priv);

intel_fbdev_unregister(dev_priv);
intel_audio_deinit(dev_priv);
Expand Down Expand Up @@ -1374,7 +1376,7 @@ int i915_driver_load(struct pci_dev *pdev, const struct pci_device_id *ent)
if (ret < 0)
goto out_pci_disable;

intel_runtime_pm_get(dev_priv);
disable_rpm_wakeref_asserts(dev_priv);

ret = i915_driver_init_mmio(dev_priv);
if (ret < 0)
Expand Down Expand Up @@ -1404,7 +1406,7 @@ int i915_driver_load(struct pci_dev *pdev, const struct pci_device_id *ent)

intel_init_ipc(dev_priv);

intel_runtime_pm_put(dev_priv);
enable_rpm_wakeref_asserts(dev_priv);

i915_welcome_messages(dev_priv);

Expand All @@ -1415,7 +1417,7 @@ int i915_driver_load(struct pci_dev *pdev, const struct pci_device_id *ent)
out_cleanup_mmio:
i915_driver_cleanup_mmio(dev_priv);
out_runtime_pm_put:
intel_runtime_pm_put(dev_priv);
enable_rpm_wakeref_asserts(dev_priv);
i915_driver_cleanup_early(dev_priv);
out_pci_disable:
pci_disable_device(pdev);
Expand All @@ -1433,7 +1435,7 @@ void i915_driver_unload(struct drm_device *dev)
struct drm_i915_private *dev_priv = to_i915(dev);
struct pci_dev *pdev = dev_priv->drm.pdev;

intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
disable_rpm_wakeref_asserts(dev_priv);

i915_driver_unregister(dev_priv);

Expand Down Expand Up @@ -1465,7 +1467,8 @@ void i915_driver_unload(struct drm_device *dev)
i915_driver_cleanup_hw(dev_priv);
i915_driver_cleanup_mmio(dev_priv);

intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
enable_rpm_wakeref_asserts(dev_priv);

WARN_ON(atomic_read(&dev_priv->runtime_pm.wakeref_count));
}

Expand Down Expand Up @@ -1575,7 +1578,7 @@ static int i915_drm_suspend(struct drm_device *dev)

/* We do a lot of poking in a lot of registers, make sure they work
* properly. */
intel_display_set_init_power(dev_priv, true);
intel_power_domains_disable(dev_priv);

drm_kms_helper_poll_disable(dev);

Expand Down Expand Up @@ -1612,6 +1615,18 @@ static int i915_drm_suspend(struct drm_device *dev)
return 0;
}

static enum i915_drm_suspend_mode
get_suspend_mode(struct drm_i915_private *dev_priv, bool hibernate)
{
if (hibernate)
return I915_DRM_SUSPEND_HIBERNATE;

if (suspend_to_idle(dev_priv))
return I915_DRM_SUSPEND_IDLE;

return I915_DRM_SUSPEND_MEM;
}

static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation)
{
struct drm_i915_private *dev_priv = to_i915(dev);
Expand All @@ -1622,21 +1637,10 @@ static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation)

i915_gem_suspend_late(dev_priv);

intel_display_set_init_power(dev_priv, false);
intel_uncore_suspend(dev_priv);

/*
* In case of firmware assisted context save/restore don't manually
* deinit the power domains. This also means the CSR/DMC firmware will
* stay active, it will power down any HW resources as required and
* also enable deeper system power states that would be blocked if the
* firmware was inactive.
*/
if (IS_GEN9_LP(dev_priv) || hibernation || !suspend_to_idle(dev_priv) ||
dev_priv->csr.dmc_payload == NULL) {
intel_power_domains_suspend(dev_priv);
dev_priv->power_domains_suspended = true;
}
intel_power_domains_suspend(dev_priv,
get_suspend_mode(dev_priv, hibernation));

ret = 0;
if (IS_GEN9_LP(dev_priv))
Expand All @@ -1648,10 +1652,7 @@ static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation)

if (ret) {
DRM_ERROR("Suspend complete failed: %d\n", ret);
if (dev_priv->power_domains_suspended) {
intel_power_domains_init_hw(dev_priv, true);
dev_priv->power_domains_suspended = false;
}
intel_power_domains_resume(dev_priv);

goto out;
}
Expand Down Expand Up @@ -1768,6 +1769,8 @@ static int i915_drm_resume(struct drm_device *dev)

intel_opregion_notify_adapter(dev_priv, PCI_D0);

intel_power_domains_enable(dev_priv);

enable_rpm_wakeref_asserts(dev_priv);

return 0;
Expand Down Expand Up @@ -1802,7 +1805,7 @@ static int i915_drm_resume_early(struct drm_device *dev)
ret = pci_set_power_state(pdev, PCI_D0);
if (ret) {
DRM_ERROR("failed to set PCI D0 power state (%d)\n", ret);
goto out;
return ret;
}

/*
Expand All @@ -1818,10 +1821,8 @@ static int i915_drm_resume_early(struct drm_device *dev)
* depend on the device enable refcount we can't anyway depend on them
* disabling/enabling the device.
*/
if (pci_enable_device(pdev)) {
ret = -EIO;
goto out;
}
if (pci_enable_device(pdev))
return -EIO;

pci_set_master(pdev);

Expand All @@ -1844,18 +1845,12 @@ static int i915_drm_resume_early(struct drm_device *dev)

intel_uncore_sanitize(dev_priv);

if (dev_priv->power_domains_suspended)
intel_power_domains_init_hw(dev_priv, true);
else
intel_display_set_init_power(dev_priv, true);
intel_power_domains_resume(dev_priv);

intel_engines_sanitize(dev_priv);

enable_rpm_wakeref_asserts(dev_priv);

out:
dev_priv->power_domains_suspended = false;

return ret;
}

Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/i915/i915_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -935,8 +935,8 @@ struct i915_power_domains {
* Power wells needed for initialization at driver init and suspend
* time are on. They are kept on until after the first modeset.
*/
bool init_power_on;
bool initializing;
bool display_core_suspended;
int power_well_count;

struct mutex lock;
Expand Down
5 changes: 4 additions & 1 deletion drivers/gpu/drm/i915/intel_display.c
Original file line number Diff line number Diff line change
Expand Up @@ -15846,6 +15846,8 @@ intel_modeset_setup_hw_state(struct drm_device *dev,
struct intel_encoder *encoder;
int i;

intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);

intel_early_display_was(dev_priv);
intel_modeset_readout_hw_state(dev);

Expand Down Expand Up @@ -15900,7 +15902,8 @@ intel_modeset_setup_hw_state(struct drm_device *dev,
if (WARN_ON(put_domains))
modeset_put_power_domains(dev_priv, put_domains);
}
intel_display_set_init_power(dev_priv, false);

intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);

intel_power_domains_verify_state(dev_priv);

Expand Down
15 changes: 12 additions & 3 deletions drivers/gpu/drm/i915/intel_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -1954,7 +1954,18 @@ int intel_power_domains_init(struct drm_i915_private *);
void intel_power_domains_cleanup(struct drm_i915_private *dev_priv);
void intel_power_domains_init_hw(struct drm_i915_private *dev_priv, bool resume);
void intel_power_domains_fini_hw(struct drm_i915_private *dev_priv);
void intel_power_domains_suspend(struct drm_i915_private *dev_priv);
void intel_power_domains_enable(struct drm_i915_private *dev_priv);
void intel_power_domains_disable(struct drm_i915_private *dev_priv);

enum i915_drm_suspend_mode {
I915_DRM_SUSPEND_IDLE,
I915_DRM_SUSPEND_MEM,
I915_DRM_SUSPEND_HIBERNATE,
};

void intel_power_domains_suspend(struct drm_i915_private *dev_priv,
enum i915_drm_suspend_mode);
void intel_power_domains_resume(struct drm_i915_private *dev_priv);
void intel_power_domains_verify_state(struct drm_i915_private *dev_priv);
void bxt_display_core_init(struct drm_i915_private *dev_priv, bool resume);
void bxt_display_core_uninit(struct drm_i915_private *dev_priv);
Expand Down Expand Up @@ -2037,8 +2048,6 @@ bool intel_runtime_pm_get_if_in_use(struct drm_i915_private *dev_priv);
void intel_runtime_pm_get_noresume(struct drm_i915_private *dev_priv);
void intel_runtime_pm_put(struct drm_i915_private *dev_priv);

void intel_display_set_init_power(struct drm_i915_private *dev, bool enable);

void chv_phy_powergate_lanes(struct intel_encoder *encoder,
bool override, unsigned int mask);
bool chv_phy_powergate_ch(struct drm_i915_private *dev_priv, enum dpio_phy phy,
Expand Down
Loading

0 comments on commit 2cd9a68

Please sign in to comment.