|
@@ -2949,14 +2949,44 @@ static void semaphore_clear_deadlocks(struct drm_i915_private *dev_priv)
|
|
ring->hangcheck.deadlock = 0;
|
|
ring->hangcheck.deadlock = 0;
|
|
}
|
|
}
|
|
|
|
|
|
-static enum intel_ring_hangcheck_action
|
|
|
|
-ring_stuck(struct intel_engine_cs *ring, u64 acthd)
|
|
|
|
|
|
+static bool subunits_stuck(struct intel_engine_cs *ring)
|
|
{
|
|
{
|
|
- struct drm_device *dev = ring->dev;
|
|
|
|
- struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
|
- u32 tmp;
|
|
|
|
|
|
+ u32 instdone[I915_NUM_INSTDONE_REG];
|
|
|
|
+ bool stuck;
|
|
|
|
+ int i;
|
|
|
|
+
|
|
|
|
+ if (ring->id != RCS)
|
|
|
|
+ return true;
|
|
|
|
+
|
|
|
|
+ i915_get_extra_instdone(ring->dev, instdone);
|
|
|
|
|
|
|
|
+ /* There might be unstable subunit states even when
|
|
|
|
+ * actual head is not moving. Filter out the unstable ones by
|
|
|
|
+ * accumulating the undone -> done transitions and only
|
|
|
|
+ * consider those as progress.
|
|
|
|
+ */
|
|
|
|
+ stuck = true;
|
|
|
|
+ for (i = 0; i < I915_NUM_INSTDONE_REG; i++) {
|
|
|
|
+ const u32 tmp = instdone[i] | ring->hangcheck.instdone[i];
|
|
|
|
+
|
|
|
|
+ if (tmp != ring->hangcheck.instdone[i])
|
|
|
|
+ stuck = false;
|
|
|
|
+
|
|
|
|
+ ring->hangcheck.instdone[i] |= tmp;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return stuck;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static enum intel_ring_hangcheck_action
|
|
|
|
+head_stuck(struct intel_engine_cs *ring, u64 acthd)
|
|
|
|
+{
|
|
if (acthd != ring->hangcheck.acthd) {
|
|
if (acthd != ring->hangcheck.acthd) {
|
|
|
|
+
|
|
|
|
+ /* Clear subunit states on head movement */
|
|
|
|
+ memset(ring->hangcheck.instdone, 0,
|
|
|
|
+ sizeof(ring->hangcheck.instdone));
|
|
|
|
+
|
|
if (acthd > ring->hangcheck.max_acthd) {
|
|
if (acthd > ring->hangcheck.max_acthd) {
|
|
ring->hangcheck.max_acthd = acthd;
|
|
ring->hangcheck.max_acthd = acthd;
|
|
return HANGCHECK_ACTIVE;
|
|
return HANGCHECK_ACTIVE;
|
|
@@ -2965,6 +2995,24 @@ ring_stuck(struct intel_engine_cs *ring, u64 acthd)
|
|
return HANGCHECK_ACTIVE_LOOP;
|
|
return HANGCHECK_ACTIVE_LOOP;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (!subunits_stuck(ring))
|
|
|
|
+ return HANGCHECK_ACTIVE;
|
|
|
|
+
|
|
|
|
+ return HANGCHECK_HUNG;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static enum intel_ring_hangcheck_action
|
|
|
|
+ring_stuck(struct intel_engine_cs *ring, u64 acthd)
|
|
|
|
+{
|
|
|
|
+ struct drm_device *dev = ring->dev;
|
|
|
|
+ struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
|
+ enum intel_ring_hangcheck_action ha;
|
|
|
|
+ u32 tmp;
|
|
|
|
+
|
|
|
|
+ ha = head_stuck(ring, acthd);
|
|
|
|
+ if (ha != HANGCHECK_HUNG)
|
|
|
|
+ return ha;
|
|
|
|
+
|
|
if (IS_GEN2(dev))
|
|
if (IS_GEN2(dev))
|
|
return HANGCHECK_HUNG;
|
|
return HANGCHECK_HUNG;
|
|
|
|
|
|
@@ -3106,7 +3154,11 @@ static void i915_hangcheck_elapsed(struct work_struct *work)
|
|
if (ring->hangcheck.score > 0)
|
|
if (ring->hangcheck.score > 0)
|
|
ring->hangcheck.score--;
|
|
ring->hangcheck.score--;
|
|
|
|
|
|
|
|
+ /* Clear head and subunit states on seqno movement */
|
|
ring->hangcheck.acthd = ring->hangcheck.max_acthd = 0;
|
|
ring->hangcheck.acthd = ring->hangcheck.max_acthd = 0;
|
|
|
|
+
|
|
|
|
+ memset(ring->hangcheck.instdone, 0,
|
|
|
|
+ sizeof(ring->hangcheck.instdone));
|
|
}
|
|
}
|
|
|
|
|
|
ring->hangcheck.seqno = seqno;
|
|
ring->hangcheck.seqno = seqno;
|