From 74628fea62a315e5386955420f3daf4dfba0244c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 25 Apr 2012 19:09:39 +0100 Subject: [PATCH] drm/i915: Always unsuppress down-interrupts when programming a non-min value The GT power programing guide recommends always unsuppressing the down interrupt when programming any render frequency above the minimum. This is because the GT unit doesn't emit interrupts whilst it is asleep which can lead to the down interrupt being lost. Also due to our own coalescing of interrupts through use of a bottom-half, it looks safer to always rewrite the limits. References: https://bugs.freedesktop.org/show_bug.cgi?id=44006 Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_irq.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 13d40a1..2b130c6 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -384,6 +384,7 @@ static void gen6_pm_rps_work(struct work_struct *work) rps_work); u8 new_delay = dev_priv->cur_delay; u32 pm_iir, pm_imr; + u32 limits; spin_lock_irq(&dev_priv->rps_lock); pm_iir = dev_priv->pm_iir; @@ -396,32 +397,32 @@ static void gen6_pm_rps_work(struct work_struct *work) return; mutex_lock(&dev_priv->dev->struct_mutex); + + gen6_gt_force_wake_get(dev_priv); + limits = I915_READ(GEN6_RP_INTERRUPT_LIMITS); + + /* Make sure we continue to get down interrupts + * until we hit the minimum frequency */ + limits &= ~(0x3f << 16); + if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) { - if (dev_priv->cur_delay != dev_priv->max_delay) - new_delay = dev_priv->cur_delay + 1; + new_delay = dev_priv->cur_delay + 1; if (new_delay > dev_priv->max_delay) new_delay = dev_priv->max_delay; } else if (pm_iir & (GEN6_PM_RP_DOWN_THRESHOLD | GEN6_PM_RP_DOWN_TIMEOUT)) { - gen6_gt_force_wake_get(dev_priv); - if (dev_priv->cur_delay != dev_priv->min_delay) - new_delay = dev_priv->cur_delay - 1; + new_delay = dev_priv->cur_delay - 1; if (new_delay < dev_priv->min_delay) { new_delay = dev_priv->min_delay; - I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, - I915_READ(GEN6_RP_INTERRUPT_LIMITS) | - ((new_delay << 16) & 0x3f0000)); - } else { - /* Make sure we continue to get down interrupts - * until we hit the minimum frequency */ - I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, - I915_READ(GEN6_RP_INTERRUPT_LIMITS) & ~0x3f0000); + limits |= (new_delay & 0x3f) << 16; } - gen6_gt_force_wake_put(dev_priv); } gen6_set_rps(dev_priv->dev, new_delay); dev_priv->cur_delay = new_delay; + I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, limits); + gen6_gt_force_wake_put(dev_priv); + /* * rps_lock not held here because clearing is non-destructive. There is * an *extremely* unlikely race with gen6_rps_enable() that is prevented -- 1.7.10