drm/i915: get a runtime PM ref for the deferred GT powersave enabling

At least on VLV but probably on other platforms too we depend on RC6
being enabled for RPM, so disable RPM until the delayed RC6 enabling
completes.

v2:
- explain the reason for the _noresume version of RPM get (Daniel)
- use the simpler 'if (schedule_work()) rpm_get();' instead of
  'if (!cancel_work_sync()) rpm_get(); schedule_work();'

Signed-off-by: Imre Deak <imre.deak@intel.com>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
This commit is contained in:
Imre Deak 2014-04-14 20:24:29 +03:00 committed by Daniel Vetter
parent dc1d0136a4
commit c6df39b5ea
3 changed files with 38 additions and 3 deletions

View File

@ -782,7 +782,7 @@ int i915_reset(struct drm_device *dev)
* previous concerns that it doesn't respond well to some forms
* of re-init after reset. */
if (INTEL_INFO(dev)->gen > 5)
intel_enable_gt_powersave(dev);
intel_reset_gt_powersave(dev);
intel_hpd_init(dev);
} else {
@ -951,6 +951,9 @@ static int intel_runtime_suspend(struct device *device)
struct drm_device *dev = pci_get_drvdata(pdev);
struct drm_i915_private *dev_priv = dev->dev_private;
if (WARN_ON_ONCE(!dev_priv->rps.enabled))
return -ENODEV;
WARN_ON(!HAS_RUNTIME_PM(dev));
assert_force_wake_inactive(dev_priv);

View File

@ -925,6 +925,7 @@ void intel_init_gt_powersave(struct drm_device *dev);
void intel_cleanup_gt_powersave(struct drm_device *dev);
void intel_enable_gt_powersave(struct drm_device *dev);
void intel_disable_gt_powersave(struct drm_device *dev);
void intel_reset_gt_powersave(struct drm_device *dev);
void ironlake_teardown_rc6(struct drm_device *dev);
void gen6_update_ring_freq(struct drm_device *dev);
void gen6_rps_idle(struct drm_i915_private *dev_priv);
@ -932,6 +933,7 @@ void gen6_rps_boost(struct drm_i915_private *dev_priv);
void intel_aux_display_runtime_get(struct drm_i915_private *dev_priv);
void intel_aux_display_runtime_put(struct drm_i915_private *dev_priv);
void intel_runtime_pm_get(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_init_runtime_pm(struct drm_i915_private *dev_priv);
void intel_fini_runtime_pm(struct drm_i915_private *dev_priv);

View File

@ -4549,6 +4549,8 @@ static void intel_gen6_powersave_work(struct work_struct *work)
}
dev_priv->rps.enabled = true;
mutex_unlock(&dev_priv->rps.hw_lock);
intel_runtime_pm_put(dev_priv);
}
void intel_enable_gt_powersave(struct drm_device *dev)
@ -4566,12 +4568,28 @@ void intel_enable_gt_powersave(struct drm_device *dev)
* PCU communication is slow and this doesn't need to be
* done at any specific time, so do this out of our fast path
* to make resume and init faster.
*
* We depend on the HW RC6 power context save/restore
* mechanism when entering D3 through runtime PM suspend. So
* disable RPM until RPS/RC6 is properly setup. We can only
* get here via the driver load/system resume/runtime resume
* paths, so the _noresume version is enough (and in case of
* runtime resume it's necessary).
*/
schedule_delayed_work(&dev_priv->rps.delayed_resume_work,
round_jiffies_up_relative(HZ));
if (schedule_delayed_work(&dev_priv->rps.delayed_resume_work,
round_jiffies_up_relative(HZ)))
intel_runtime_pm_get_noresume(dev_priv);
}
}
void intel_reset_gt_powersave(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
dev_priv->rps.enabled = false;
intel_enable_gt_powersave(dev);
}
static void ibx_init_clock_gating(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@ -6025,6 +6043,18 @@ void intel_runtime_pm_get(struct drm_i915_private *dev_priv)
WARN(dev_priv->pm.suspended, "Device still suspended.\n");
}
void intel_runtime_pm_get_noresume(struct drm_i915_private *dev_priv)
{
struct drm_device *dev = dev_priv->dev;
struct device *device = &dev->pdev->dev;
if (!HAS_RUNTIME_PM(dev))
return;
WARN(dev_priv->pm.suspended, "Getting nosync-ref while suspended.\n");
pm_runtime_get_noresume(device);
}
void intel_runtime_pm_put(struct drm_i915_private *dev_priv)
{
struct drm_device *dev = dev_priv->dev;