diff mbox series

drm/i915: Disable LP3 watermarks on all SNB machines

Message ID 20181113181023.9639-1-ville.syrjala@linux.intel.com (mailing list archive)
State New, archived
Headers show
Series drm/i915: Disable LP3 watermarks on all SNB machines | expand

Commit Message

Ville Syrjälä Nov. 13, 2018, 6:10 p.m. UTC
From: Ville Syrjälä <ville.syrjala@linux.intel.com>

I have a Thinkpad X220 Tablet in my hands that is losing vblank
interrupts whenever LP3 watermarks are used.

If I nudge the latency value written to the WM3 register just
by one in either direction the problem disappears. That to me
suggests that the punit will not enter the corrsponding
powersave mode (MPLL shutdown IIRC) unless the latency value
in the register matches exactly what we read from SSKPD. Ie.
it's not really a latency value but rather just a cookie
by which the punit can identify the desired power saving state.
On HSW/BDW this was changed such that we actually just write
the WM level number into those bits, which makes much more
sense given the observed behaviour.

We could try to handle this by disallowing LP3 watermarks
only when vblank interrupts are enabled but we'd first have
to prove that only vblank interrupts are affected, which
seems unlikely. Also we can't grab the wm mutex from the
vblank enable/disable hooks because those are called with
various spinlocks held. Thus we'd have to redesigne the
watermark locking. So to play it safe and keep the code
simple we simply disable LP3 watermarks on all SNB machines.

To do that we simply zero out the latency values for
watermark level 3, and we adjust the watermark computation
to check for that. The behaviour now matches that of the
g4x/vlv/skl wm code in the presence of a zeroed latency
value.

Cc: stable@vger.kernel.org
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=101269
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=103713
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_pm.c | 41 ++++++++++++++++++++++++++++++++-
 1 file changed, 40 insertions(+), 1 deletion(-)

Comments

