[Intel-gfx] [PATCH 02/16] drm/i915: make PC8 be part of runtime PM suspend/resume
Daniel Vetter
daniel at ffwll.ch
Wed Mar 19 16:45:29 CET 2014
On Wed, Mar 19, 2014 at 05:07:53PM +0200, Imre Deak wrote:
> On Fri, 2014-03-07 at 20:08 -0300, Paulo Zanoni wrote:
> > From: Paulo Zanoni <paulo.r.zanoni at intel.com>
> >
> > Currently, when our driver becomes idle for i915.pc8_timeout (default:
> > 5s) we enable PC8, so we save some power, but not everything we can.
> > Then, while PC8 is enabled, if we stay idle for more
> > autosuspend_delay_ms (default: 10s) we'll enter runtime PM and put the
> > graphics device in D3 state, saving even more power. The two features
> > are separate things with increasing levels of power savings, but if we
> > disable PC8 we'll never get into D3.
> >
> > While from the modularity point of view it would be nice to keep these
> > features as separate, we have reasons to merge them:
> > - We are not aware of anybody wanting a "PC8 without D3" environment.
> > - If we keep both features as separate, we'll have to to test both
> > PC8 and PC8+D3 code paths. We're already having a major pain to
> > make QA do automated testing of just one thing, testing both paths
> > will cost even more.
> > - Only Haswell+ supports PC8, so if we want to add runtime PM support
> > to, for example, IVB, we'll have to copy some code from the PC8
> > feature to runtime PM, so merging both features as a single thing
> > will make it easier for enabling runtime PM on other platforms.
> >
> > This patch only does the very basic steps required to have PC8 and
> > runtime PM merged on a single feature: the next patches will take care
> > of cleaning up everything.
> >
> > v2: - Rebase.
> > v3: - Rebase.
> > - Fully remove the deprecated i915 params since Daniel doesn't
> > consider them as part of the ABI.
> > v4: - Rebase.
> > - Fix typo in the commit message.
> > v5: - Rebase, again.
> > - Add a huge comment explaining the different forcewake usage
> > (Chris, Daniel).
> > - Use open-coded forcewake functions (Daniel).
> >
> > Signed-off-by: Paulo Zanoni <paulo.r.zanoni at intel.com>
> > ---
> > drivers/gpu/drm/i915/i915_dma.c | 2 --
> > drivers/gpu/drm/i915/i915_drv.c | 8 +++++
> > drivers/gpu/drm/i915/i915_drv.h | 7 ++--
> > drivers/gpu/drm/i915/i915_params.c | 10 ------
> > drivers/gpu/drm/i915/intel_display.c | 65 ++++++++++++++++--------------------
> > drivers/gpu/drm/i915/intel_drv.h | 3 +-
> > drivers/gpu/drm/i915/intel_pm.c | 1 -
> > 7 files changed, 43 insertions(+), 53 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
> > index e4d2b9f..6aa23af 100644
> > --- a/drivers/gpu/drm/i915/i915_dma.c
> > +++ b/drivers/gpu/drm/i915/i915_dma.c
> > @@ -1822,8 +1822,6 @@ int i915_driver_unload(struct drm_device *dev)
> > cancel_work_sync(&dev_priv->gpu_error.work);
> > i915_destroy_error_state(dev);
> >
> > - cancel_delayed_work_sync(&dev_priv->pc8.enable_work);
> > -
> > if (dev->pdev->msi_enabled)
> > pci_disable_msi(dev->pdev);
> >
> > diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
> > index 658fe24..6178c95 100644
> > --- a/drivers/gpu/drm/i915/i915_drv.c
> > +++ b/drivers/gpu/drm/i915/i915_drv.c
> > @@ -848,6 +848,9 @@ static int i915_runtime_suspend(struct device *device)
> >
> > DRM_DEBUG_KMS("Suspending device\n");
> >
> > + if (HAS_PC8(dev))
> > + __hsw_do_enable_pc8(dev_priv);
> > +
> > i915_gem_release_all_mmaps(dev_priv);
> >
> > del_timer_sync(&dev_priv->gpu_error.hangcheck_timer);
> > @@ -862,6 +865,7 @@ static int i915_runtime_suspend(struct device *device)
> > */
> > intel_opregion_notify_adapter(dev, PCI_D1);
> >
> > + DRM_DEBUG_KMS("Device suspended\n");
> > return 0;
> > }
> >
> > @@ -878,6 +882,10 @@ static int i915_runtime_resume(struct device *device)
> > intel_opregion_notify_adapter(dev, PCI_D0);
> > dev_priv->pm.suspended = false;
> >
> > + if (HAS_PC8(dev))
> > + __hsw_do_disable_pc8(dev_priv);
> > +
> > + DRM_DEBUG_KMS("Device resumed\n");
> > return 0;
> > }
> >
> > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> > index 2a319ba..a5f1780 100644
> > --- a/drivers/gpu/drm/i915/i915_drv.h
> > +++ b/drivers/gpu/drm/i915/i915_drv.h
> > @@ -1335,6 +1335,10 @@ struct ilk_wm_values {
> > /*
> > * This struct tracks the state needed for the Package C8+ feature.
> > *
> > + * TODO: we're merging the Package C8+ feature with the runtime PM support. To
> > + * avoid having to update the documentation at each patch of the series, we'll
> > + * do a final update at the end.
> > + *
> > * Package states C8 and deeper are really deep PC states that can only be
> > * reached when all the devices on the system allow it, so even if the graphics
> > * device allows PC8+, it doesn't mean the system will actually get to these
> > @@ -1388,7 +1392,6 @@ struct i915_package_c8 {
> > bool enabled;
> > int disable_count;
> > struct mutex lock;
> > - struct delayed_work enable_work;
> >
> > struct {
> > uint32_t deimr;
> > @@ -2092,8 +2095,6 @@ struct i915_params {
> > unsigned int preliminary_hw_support;
> > int disable_power_well;
> > int enable_ips;
> > - int enable_pc8;
> > - int pc8_timeout;
> > int invert_brightness;
> > int enable_cmd_parser;
> > /* leave bools at the end to not create holes */
> > diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c
> > index a66ffb6..d1d7980 100644
> > --- a/drivers/gpu/drm/i915/i915_params.c
> > +++ b/drivers/gpu/drm/i915/i915_params.c
> > @@ -42,8 +42,6 @@ struct i915_params i915 __read_mostly = {
> > .disable_power_well = 1,
> > .enable_ips = 1,
> > .fastboot = 0,
> > - .enable_pc8 = 1,
> > - .pc8_timeout = 5000,
> > .prefault_disable = 0,
> > .reset = true,
> > .invert_brightness = 0,
> > @@ -135,14 +133,6 @@ module_param_named(fastboot, i915.fastboot, bool, 0600);
> > MODULE_PARM_DESC(fastboot,
> > "Try to skip unnecessary mode sets at boot time (default: false)");
> >
> > -module_param_named(enable_pc8, i915.enable_pc8, int, 0600);
> > -MODULE_PARM_DESC(enable_pc8,
> > - "Enable support for low power package C states (PC8+) (default: true)");
> > -
> > -module_param_named(pc8_timeout, i915.pc8_timeout, int, 0600);
> > -MODULE_PARM_DESC(pc8_timeout,
> > - "Number of msecs of idleness required to enter PC8+ (default: 5000)");
> > -
> > module_param_named(prefault_disable, i915.prefault_disable, bool, 0600);
> > MODULE_PARM_DESC(prefault_disable,
> > "Disable page prefaulting for pread/pwrite/reloc (default:false). "
> > diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
> > index 9c3e2c5..ab02848 100644
> > --- a/drivers/gpu/drm/i915/intel_display.c
> > +++ b/drivers/gpu/drm/i915/intel_display.c
> > @@ -6726,6 +6726,7 @@ static void hsw_disable_lcpll(struct drm_i915_private *dev_priv,
> > static void hsw_restore_lcpll(struct drm_i915_private *dev_priv)
> > {
> > uint32_t val;
> > + unsigned long irqflags;
> >
> > val = I915_READ(LCPLL_CTL);
> >
> > @@ -6733,9 +6734,22 @@ static void hsw_restore_lcpll(struct drm_i915_private *dev_priv)
> > LCPLL_POWER_DOWN_ALLOW)) == LCPLL_PLL_LOCK)
> > return;
> >
> > - /* Make sure we're not on PC8 state before disabling PC8, otherwise
> > - * we'll hang the machine! */
> > - gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
> > + /*
> > + * Make sure we're not on PC8 state before disabling PC8, otherwise
>
> While at it the above comment could be clarified. For me 'before
> enabling PLL, which also disables PC8' would be clearer, if that's what
> was meant.
I think we can do this comment polishing later on.
> > + * we'll hang the machine. To prevent PC8 state, just enable force_wake.
> > + *
> > + * The other problem is that hsw_restore_lcpll() is called as part of
> > + * the runtime PM resume sequence, so we can't just call
> > + * gen6_gt_force_wake_get() because that function calls
> > + * intel_runtime_pm_get(), and we can't change the runtime PM refcount
> > + * while we are on the resume sequence. So to solve this problem we have
> > + * to call special forcewake code that doesn't touch runtime PM and
> > + * doesn't enable the forcewake delayed work.
> > + */
> > + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
> > + if (dev_priv->uncore.forcewake_count++ == 0)
> > + dev_priv->uncore.funcs.force_wake_get(dev_priv, FORCEWAKE_ALL);
> > + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
> >
> > if (val & LCPLL_POWER_DOWN_ALLOW) {
> > val &= ~LCPLL_POWER_DOWN_ALLOW;
> > @@ -6769,14 +6783,20 @@ static void hsw_restore_lcpll(struct drm_i915_private *dev_priv)
> > DRM_ERROR("Switching back to LCPLL failed\n");
> > }
> >
> > - gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
> > + /* See the big comment above. */
> > + spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
> > + if (--dev_priv->uncore.forcewake_count == 0)
> > + dev_priv->uncore.funcs.force_wake_put(dev_priv, FORCEWAKE_ALL);
> > + spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
>
> For clarity I would group these in separate functions with the rest of
> force wake helpers in intel_uncore.c.
tbh we currently have a rather big mess with all our forcewake functions
and the setup/init code. Before we encapsulate things like crazy I think
we should work out all the existing little bugs and races we have :(
>
> Otherwise looks good, so with the above fixed:
> Reviewed-by: Imre Deak <imre.deak at intel.com>
Thanks for patches&review, merged it all to dinq.
-Daniel
--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
More information about the Intel-gfx
mailing list