Skip to content

Commit

Permalink
drm/i915: Fix hangcheck to handle multiple rings
Browse files Browse the repository at this point in the history
Currently, we believe the GPU is idle if just the RENDER ring is idle.
This is obviously wrong if we only using either the BLT or the BSD
rings and so masking genuine hangs.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
  • Loading branch information
Chris Wilson committed Oct 27, 2010
1 parent 7e318e1 commit 893eead
Showing 1 changed file with 35 additions and 39 deletions.
74 changes: 35 additions & 39 deletions drivers/gpu/drm/i915/i915_irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -1307,12 +1307,29 @@ int i915_vblank_swap(struct drm_device *dev, void *data,
return -EINVAL;
}

static struct drm_i915_gem_request *
i915_get_tail_request(struct drm_device *dev)
static u32
ring_last_seqno(struct intel_ring_buffer *ring)
{
drm_i915_private_t *dev_priv = dev->dev_private;
return list_entry(dev_priv->render_ring.request_list.prev,
struct drm_i915_gem_request, list);
return list_entry(ring->request_list.prev,
struct drm_i915_gem_request, list)->seqno;
}

static bool i915_hangcheck_ring_idle(struct intel_ring_buffer *ring, bool *err)
{
if (list_empty(&ring->request_list) ||
i915_seqno_passed(ring->get_seqno(ring), ring_last_seqno(ring))) {
/* Issue a wake-up to catch stuck h/w. */
if (ring->waiting_gem_seqno && waitqueue_active(&ring->irq_queue)) {
DRM_ERROR("Hangcheck timer elapsed... %s idle [waiting on %d, at %d], missed IRQ?\n",
ring->name,
ring->waiting_gem_seqno,
ring->get_seqno(ring));
wake_up_all(&ring->irq_queue);
*err = true;
}
return true;
}
return false;
}

/**
Expand All @@ -1326,6 +1343,17 @@ void i915_hangcheck_elapsed(unsigned long data)
struct drm_device *dev = (struct drm_device *)data;
drm_i915_private_t *dev_priv = dev->dev_private;
uint32_t acthd, instdone, instdone1;
bool err = false;

/* If all work is done then ACTHD clearly hasn't advanced. */
if (i915_hangcheck_ring_idle(&dev_priv->render_ring, &err) &&
i915_hangcheck_ring_idle(&dev_priv->bsd_ring, &err) &&
i915_hangcheck_ring_idle(&dev_priv->blt_ring, &err)) {
dev_priv->hangcheck_count = 0;
if (err)
goto repeat;
return;
}

if (INTEL_INFO(dev)->gen < 4) {
acthd = I915_READ(ACTHD);
Expand All @@ -1337,38 +1365,6 @@ void i915_hangcheck_elapsed(unsigned long data)
instdone1 = I915_READ(INSTDONE1);
}

/* If all work is done then ACTHD clearly hasn't advanced. */
if (list_empty(&dev_priv->render_ring.request_list) ||
i915_seqno_passed(dev_priv->render_ring.get_seqno(&dev_priv->render_ring),
i915_get_tail_request(dev)->seqno)) {
bool missed_wakeup = false;

dev_priv->hangcheck_count = 0;

/* Issue a wake-up to catch stuck h/w. */
if (dev_priv->render_ring.waiting_gem_seqno &&
waitqueue_active(&dev_priv->render_ring.irq_queue)) {
wake_up_all(&dev_priv->render_ring.irq_queue);
missed_wakeup = true;
}

if (dev_priv->bsd_ring.waiting_gem_seqno &&
waitqueue_active(&dev_priv->bsd_ring.irq_queue)) {
wake_up_all(&dev_priv->bsd_ring.irq_queue);
missed_wakeup = true;
}

if (dev_priv->blt_ring.waiting_gem_seqno &&
waitqueue_active(&dev_priv->blt_ring.irq_queue)) {
wake_up_all(&dev_priv->blt_ring.irq_queue);
missed_wakeup = true;
}

if (missed_wakeup)
DRM_ERROR("Hangcheck timer elapsed... GPU idle, missed IRQ.\n");
return;
}

if (dev_priv->last_acthd == acthd &&
dev_priv->last_instdone == instdone &&
dev_priv->last_instdone1 == instdone1) {
Expand All @@ -1385,7 +1381,7 @@ void i915_hangcheck_elapsed(unsigned long data)
if (tmp & RING_WAIT) {
I915_WRITE(PRB0_CTL, tmp);
POSTING_READ(PRB0_CTL);
goto out;
goto repeat;
}
}

Expand All @@ -1400,7 +1396,7 @@ void i915_hangcheck_elapsed(unsigned long data)
dev_priv->last_instdone1 = instdone1;
}

out:
repeat:
/* Reset timer case chip hangs without another request being added */
mod_timer(&dev_priv->hangcheck_timer,
jiffies + msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD));
Expand Down

0 comments on commit 893eead

Please sign in to comment.