Chris Wilson Nov. 13, 2018, 6:25 p.m. UTC | #1
Quoting Ville Syrjala (2018-11-13 18:10:23)
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> I have a Thinkpad X220 Tablet in my hands that is losing vblank
> interrupts whenever LP3 watermarks are used.
> 
> If I nudge the latency value written to the WM3 register just
> by one in either direction the problem disappears. That to me
> suggests that the punit will not enter the corrsponding
> powersave mode (MPLL shutdown IIRC) unless the latency value
> in the register matches exactly what we read from SSKPD. Ie.
> it's not really a latency value but rather just a cookie
> by which the punit can identify the desired power saving state.
> On HSW/BDW this was changed such that we actually just write
> the WM level number into those bits, which makes much more
> sense given the observed behaviour.
> 
> We could try to handle this by disallowing LP3 watermarks
> only when vblank interrupts are enabled but we'd first have
> to prove that only vblank interrupts are affected, which
> seems unlikely. Also we can't grab the wm mutex from the
> vblank enable/disable hooks because those are called with
> various spinlocks held. Thus we'd have to redesigne the
> watermark locking. So to play it safe and keep the code
> simple we simply disable LP3 watermarks on all SNB machines.
> 
> To do that we simply zero out the latency values for
> watermark level 3, and we adjust the watermark computation
> to check for that. The behaviour now matches that of the
> g4x/vlv/skl wm code in the presence of a zeroed latency
> value.
> 
> Cc: stable@vger.kernel.org
> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=101269
> Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=103713
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/intel_pm.c | 41 ++++++++++++++++++++++++++++++++-
>  1 file changed, 40 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> index 27498ded4949..ef1ae2ede379 100644
> --- a/drivers/gpu/drm/i915/intel_pm.c
> +++ b/drivers/gpu/drm/i915/intel_pm.c
> @@ -2493,6 +2493,9 @@ static uint32_t ilk_compute_pri_wm(const struct intel_crtc_state *cstate,
>         uint32_t method1, method2;
>         int cpp;
>  
> +       if (mem_value == 0)
> +               return USHRT_MAX;
> +
>         if (!intel_wm_plane_visible(cstate, pstate))
>                 return 0;
>  
> @@ -2522,6 +2525,9 @@ static uint32_t ilk_compute_spr_wm(const struct intel_crtc_state *cstate,
>         uint32_t method1, method2;
>         int cpp;
>  
> +       if (mem_value == 0)
> +               return USHRT_MAX;
> +
>         if (!intel_wm_plane_visible(cstate, pstate))
>                 return 0;
>  
> @@ -2545,6 +2551,9 @@ static uint32_t ilk_compute_cur_wm(const struct intel_crtc_state *cstate,
>  {
>         int cpp;
>  
> +       if (mem_value == 0)
> +               return USHRT_MAX;
> +
>         if (!intel_wm_plane_visible(cstate, pstate))
>                 return 0;
>  
> @@ -3008,6 +3017,34 @@ static void snb_wm_latency_quirk(struct drm_i915_private *dev_priv)
>         intel_print_wm_latency(dev_priv, "Cursor", dev_priv->wm.cur_latency);
>  }
>  
> +static void snb_wm_lp3_irq_quirk(struct drm_i915_private *dev_priv)
> +{
> +       /*
> +        * On some SNB machines (Thinkpad X220 Tablet at least)
> +        * LP3 usage can cause vblank interrupts to be lost.
> +        * The DEIIR bit will go high but it looks like the CPU
> +        * never gets interrupted.
> +        *
> +        * It's not clear whether other interrupt source could
> +        * be affected or if this is somehow limited to vblank
> +        * interrupts only. To play it safe we disable LP3
> +        * watermarks entirely.
> +        */
> +       if (dev_priv->wm.pri_latency[3] == 0 &&
> +           dev_priv->wm.spr_latency[3] == 0 &&
> +           dev_priv->wm.cur_latency[3] == 0)
> +               return;
> +
> +       dev_priv->wm.pri_latency[3] = 0;
> +       dev_priv->wm.spr_latency[3] = 0;
> +       dev_priv->wm.cur_latency[3] = 0;

-> return USHRT_MAX for pri/spr/cur planes.
-> result->enable = false;

Only question then why USHRT_MAX for a u32 parameter? Seems to be copied
from gm45 where it is a u16 parameter instead.
-Chris
Ville Syrjälä Nov. 13, 2018, 6:40 p.m. UTC | #2
On Tue, Nov 13, 2018 at 06:25:47PM +0000, Chris Wilson wrote:
> Quoting Ville Syrjala (2018-11-13 18:10:23)
> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > 
> > I have a Thinkpad X220 Tablet in my hands that is losing vblank
> > interrupts whenever LP3 watermarks are used.
> > 
> > If I nudge the latency value written to the WM3 register just
> > by one in either direction the problem disappears. That to me
> > suggests that the punit will not enter the corrsponding
> > powersave mode (MPLL shutdown IIRC) unless the latency value
> > in the register matches exactly what we read from SSKPD. Ie.
> > it's not really a latency value but rather just a cookie
> > by which the punit can identify the desired power saving state.
> > On HSW/BDW this was changed such that we actually just write
> > the WM level number into those bits, which makes much more
> > sense given the observed behaviour.
> > 
> > We could try to handle this by disallowing LP3 watermarks
> > only when vblank interrupts are enabled but we'd first have
> > to prove that only vblank interrupts are affected, which
> > seems unlikely. Also we can't grab the wm mutex from the
> > vblank enable/disable hooks because those are called with
> > various spinlocks held. Thus we'd have to redesigne the
> > watermark locking. So to play it safe and keep the code
> > simple we simply disable LP3 watermarks on all SNB machines.
> > 
> > To do that we simply zero out the latency values for
> > watermark level 3, and we adjust the watermark computation
> > to check for that. The behaviour now matches that of the
> > g4x/vlv/skl wm code in the presence of a zeroed latency
> > value.
> > 
> > Cc: stable@vger.kernel.org
> > Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=101269
> > Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=103713
> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > ---
> >  drivers/gpu/drm/i915/intel_pm.c | 41 ++++++++++++++++++++++++++++++++-
> >  1 file changed, 40 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> > index 27498ded4949..ef1ae2ede379 100644
> > --- a/drivers/gpu/drm/i915/intel_pm.c
> > +++ b/drivers/gpu/drm/i915/intel_pm.c
> > @@ -2493,6 +2493,9 @@ static uint32_t ilk_compute_pri_wm(const struct intel_crtc_state *cstate,
> >         uint32_t method1, method2;
> >         int cpp;
> >  
> > +       if (mem_value == 0)
> > +               return USHRT_MAX;
> > +
> >         if (!intel_wm_plane_visible(cstate, pstate))
> >                 return 0;
> >  
> > @@ -2522,6 +2525,9 @@ static uint32_t ilk_compute_spr_wm(const struct intel_crtc_state *cstate,
> >         uint32_t method1, method2;
> >         int cpp;
> >  
> > +       if (mem_value == 0)
> > +               return USHRT_MAX;
> > +
> >         if (!intel_wm_plane_visible(cstate, pstate))
> >                 return 0;
> >  
> > @@ -2545,6 +2551,9 @@ static uint32_t ilk_compute_cur_wm(const struct intel_crtc_state *cstate,
> >  {
> >         int cpp;
> >  
> > +       if (mem_value == 0)
> > +               return USHRT_MAX;
> > +
> >         if (!intel_wm_plane_visible(cstate, pstate))
> >                 return 0;
> >  
> > @@ -3008,6 +3017,34 @@ static void snb_wm_latency_quirk(struct drm_i915_private *dev_priv)
> >         intel_print_wm_latency(dev_priv, "Cursor", dev_priv->wm.cur_latency);
> >  }
> >  
> > +static void snb_wm_lp3_irq_quirk(struct drm_i915_private *dev_priv)
> > +{
> > +       /*
> > +        * On some SNB machines (Thinkpad X220 Tablet at least)
> > +        * LP3 usage can cause vblank interrupts to be lost.
> > +        * The DEIIR bit will go high but it looks like the CPU
> > +        * never gets interrupted.
> > +        *
> > +        * It's not clear whether other interrupt source could
> > +        * be affected or if this is somehow limited to vblank
> > +        * interrupts only. To play it safe we disable LP3
> > +        * watermarks entirely.
> > +        */
> > +       if (dev_priv->wm.pri_latency[3] == 0 &&
> > +           dev_priv->wm.spr_latency[3] == 0 &&
> > +           dev_priv->wm.cur_latency[3] == 0)
> > +               return;
> > +
> > +       dev_priv->wm.pri_latency[3] = 0;
> > +       dev_priv->wm.spr_latency[3] = 0;
> > +       dev_priv->wm.cur_latency[3] = 0;
> 
> -> return USHRT_MAX for pri/spr/cur planes.
> -> result->enable = false;
> 
> Only question then why USHRT_MAX for a u32 parameter? Seems to be copied
> from gm45 where it is a u16 parameter instead.

A good question. My excuse is that I was expecting it to be a u16.
The max value the registers can hold is 11 bits, so u16 would be
more than enough for our needs.

Looks like we store these as u32 in the struct as well so we end
up wasting a bit of memory. I'll go write a patch to shrink it
a bit.
Chris Wilson Nov. 14, 2018, 4:49 p.m. UTC | #3
Quoting Ville Syrjälä (2018-11-13 18:40:20)
> On Tue, Nov 13, 2018 at 06:25:47PM +0000, Chris Wilson wrote:
> > Quoting Ville Syrjala (2018-11-13 18:10:23)
> > > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > 
> > > I have a Thinkpad X220 Tablet in my hands that is losing vblank
> > > interrupts whenever LP3 watermarks are used.
> > > 
> > > If I nudge the latency value written to the WM3 register just
> > > by one in either direction the problem disappears. That to me
> > > suggests that the punit will not enter the corrsponding
> > > powersave mode (MPLL shutdown IIRC) unless the latency value
> > > in the register matches exactly what we read from SSKPD. Ie.
> > > it's not really a latency value but rather just a cookie
> > > by which the punit can identify the desired power saving state.
> > > On HSW/BDW this was changed such that we actually just write
> > > the WM level number into those bits, which makes much more
> > > sense given the observed behaviour.
> > > 
> > > We could try to handle this by disallowing LP3 watermarks
> > > only when vblank interrupts are enabled but we'd first have
> > > to prove that only vblank interrupts are affected, which
> > > seems unlikely. Also we can't grab the wm mutex from the
> > > vblank enable/disable hooks because those are called with
> > > various spinlocks held. Thus we'd have to redesigne the
> > > watermark locking. So to play it safe and keep the code
> > > simple we simply disable LP3 watermarks on all SNB machines.
> > > 
> > > To do that we simply zero out the latency values for
> > > watermark level 3, and we adjust the watermark computation
> > > to check for that. The behaviour now matches that of the
> > > g4x/vlv/skl wm code in the presence of a zeroed latency
> > > value.
> > > 
> > > Cc: stable@vger.kernel.org
> > > Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=101269
> > > Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=103713
> > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > ---
> > >  drivers/gpu/drm/i915/intel_pm.c | 41 ++++++++++++++++++++++++++++++++-
> > >  1 file changed, 40 insertions(+), 1 deletion(-)
> > > 
> > > diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
> > > index 27498ded4949..ef1ae2ede379 100644
> > > --- a/drivers/gpu/drm/i915/intel_pm.c
> > > +++ b/drivers/gpu/drm/i915/intel_pm.c
> > > @@ -2493,6 +2493,9 @@ static uint32_t ilk_compute_pri_wm(const struct intel_crtc_state *cstate,
> > >         uint32_t method1, method2;
> > >         int cpp;
> > >  
> > > +       if (mem_value == 0)
> > > +               return USHRT_MAX;
> > > +
> > >         if (!intel_wm_plane_visible(cstate, pstate))
> > >                 return 0;
> > >  
> > > @@ -2522,6 +2525,9 @@ static uint32_t ilk_compute_spr_wm(const struct intel_crtc_state *cstate,
> > >         uint32_t method1, method2;
> > >         int cpp;
> > >  
> > > +       if (mem_value == 0)
> > > +               return USHRT_MAX;
> > > +
> > >         if (!intel_wm_plane_visible(cstate, pstate))
> > >                 return 0;
> > >  
> > > @@ -2545,6 +2551,9 @@ static uint32_t ilk_compute_cur_wm(const struct intel_crtc_state *cstate,
> > >  {
> > >         int cpp;
> > >  
> > > +       if (mem_value == 0)
> > > +               return USHRT_MAX;
> > > +
> > >         if (!intel_wm_plane_visible(cstate, pstate))
> > >                 return 0;
> > >  
> > > @@ -3008,6 +3017,34 @@ static void snb_wm_latency_quirk(struct drm_i915_private *dev_priv)
> > >         intel_print_wm_latency(dev_priv, "Cursor", dev_priv->wm.cur_latency);
> > >  }
> > >  
> > > +static void snb_wm_lp3_irq_quirk(struct drm_i915_private *dev_priv)
> > > +{
> > > +       /*
> > > +        * On some SNB machines (Thinkpad X220 Tablet at least)
> > > +        * LP3 usage can cause vblank interrupts to be lost.
> > > +        * The DEIIR bit will go high but it looks like the CPU
> > > +        * never gets interrupted.
> > > +        *
> > > +        * It's not clear whether other interrupt source could
> > > +        * be affected or if this is somehow limited to vblank
> > > +        * interrupts only. To play it safe we disable LP3
> > > +        * watermarks entirely.
> > > +        */
> > > +       if (dev_priv->wm.pri_latency[3] == 0 &&
> > > +           dev_priv->wm.spr_latency[3] == 0 &&
> > > +           dev_priv->wm.cur_latency[3] == 0)
> > > +               return;
> > > +
> > > +       dev_priv->wm.pri_latency[3] = 0;
> > > +       dev_priv->wm.spr_latency[3] = 0;
> > > +       dev_priv->wm.cur_latency[3] = 0;
> > 
> > -> return USHRT_MAX for pri/spr/cur planes.
> > -> result->enable = false;
> > 
> > Only question then why USHRT_MAX for a u32 parameter? Seems to be copied
> > from gm45 where it is a u16 parameter instead.
> 
> A good question. My excuse is that I was expecting it to be a u16.
> The max value the registers can hold is 11 bits, so u16 would be
> more than enough for our needs.
> 
> Looks like we store these as u32 in the struct as well so we end
> up wasting a bit of memory. I'll go write a patch to shrink it
> a bit.

That's all fine. I'd like to see this patch use U32_MAX for consistency
with itself in the meantime, but as far as the code doing what you claim,
Acked-by: Chris Wilson <chris@chris-wilson.co.uk>
-Chris
diff mbox series

Patch

diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 27498ded4949..ef1ae2ede379 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -2493,6 +2493,9 @@  static uint32_t ilk_compute_pri_wm(const struct intel_crtc_state *cstate,
 	uint32_t method1, method2;
 	int cpp;
 
+	if (mem_value == 0)
+		return USHRT_MAX;
+
 	if (!intel_wm_plane_visible(cstate, pstate))
 		return 0;
 
@@ -2522,6 +2525,9 @@  static uint32_t ilk_compute_spr_wm(const struct intel_crtc_state *cstate,
 	uint32_t method1, method2;
 	int cpp;
 
+	if (mem_value == 0)
+		return USHRT_MAX;
+
 	if (!intel_wm_plane_visible(cstate, pstate))
 		return 0;
 
@@ -2545,6 +2551,9 @@  static uint32_t ilk_compute_cur_wm(const struct intel_crtc_state *cstate,
 {
 	int cpp;
 
+	if (mem_value == 0)
+		return USHRT_MAX;
+
 	if (!intel_wm_plane_visible(cstate, pstate))
 		return 0;
 
@@ -3008,6 +3017,34 @@  static void snb_wm_latency_quirk(struct drm_i915_private *dev_priv)
 	intel_print_wm_latency(dev_priv, "Cursor", dev_priv->wm.cur_latency);
 }
 
+static void snb_wm_lp3_irq_quirk(struct drm_i915_private *dev_priv)
+{
+	/*
+	 * On some SNB machines (Thinkpad X220 Tablet at least)
+	 * LP3 usage can cause vblank interrupts to be lost.
+	 * The DEIIR bit will go high but it looks like the CPU
+	 * never gets interrupted.
+	 *
+	 * It's not clear whether other interrupt source could
+	 * be affected or if this is somehow limited to vblank
+	 * interrupts only. To play it safe we disable LP3
+	 * watermarks entirely.
+	 */
+	if (dev_priv->wm.pri_latency[3] == 0 &&
+	    dev_priv->wm.spr_latency[3] == 0 &&
+	    dev_priv->wm.cur_latency[3] == 0)
+		return;
+
+	dev_priv->wm.pri_latency[3] = 0;
+	dev_priv->wm.spr_latency[3] = 0;
+	dev_priv->wm.cur_latency[3] = 0;
+
+	DRM_DEBUG_KMS("LP3 watermarks disabled due to potential for lost interrupts\n");
+	intel_print_wm_latency(dev_priv, "Primary", dev_priv->wm.pri_latency);
+	intel_print_wm_latency(dev_priv, "Sprite", dev_priv->wm.spr_latency);
+	intel_print_wm_latency(dev_priv, "Cursor", dev_priv->wm.cur_latency);
+}
+
 static void ilk_setup_wm_latency(struct drm_i915_private *dev_priv)
 {
 	intel_read_wm_latency(dev_priv, dev_priv->wm.pri_latency);
@@ -3024,8 +3061,10 @@  static void ilk_setup_wm_latency(struct drm_i915_private *dev_priv)
 	intel_print_wm_latency(dev_priv, "Sprite", dev_priv->wm.spr_latency);
 	intel_print_wm_latency(dev_priv, "Cursor", dev_priv->wm.cur_latency);
 
-	if (IS_GEN6(dev_priv))
+	if (IS_GEN6(dev_priv)) {
 		snb_wm_latency_quirk(dev_priv);
+		snb_wm_lp3_irq_quirk(dev_priv);
+	}
 }
 
 static void skl_setup_wm_latency(struct drm_i915_private *dev_priv)