From: Daniel Vetter <daniel@ffwll.ch>
To: Imre Deak <imre.deak@intel.com>
Cc: intel-gfx@lists.freedesktop.org
Subject: Re: [PATCH 14/15] drm/i915: vlv: add runtime PM support
Date: Wed, 9 Apr 2014 16:22:22 +0200 [thread overview]
Message-ID: <20140409142222.GA9262@phenom.ffwll.local> (raw)
In-Reply-To: <1396976276-32714-15-git-send-email-imre.deak@intel.com>
On Tue, Apr 08, 2014 at 07:57:55PM +0300, Imre Deak wrote:
> Add runtime PM support for VLV, but leave it disabled. The next patch
> enables it.
>
> The suspend/resume sequence used is based on [1] and [2]. In practice we
> depend on the GT RC6 mechanism to save the HW context depending on the
> render and media power wells. By the time we run the runtime suspend
> callback the display side is also off and the HW context for that is
> managed by the display power domain framework.
>
> Besides the above there are Gunit registers that depend on a system-wide
> power well. This power well goes off once the device enters any of the
> S0i[R123] states. To handle this scenario, save/restore these Gunit
> registers. Note that this is not the complete register set dictated by
> [2], to remove some overhead registers that are known not to be used are
> ignored. Also some registers are fully setup by initialization functions
> called during resume, these are not saved either. The list of registers
> can be further reduced, see the TODO note in the code.
>
> [1] VLV_gfx_clocking_PM_reset_y12w21d3 / "Driver D3 entry/exit"
> [2] VLV2_S0IXRegs
>
> Signed-off-by: Imre Deak <imre.deak@intel.com>
> ---
> drivers/gpu/drm/i915/i915_drv.c | 170 +++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 166 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
> index 9f9d0db..16ca37f 100644
> --- a/drivers/gpu/drm/i915/i915_drv.c
> +++ b/drivers/gpu/drm/i915/i915_drv.c
> @@ -891,19 +891,23 @@ static int i915_pm_poweroff(struct device *dev)
> return i915_drm_freeze(drm_dev);
> }
>
> -static void snb_runtime_suspend(struct drm_i915_private *dev_priv)
> +static int snb_runtime_suspend(struct drm_i915_private *dev_priv)
> {
> struct drm_device *dev = dev_priv->dev;
>
> intel_runtime_pm_disable_interrupts(dev);
> +
> + return 0;
> }
>
> -static void hsw_runtime_suspend(struct drm_i915_private *dev_priv)
> +static int hsw_runtime_suspend(struct drm_i915_private *dev_priv)
> {
> hsw_enable_pc8(dev_priv);
> +
> + return 0;
> }
>
> -static void snb_runtime_resume(struct drm_i915_private *dev_priv)
> +static int snb_runtime_resume(struct drm_i915_private *dev_priv)
> {
> struct drm_device *dev = dev_priv->dev;
>
> @@ -913,11 +917,15 @@ static void snb_runtime_resume(struct drm_i915_private *dev_priv)
> mutex_lock(&dev_priv->rps.hw_lock);
> gen6_update_ring_freq(dev);
> mutex_unlock(&dev_priv->rps.hw_lock);
> +
> + return 0;
> }
>
> -static void hsw_runtime_resume(struct drm_i915_private *dev_priv)
> +static int hsw_runtime_resume(struct drm_i915_private *dev_priv)
> {
> hsw_disable_pc8(dev_priv);
> +
> + return 0;
> }
>
> /*
> @@ -1144,11 +1152,155 @@ int vlv_force_gfx_clock(struct drm_i915_private *dev_priv, bool force_on)
> #undef COND
> }
>
> +static int vlv_allow_gt_wake(struct drm_i915_private *dev_priv, bool allow)
> +{
> + u32 val;
> + int err = 0;
> +
> + val = I915_READ(VLV_GTLC_WAKE_CTRL);
> + val &= ~VLV_GTLC_ALLOWWAKEREQ;
> + if (allow)
> + val |= VLV_GTLC_ALLOWWAKEREQ;
> + I915_WRITE(VLV_GTLC_WAKE_CTRL, val);
> + POSTING_READ(VLV_GTLC_WAKE_CTRL);
> +
> +#define COND (!!(I915_READ(VLV_GTLC_PW_STATUS) & VLV_GTLC_ALLOWWAKEACK) == \
> + allow)
> + err = wait_for(COND, 1);
> + if (err)
> + DRM_ERROR("timeout disabling GT waking\n");
> + return err;
> +#undef COND
> +}
> +
> +static int vlv_wait_for_gt_wells(struct drm_i915_private *dev_priv,
> + bool wait_for_on)
> +{
> + u32 mask;
> + u32 val;
> + int err;
> +
> + mask = VLV_GTLC_PW_MEDIA_STATUS_MASK | VLV_GTLC_PW_RENDER_STATUS_MASK;
> + val = wait_for_on ? mask : 0;
> +#define COND ((I915_READ(VLV_GTLC_PW_STATUS) & mask) == val)
> + if (COND)
> + return 0;
> +
> + DRM_DEBUG_KMS("waiting for GT wells to go %s (%08x)\n",
> + wait_for_on ? "on" : "off",
> + I915_READ(VLV_GTLC_PW_STATUS));
> +
> + /*
> + * RC6 transitioning can be delayed up to 2 msec (see
> + * valleyview_enable_rps), use 3 msec for safety.
> + */
> + err = wait_for(COND, 3);
> + if (err)
> + DRM_ERROR("timeout waiting for GT wells to go %s\n",
> + wait_for_on ? "on" : "off");
> +
> + return err;
> +#undef COND
> +}
> +
> +static void vlv_check_no_gt_access(struct drm_i915_private *dev_priv)
> +{
> + if (!(I915_READ(VLV_GTLC_PW_STATUS) & VLV_GTLC_ALLOWWAKEERR))
> + return;
> +
> + DRM_ERROR("GT register access while GT waking disabled\n");
> + I915_WRITE(VLV_GTLC_PW_STATUS, VLV_GTLC_ALLOWWAKEERR);
> +}
> +
> +static int vlv_runtime_suspend(struct drm_i915_private *dev_priv)
> +{
> + struct drm_device *dev = dev_priv->dev;
> + u32 mask;
> + int err;
> +
> + if (WARN_ON(!valleyview_rc6_enabled(dev)))
> + return -ENODEV;
> +
> + intel_runtime_pm_disable_interrupts(dev);
> + cancel_work_sync(&dev_priv->rps.work);
> +
> + /*
> + * Bspec defines the following GT well on flags as debug only, so
> + * don't treat them as hard failures.
> + */
> + (void)vlv_wait_for_gt_wells(dev_priv, false);
> +
> + mask = VLV_GTLC_RENDER_CTX_EXISTS | VLV_GTLC_MEDIA_CTX_EXISTS;
> + WARN_ON((I915_READ(VLV_GTLC_WAKE_CTRL) & mask) != mask);
> +
> + vlv_check_no_gt_access(dev_priv);
> +
> + err = vlv_force_gfx_clock(dev_priv, true);
> + if (err)
> + goto err1;
> +
> + err = vlv_allow_gt_wake(dev_priv, false);
> + if (err)
> + goto err2;
> + vlv_save_gunit_s0ix_state(dev_priv);
> +
> + err = vlv_force_gfx_clock(dev_priv, false);
> + if (err)
> + goto err2;
> +
> + return 0;
> +
> +err2:
> + /* For safety always re-enable waking and disable gfx clock forcing */
> + vlv_allow_gt_wake(dev_priv, true);
> +err1:
> + vlv_force_gfx_clock(dev_priv, false);
> + intel_runtime_pm_restore_interrupts(dev);
> +
> + return err;
> +}
> +
> +static int vlv_runtime_resume(struct drm_i915_private *dev_priv)
> +{
> + struct drm_device *dev = dev_priv->dev;
> + int err;
> + int ret;
> +
> + /*
> + * If any of the steps fail just try to continue, that's the best we
> + * can do at this point. Return the first error code (which will also
> + * leave RPM permanentyl disabled).
> + */
> + ret = vlv_force_gfx_clock(dev_priv, true);
> +
> + vlv_restore_gunit_s0ix_state(dev_priv);
> +
> + err = vlv_allow_gt_wake(dev_priv, true);
> + if (!ret)
> + ret = err;
> +
> + err = vlv_force_gfx_clock(dev_priv, false);
> + if (!ret)
> + ret = err;
> +
> + vlv_check_no_gt_access(dev_priv);
> +
> + intel_init_clock_gating(dev);
> + intel_reset_gt_powersave(dev);
> + i915_gem_init_swizzling(dev);
> + i915_gem_restore_fences(dev);
> +
> + intel_runtime_pm_restore_interrupts(dev);
> +
> + return ret;
> +}
> +
> static int intel_runtime_suspend(struct device *device)
> {
> struct pci_dev *pdev = to_pci_dev(device);
> struct drm_device *dev = pci_get_drvdata(pdev);
> struct drm_i915_private *dev_priv = dev->dev_private;
> + int ret = 0;
>
> if (WARN_ON_ONCE(!dev_priv->rps.enabled))
> return -ENODEV;
> @@ -1162,9 +1314,17 @@ static int intel_runtime_suspend(struct device *device)
> snb_runtime_suspend(dev_priv);
> else if (IS_HASWELL(dev) || IS_BROADWELL(dev))
> hsw_runtime_suspend(dev_priv);
> + else if (IS_VALLEYVIEW(dev))
> + ret = vlv_runtime_suspend(dev_priv);
> else
> WARN_ON(1);
>
> + if (ret) {
> + DRM_ERROR("Runtime suspend failed, disabling it\n");
> +
> + return ret;
> + }
> +
> i915_gem_release_all_mmaps(dev_priv);
>
> del_timer_sync(&dev_priv->gpu_error.hangcheck_timer);
> @@ -1200,6 +1360,8 @@ static int intel_runtime_resume(struct device *device)
> snb_runtime_resume(dev_priv);
> else if (IS_HASWELL(dev) || IS_BROADWELL(dev))
> hsw_runtime_resume(dev_priv);
> + else if (IS_VALLEYVIEW(dev))
> + vlv_runtime_resume(dev_priv);
Golden rule of refactoring: The 3rd guy gets to cleanup the mess. Imo
it's time to refactor the common parts form these platform functions out
and move them into generic code, and only call down into platform code as
needed. If we don't do that we'll have completely hell due to slight
differences in ordering between platforms.
Also I think we should try to share as much code as possible with the
other setup/teardowns paths, i.e. driver load/unload, system
suspend/resume and gpu reset.
Thanks, Daniel
> else
> WARN_ON(1);
>
> --
> 1.8.4
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx
--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch
next prev parent reply other threads:[~2014-04-09 14:22 UTC|newest]
Thread overview: 40+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-04-08 16:57 [PATCH 00/15] vlv: add support for RPM Imre Deak
2014-04-08 16:57 ` [PATCH 01/15] drm/i915: vlv: clean up GTLC wake control/status register macros Imre Deak
2014-04-16 21:08 ` Rodrigo Vivi
2014-04-16 21:20 ` Imre Deak
2014-04-08 16:57 ` [PATCH 02/15] drm/i915: vlv: clear master interrupt flag when disabling interrupts Imre Deak
2014-04-08 16:57 ` [PATCH 03/15] drm/i915: vlv: add RC6 residency counters Imre Deak
2014-04-08 16:57 ` [PATCH 04/15] drm/i915: fix rc6 status debug print Imre Deak
2014-04-08 16:57 ` [PATCH 05/15] drm/i915: take init power domain for sysfs/debugfs entries where needed Imre Deak
2014-04-08 19:34 ` [PATCH v2 5/15] " Imre Deak
2014-04-09 14:15 ` Daniel Vetter
2014-04-09 14:21 ` Paulo Zanoni
2014-04-09 14:21 ` Imre Deak
2014-04-09 16:06 ` Ville Syrjälä
2014-04-09 16:30 ` Imre Deak
2014-04-09 16:35 ` Daniel Vetter
2014-04-08 16:57 ` [PATCH 06/15] drm/i915: get init power domain for gpu error state capture Imre Deak
2014-04-09 14:17 ` Daniel Vetter
2014-04-08 16:57 ` [PATCH 07/15] drm/i915: vlv: check port power domain instead of only D0 for eDP VDD on Imre Deak
2014-04-09 14:32 ` Paulo Zanoni
2014-04-09 14:50 ` Imre Deak
2014-04-08 16:57 ` [PATCH 08/15] drm/i915: vlv: setup RPS min/max frequencies once during init time Imre Deak
2014-04-08 16:57 ` [PATCH 09/15] drm/i915: vlv: factor out vlv_force_gfx_clock Imre Deak
2014-04-08 16:57 ` [PATCH 10/15] drm/i915: disable runtime PM until delayed RPS/RC6 enabling completes Imre Deak
2014-04-09 14:19 ` Daniel Vetter
2014-04-09 14:38 ` Imre Deak
2014-04-09 16:38 ` Daniel Vetter
2014-04-09 16:43 ` Daniel Vetter
2014-04-08 16:57 ` [PATCH 11/15] drm/i915: vlv: disable RPM if RC6 is not enabled Imre Deak
2014-04-09 14:36 ` Paulo Zanoni
2014-04-09 14:59 ` Imre Deak
2014-04-09 16:41 ` Daniel Vetter
2014-04-08 16:57 ` [PATCH 12/15] drm/i915: add various missing GTI/Gunit register definitions Imre Deak
2014-04-08 16:57 ` [PATCH 13/15] drm/i915: vlv: add gunit s0ix save/restore helpers Imre Deak
2014-04-08 16:57 ` [PATCH 14/15] drm/i915: vlv: add runtime PM support Imre Deak
2014-04-09 14:22 ` Daniel Vetter [this message]
2014-04-09 15:43 ` Imre Deak
2014-04-09 16:45 ` Daniel Vetter
2014-04-09 16:40 ` Paulo Zanoni
2014-04-09 16:47 ` Imre Deak
2014-04-08 16:57 ` [PATCH 15/15] drm/i915: vlv: enable RPM Imre Deak
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20140409142222.GA9262@phenom.ffwll.local \
--to=daniel@ffwll.ch \
--cc=imre.deak@intel.com \
--cc=intel-gfx@lists.freedesktop.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox