From b1fffd1a2587578bf0d238c37de80444f044bf30 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. Also note that in the original code we never wrote the Pn value to suppress down interrupts as the new_delay would never be decremented past min_delay. Further confusion abounds. References: https://bugs.freedesktop.org/show_bug.cgi?id=44006 Signed-off-by: Chris Wilson Cc: Jesse Barnes --- drivers/gpu/drm/i915/i915_irq.c | 41 +++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 13d40a1..bdfe6d4 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -382,8 +382,8 @@ static void gen6_pm_rps_work(struct work_struct *work) { drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t, rps_work); - u8 new_delay = dev_priv->cur_delay; u32 pm_iir, pm_imr; + u32 limits, new_delay; spin_lock_irq(&dev_priv->rps_lock); pm_iir = dev_priv->pm_iir; @@ -392,36 +392,39 @@ static void gen6_pm_rps_work(struct work_struct *work) I915_WRITE(GEN6_PMIMR, 0); spin_unlock_irq(&dev_priv->rps_lock); - if (!pm_iir) + if ((pm_iir & GEN6_PM_DEFERRED_EVENTS) == 0) 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 interrupts + * until we hit the minimum or maximum frequencies. + */ + limits &= ~(0x3f << 16 | 0x3f << 24); + if (pm_iir & GEN6_PM_RP_UP_THRESHOLD) { - if (dev_priv->cur_delay != dev_priv->max_delay) - new_delay = dev_priv->cur_delay + 1; - if (new_delay > dev_priv->max_delay) + 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; - if (new_delay < dev_priv->min_delay) { + else + limits |= (dev_priv->max_delay & 0x3f) << 24; + } else { + 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