@@ -2332,9 +2332,10 @@ static bool i915_context_is_banned(struct drm_device *dev,
static void i915_set_reset_status(struct intel_ring_buffer *ring,
struct drm_i915_gem_request *request,
- u32 acthd)
+ const bool guilty)
{
- bool inside, guilty;
+ const u32 acthd = intel_ring_get_active_head(ring);
+ bool inside;
unsigned long offset = 0;
struct i915_hw_context *ctx = request->ctx;
struct i915_ctx_hang_stats *hs;
@@ -2342,14 +2343,11 @@ static void i915_set_reset_status(struct intel_ring_buffer *ring,
if (WARN_ON(!ctx))
return;
- /* Innocent until proven guilty */
- guilty = false;
-
if (request->batch_obj)
offset = i915_gem_obj_offset(request->batch_obj,
request_to_vm(request));
- if (ring->hangcheck.action != HANGCHECK_WAIT &&
+ if (guilty &&
i915_request_guilty(request, acthd, &inside)) {
DRM_DEBUG("%s hung %s bo (0x%lx ctx %d) at 0x%x\n",
ring->name,
@@ -2357,8 +2355,6 @@ static void i915_set_reset_status(struct intel_ring_buffer *ring,
offset,
ctx->id,
acthd);
-
- guilty = true;
}
WARN_ON(!ctx->last_ring);
@@ -2385,19 +2381,39 @@ static void i915_gem_free_request(struct drm_i915_gem_request *request)
kfree(request);
}
-static void i915_gem_reset_ring_status(struct drm_i915_private *dev_priv,
- struct intel_ring_buffer *ring)
+static struct drm_i915_gem_request *
+i915_gem_find_first_non_complete(struct intel_ring_buffer *ring)
{
- u32 completed_seqno = ring->get_seqno(ring, false);
- u32 acthd = intel_ring_get_active_head(ring);
struct drm_i915_gem_request *request;
+ const u32 completed_seqno = ring->get_seqno(ring, false);
list_for_each_entry(request, &ring->request_list, list) {
if (i915_seqno_passed(completed_seqno, request->seqno))
continue;
- i915_set_reset_status(ring, request, acthd);
+ return request;
}
+
+ return NULL;
+}
+
+static void i915_gem_reset_ring_status(struct drm_i915_private *dev_priv,
+ struct intel_ring_buffer *ring)
+{
+ struct drm_i915_gem_request *request;
+ bool ring_hung;
+
+ request = i915_gem_find_first_non_complete(ring);
+
+ if (request == NULL)
+ return;
+
+ ring_hung = ring->hangcheck.score >= HANGCHECK_SCORE_RING_HUNG;
+
+ i915_set_reset_status(ring, request, ring_hung);
+
+ list_for_each_entry_continue(request, &ring->request_list, list)
+ i915_set_reset_status(ring, request, false);
}
static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv,
@@ -2544,7 +2544,6 @@ static void i915_hangcheck_elapsed(unsigned long data)
#define BUSY 1
#define KICK 5
#define HUNG 20
-#define FIRE 30
if (!i915.enable_hangcheck)
return;
@@ -2628,7 +2627,7 @@ static void i915_hangcheck_elapsed(unsigned long data)
}
for_each_ring(ring, dev_priv, i) {
- if (ring->hangcheck.score > FIRE) {
+ if (ring->hangcheck.score >= HANGCHECK_SCORE_RING_HUNG) {
DRM_INFO("%s on %s\n",
stuck[i] ? "stuck" : "no progress",
ring->name);
@@ -41,6 +41,8 @@ enum intel_ring_hangcheck_action {
HANGCHECK_HUNG,
};
+#define HANGCHECK_SCORE_RING_HUNG 31
+
struct intel_ring_hangcheck {
bool deadlock;
u32 seqno;