| From 9f3f987cb1f2ebc32e2442b63a4b0e75c648f45f Mon Sep 17 00:00:00 2001 |
| From: Mika Kuoppala <mika.kuoppala@linux.intel.com> |
| Date: Fri, 24 May 2013 17:16:07 +0300 |
| Subject: drm/i915: track ring progression using seqnos |
| |
| Instead of relying in acthd, track ring seqno progression |
| to detect if ring has hung. |
| |
| v2: put hangcheck stuff inside struct (Chris Wilson) |
| |
| v3: initialize hangcheck.seqno (Ben Widawsky) |
| |
| Signed-off-by: Mika Kuoppala <mika.kuoppala@intel.com> |
| Reviewed-by: Ben Widawsky <ben@bwidawsk.net> |
| Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch> |
| (cherry picked from commit 92cab7345131db7af18f630a799ce6b2e8e624c5) |
| Signed-off-by: Darren Hart <dvhart@linux.intel.com> |
| --- |
| drivers/gpu/drm/i915/i915_drv.h | 2 -- |
| drivers/gpu/drm/i915/i915_irq.c | 30 +++++++++++++----------------- |
| drivers/gpu/drm/i915/intel_ringbuffer.c | 1 + |
| drivers/gpu/drm/i915/intel_ringbuffer.h | 6 ++++++ |
| 4 files changed, 20 insertions(+), 19 deletions(-) |
| |
| --- a/drivers/gpu/drm/i915/i915_drv.h |
| +++ b/drivers/gpu/drm/i915/i915_drv.h |
| @@ -843,8 +843,6 @@ struct i915_gpu_error { |
| #define DRM_I915_HANGCHECK_JIFFIES msecs_to_jiffies(DRM_I915_HANGCHECK_PERIOD) |
| struct timer_list hangcheck_timer; |
| int hangcheck_count; |
| - uint32_t last_acthd[I915_NUM_RINGS]; |
| - uint32_t prev_instdone[I915_NUM_INSTDONE_REG]; |
| |
| /* For reset and error_state handling. */ |
| spinlock_t lock; |
| --- a/drivers/gpu/drm/i915/i915_irq.c |
| +++ b/drivers/gpu/drm/i915/i915_irq.c |
| @@ -2421,22 +2421,19 @@ void i915_hangcheck_elapsed(unsigned lon |
| { |
| struct drm_device *dev = (struct drm_device *)data; |
| drm_i915_private_t *dev_priv = dev->dev_private; |
| - uint32_t acthd[I915_NUM_RINGS], instdone[I915_NUM_INSTDONE_REG]; |
| struct intel_ring_buffer *ring; |
| bool err = false, idle; |
| int i; |
| + u32 seqno[I915_NUM_RINGS]; |
| + bool work_done; |
| |
| if (!i915_enable_hangcheck) |
| return; |
| |
| - memset(acthd, 0, sizeof(acthd)); |
| idle = true; |
| for_each_ring(ring, dev_priv, i) { |
| - u32 seqno; |
| - |
| - seqno = ring->get_seqno(ring, false); |
| - idle &= i915_hangcheck_ring_idle(ring, seqno, &err); |
| - acthd[i] = intel_ring_get_active_head(ring); |
| + seqno[i] = ring->get_seqno(ring, false); |
| + idle &= i915_hangcheck_ring_idle(ring, seqno[i], &err); |
| } |
| |
| /* If all work is done then ACTHD clearly hasn't advanced. */ |
| @@ -2452,20 +2449,19 @@ void i915_hangcheck_elapsed(unsigned lon |
| return; |
| } |
| |
| - i915_get_extra_instdone(dev, instdone); |
| - if (memcmp(dev_priv->gpu_error.last_acthd, acthd, |
| - sizeof(acthd)) == 0 && |
| - memcmp(dev_priv->gpu_error.prev_instdone, instdone, |
| - sizeof(instdone)) == 0) { |
| + work_done = false; |
| + for_each_ring(ring, dev_priv, i) { |
| + if (ring->hangcheck.seqno != seqno[i]) { |
| + work_done = true; |
| + ring->hangcheck.seqno = seqno[i]; |
| + } |
| + } |
| + |
| + if (!work_done) { |
| if (i915_hangcheck_hung(dev)) |
| return; |
| } else { |
| dev_priv->gpu_error.hangcheck_count = 0; |
| - |
| - memcpy(dev_priv->gpu_error.last_acthd, acthd, |
| - sizeof(acthd)); |
| - memcpy(dev_priv->gpu_error.prev_instdone, instdone, |
| - sizeof(instdone)); |
| } |
| |
| repeat: |
| --- a/drivers/gpu/drm/i915/intel_ringbuffer.c |
| +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c |
| @@ -1523,6 +1523,7 @@ void intel_ring_init_seqno(struct intel_ |
| } |
| |
| ring->set_seqno(ring, seqno); |
| + ring->hangcheck.seqno = seqno; |
| } |
| |
| void intel_ring_advance(struct intel_ring_buffer *ring) |
| --- a/drivers/gpu/drm/i915/intel_ringbuffer.h |
| +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h |
| @@ -37,6 +37,10 @@ struct intel_hw_status_page { |
| #define I915_READ_SYNC_0(ring) I915_READ(RING_SYNC_0((ring)->mmio_base)) |
| #define I915_READ_SYNC_1(ring) I915_READ(RING_SYNC_1((ring)->mmio_base)) |
| |
| +struct intel_ring_hangcheck { |
| + u32 seqno; |
| +}; |
| + |
| struct intel_ring_buffer { |
| const char *name; |
| enum intel_ring_id { |
| @@ -137,6 +141,8 @@ struct intel_ring_buffer { |
| struct i915_hw_context *default_context; |
| struct i915_hw_context *last_context; |
| |
| + struct intel_ring_hangcheck hangcheck; |
| + |
| void *private; |
| }; |
| |