From f1c0120fa2be8f082080ccfbfe9b46b652f56e28 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 25 Jul 2012 11:28:29 +0200 Subject: [PATCH] drm/i915: use a 10 usec delay in forcewake ack delay loop This papers over a regression introduced in commit 990bbdadabaa51828e475eda86ee5720a4910cc3 Author: Chris Wilson Date: Mon Jul 2 11:51:02 2012 -0300 drm/i915: Group the GT routines together in both code and vtable which changed the udelay used to wait for the forcewake ack from udelay(1) to udelay(10). This broke the use of the Bitstream Decoder ring on snb. Some investigation by Chris Wilson showed that a delay slightly longer than udelay(1) or just cpu_relax works around this issue, so the cpu_relax was used for wait_for_atomic_us (since that would speed up the waiting a bit, too). Unfortunately this caused another regression on snb, completely hanging the gpu even when only using glxgears. To avoid everyone else paying the penalty of the udelay(10) add a parameter to the wait_for_atomic_us macro to specifiy the delay. And also add a giant comment to the gen6 forcewake code explaining what this is all about (note that forcewake_mt is gen7+, hence doesn't need this). Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=51738 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=52424 Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 8 ++++---- drivers/gpu/drm/i915/intel_drv.h | 21 +++++++++++---------- drivers/gpu/drm/i915/intel_pm.c | 15 +++++++++------ 3 files changed, 24 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e9e476e..210b10f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -412,7 +412,7 @@ u32 intel_dpio_read(struct drm_i915_private *dev_priv, int reg) u32 val = 0; spin_lock_irqsave(&dev_priv->dpio_lock, flags); - if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) { + if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100, 0)) { DRM_ERROR("DPIO idle wait timed out\n"); goto out_unlock; } @@ -420,7 +420,7 @@ u32 intel_dpio_read(struct drm_i915_private *dev_priv, int reg) I915_WRITE(DPIO_REG, reg); I915_WRITE(DPIO_PKT, DPIO_RID | DPIO_OP_READ | DPIO_PORTID | DPIO_BYTE); - if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) { + if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100, 0)) { DRM_ERROR("DPIO read wait timed out\n"); goto out_unlock; } @@ -437,7 +437,7 @@ static void intel_dpio_write(struct drm_i915_private *dev_priv, int reg, unsigned long flags; spin_lock_irqsave(&dev_priv->dpio_lock, flags); - if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) { + if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100, 0)) { DRM_ERROR("DPIO idle wait timed out\n"); goto out_unlock; } @@ -446,7 +446,7 @@ static void intel_dpio_write(struct drm_i915_private *dev_priv, int reg, I915_WRITE(DPIO_REG, reg); I915_WRITE(DPIO_PKT, DPIO_RID | DPIO_OP_WRITE | DPIO_PORTID | DPIO_BYTE); - if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100)) + if (wait_for_atomic_us((I915_READ(DPIO_PKT) & DPIO_BUSY) == 0, 100, 0)) DRM_ERROR("DPIO write wait timed out\n"); out_unlock: diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 8435355..8e212d0 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -45,16 +45,17 @@ ret__; \ }) -#define wait_for_atomic_us(COND, US) ({ \ - int i, ret__ = -ETIMEDOUT; \ - for (i = 0; i < (US); i++) { \ - if ((COND)) { \ - ret__ = 0; \ - break; \ - } \ - udelay(1); \ - } \ - ret__; \ +#define wait_for_atomic_us(COND, US, W) ({ \ + unsigned long timeout__ = jiffies + usecs_to_jiffies(US); \ + int ret__ = 0; \ + while (!(COND)) { \ + if (time_after(jiffies, timeout__)) { \ + ret__ = -ETIMEDOUT; \ + break; \ + } \ + if (W) udelay(W); else cpu_relax(); \ + } \ + ret__; \ }) #define wait_for(COND, MS) _wait_for(COND, MS, 1) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 94aabca..dc1a9e5 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3946,7 +3946,7 @@ static void __gen6_gt_wait_for_thread_c0(struct drm_i915_private *dev_priv) /* w/a for a sporadic read returning 0 by waiting for the GT * thread to wake up. */ - if (wait_for_atomic_us((I915_READ_NOTRACE(GEN6_GT_THREAD_STATUS_REG) & gt_thread_status_mask) == 0, 500)) + if (wait_for_atomic_us((I915_READ_NOTRACE(GEN6_GT_THREAD_STATUS_REG) & gt_thread_status_mask) == 0, 500, 0)) DRM_ERROR("GT thread status wait timed out\n"); } @@ -3959,12 +3959,15 @@ static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv) else forcewake_ack = FORCEWAKE_ACK; - if (wait_for_atomic_us((I915_READ_NOTRACE(forcewake_ack) & 1) == 0, 500)) + /* Note the elephant: If we use anything shorter than udelay(10) in the + * forcewak ack loops (like udelay(1) or cpu_relax), snb just dies. + * Cause of this is totally unknown. */ + if (wait_for_atomic_us((I915_READ_NOTRACE(forcewake_ack) & 1) == 0, 500, 10)) DRM_ERROR("Force wake wait timed out\n"); I915_WRITE_NOTRACE(FORCEWAKE, 1); - if (wait_for_atomic_us((I915_READ_NOTRACE(forcewake_ack) & 1), 500)) + if (wait_for_atomic_us((I915_READ_NOTRACE(forcewake_ack) & 1), 500, 10)) DRM_ERROR("Force wake wait timed out\n"); __gen6_gt_wait_for_thread_c0(dev_priv); @@ -3979,12 +3982,12 @@ static void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv) else forcewake_ack = FORCEWAKE_MT_ACK; - if (wait_for_atomic_us((I915_READ_NOTRACE(forcewake_ack) & 1) == 0, 500)) + if (wait_for_atomic_us((I915_READ_NOTRACE(forcewake_ack) & 1) == 0, 500, 0)) DRM_ERROR("Force wake wait timed out\n"); I915_WRITE_NOTRACE(FORCEWAKE_MT, _MASKED_BIT_ENABLE(1)); - if (wait_for_atomic_us((I915_READ_NOTRACE(forcewake_ack) & 1), 500)) + if (wait_for_atomic_us((I915_READ_NOTRACE(forcewake_ack) & 1), 500, 0)) DRM_ERROR("Force wake wait timed out\n"); __gen6_gt_wait_for_thread_c0(dev_priv); @@ -4071,7 +4074,7 @@ static void vlv_force_wake_get(struct drm_i915_private *dev_priv) I915_WRITE_NOTRACE(FORCEWAKE_VLV, 0xffffffff); POSTING_READ(FORCEWAKE_VLV); - if (wait_for_atomic_us((I915_READ_NOTRACE(FORCEWAKE_ACK_VLV) & 1), 500)) + if (wait_for_atomic_us((I915_READ_NOTRACE(FORCEWAKE_ACK_VLV) & 1), 500, 0)) DRM_ERROR("Force wake wait timed out\n"); __gen6_gt_wait_for_thread_c0(dev_priv); -- 1.7.10.4