@@ -192,6 +192,7 @@ static bool stop_ring(struct intel_engine_cs *engine)
static int xcs_resume(struct intel_engine_cs *engine)
{
struct intel_ring *ring = engine->legacy.ring;
+ ktime_t kt;
ENGINE_TRACE(engine, "ring:{HEAD:%04x, TAIL:%04x}\n",
ring->head, ring->tail);
@@ -230,9 +231,31 @@ static int xcs_resume(struct intel_engine_cs *engine)
set_pp_dir(engine);
/* First wake the ring up to an empty/idle ring */
- ENGINE_WRITE_FW(engine, RING_HEAD, ring->head);
+ if (IS_HASWELL(engine->i915)) {
+ /*
+ * On Haswell, resets fails because engine resumes
+ * from incorrect RING_HEAD and then GPU may be then
+ * fed to invalid instrcutions, which may lead to unrecoverable hang.
+ * So at first write doesn't succeed then try again.
+ */
+ for ((kt) = ktime_get() + (2 * NSEC_PER_MSEC);
+ ktime_before(ktime_get(), (kt)); cpu_relax()) {
+ ENGINE_WRITE_FW(engine, RING_HEAD, ring->head);
+ if (ENGINE_READ_FW(engine, RING_HEAD) == ring->head)
+ break;
+ }
+ } else {
+ ENGINE_WRITE_FW(engine, RING_HEAD, ring->head);
+ }
+
ENGINE_WRITE_FW(engine, RING_TAIL, ring->head);
- ENGINE_POSTING_READ(engine, RING_TAIL);
+ if (ENGINE_READ_FW(engine, RING_HEAD) != ENGINE_READ_FW(engine, RING_TAIL)) {
+ ENGINE_TRACE(engine, "failed to reset empty ring: [%x, %x]: %x\n",
+ ENGINE_READ_FW(engine, RING_HEAD),
+ ENGINE_READ_FW(engine, RING_TAIL),
+ ring->head);
+ goto err;
+ }
ENGINE_WRITE_FW(engine, RING_CTL,
RING_CTL_SIZE(ring->size) | RING_VALID);
@@ -241,12 +264,16 @@ static int xcs_resume(struct intel_engine_cs *engine)
if (__intel_wait_for_register_fw(engine->uncore,
RING_CTL(engine->mmio_base),
RING_VALID, RING_VALID,
- 5000, 0, NULL))
+ 5000, 0, NULL)) {
+ ENGINE_TRACE(engine, "failed to restart\n");
goto err;
+ }
- if (GRAPHICS_VER(engine->i915) > 2)
+ if (GRAPHICS_VER(engine->i915) > 2) {
ENGINE_WRITE_FW(engine,
RING_MI_MODE, _MASKED_BIT_DISABLE(STOP_RING));
+ ENGINE_POSTING_READ(engine, RING_MI_MODE);
+ }
/* Now awake, let it get started */
if (ring->tail != ring->head) {