From 075b68c315c9f1c02565576e1f412029993472c0 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 5 Jun 2013 10:08:35 +0100 Subject: [PATCH 2/2] drm/i915: Don't count semaphore waits towards a stuck ring If we detect a ring is in a valid wait for another, just let it be. Eventually it will either begin to progress again, or the entire system will come grinding to a halt and then hangcheck will fire as soon as the deadlock is detected. Signed-off-by: Chris Wilson --- drivers/gpu/drm/i915/i915_irq.c | 55 +++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index e936fde..ae3e299 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2331,33 +2331,50 @@ static bool i915_hangcheck_ring_idle(struct intel_ring_buffer *ring, return false; } -static bool semaphore_passed(struct intel_ring_buffer *ring) +static struct intel_ring_buffer * +semaphore_waits_for(struct intel_ring_buffer *ring, u32 *acthd) { struct drm_i915_private *dev_priv = ring->dev->dev_private; - u32 acthd = intel_ring_get_active_head(ring) & HEAD_ADDR; - struct intel_ring_buffer *signaller; u32 cmd, ipehr, acthd_min; ipehr = I915_READ(RING_IPEHR(ring->mmio_base)); if ((ipehr & ~(0x3 << 16)) != (MI_SEMAPHORE_MBOX | MI_SEMAPHORE_COMPARE | MI_SEMAPHORE_REGISTER)) - return false; + return NULL; /* ACTHD is likely pointing to the dword after the actual command, * so scan backwards until we find the MBOX. */ - acthd_min = max((int)acthd - 3 * 4, 0); + *acthd = intel_ring_get_active_head(ring) & HEAD_ADDR; + acthd_min = max((int)*acthd - 3 * 4, 0); do { - cmd = ioread32(ring->virtual_start + acthd); + cmd = ioread32(ring->virtual_start + *acthd); if (cmd == ipehr) break; - acthd -= 4; - if (acthd < acthd_min) - return false; + *acthd -= 4; + if (*acthd < acthd_min) + return NULL; } while (1); - signaller = &dev_priv->ring[(ring->id + (((ipehr >> 17) & 1) + 1)) % 3]; + return &dev_priv->ring[(ring->id + (((ipehr >> 17) & 1) + 1)) % 3]; +} + +static int semaphore_passed(struct intel_ring_buffer *ring) +{ + struct drm_i915_private *dev_priv = ring->dev->dev_private; + struct intel_ring_buffer *signaller; + u32 acthd, ctl; + + signaller = semaphore_waits_for(ring, &acthd); + if (signaller == NULL || signaller == ring) + return -1; + + /* cursory check for an unkickable deadlock */ + ctl = I915_READ_CTL(signaller); + if (ctl & RING_WAIT_SEMAPHORE && semaphore_passed(signaller) <= 0) + return -1; + return i915_seqno_passed(signaller->get_seqno(signaller, false), ioread32(ring->virtual_start+acthd+4)+1); } @@ -2374,13 +2391,17 @@ static bool kick_ring(struct intel_ring_buffer *ring) return true; } - if (INTEL_INFO(dev)->gen >= 6 && - tmp & RING_WAIT_SEMAPHORE && - semaphore_passed(ring)) { - DRM_ERROR("Kicking stuck semaphore on %s\n", - ring->name); - I915_WRITE_CTL(ring, tmp); - return true; + if (INTEL_INFO(dev)->gen >= 6 && tmp & RING_WAIT_SEMAPHORE) { + switch (semaphore_passed(ring)) { + default: + return false; + case 1: + DRM_ERROR("Kicking stuck semaphore on %s\n", + ring->name); + I915_WRITE_CTL(ring, tmp); + case 0: + return true; + } } return false; } -- 1.7.10.4