drm/i915/gt: Call stop_ring() from ring resume, again

For reasons I cannot explain, except to say this is Sandybridge after
all, call stop_ring() again dring ring resume in order to prevent
mysterious hard hangs.

Testcase: igt/i915_selftest/hangcheck # snb
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Acked-by: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20210121154950.19898-3-chris@chris-wilson.co.uk
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
This commit is contained in:
Chris Wilson 2021-01-21 15:49:50 +00:00 committed by Daniel Vetter
parent eb5c10cbbc
commit 536f77b1ca

View file

@ -183,15 +183,36 @@ static void set_pp_dir(struct intel_engine_cs *engine)
}
}
static bool stop_ring(struct intel_engine_cs *engine)
{
/* Empty the ring by skipping to the end */
ENGINE_WRITE_FW(engine, RING_HEAD, ENGINE_READ_FW(engine, RING_TAIL));
ENGINE_POSTING_READ(engine, RING_HEAD);
/* The ring must be empty before it is disabled */
ENGINE_WRITE_FW(engine, RING_CTL, 0);
ENGINE_POSTING_READ(engine, RING_CTL);
/* Then reset the disabled ring */
ENGINE_WRITE_FW(engine, RING_HEAD, 0);
ENGINE_WRITE_FW(engine, RING_TAIL, 0);
return (ENGINE_READ_FW(engine, RING_HEAD) & HEAD_ADDR) == 0;
}
static int xcs_resume(struct intel_engine_cs *engine)
{
struct drm_i915_private *dev_priv = engine->i915;
struct intel_ring *ring = engine->legacy.ring;
ENGINE_TRACE(engine, "ring:{HEAD:%04x, TAIL:%04x}\n",
ring->head, ring->tail);
if (HWS_NEEDS_PHYSICAL(dev_priv))
/* Double check the ring is empty & disabled before we resume */
synchronize_hardirq(engine->i915->drm.irq);
if (!stop_ring(engine))
goto err;
if (HWS_NEEDS_PHYSICAL(engine->i915))
ring_setup_phys_status_page(engine);
else
ring_setup_status_page(engine);
@ -228,21 +249,10 @@ 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)) {
drm_err(&dev_priv->drm,
"%s initialization failed; "
"ctl %08x (valid? %d) head %08x [%08x] tail %08x [%08x] start %08x [expected %08x]\n",
engine->name,
ENGINE_READ(engine, RING_CTL),
ENGINE_READ(engine, RING_CTL) & RING_VALID,
ENGINE_READ(engine, RING_HEAD), ring->head,
ENGINE_READ(engine, RING_TAIL), ring->tail,
ENGINE_READ(engine, RING_START),
i915_ggtt_offset(ring->vma));
return -EIO;
}
5000, 0, NULL))
goto err;
if (INTEL_GEN(dev_priv) > 2)
if (INTEL_GEN(engine->i915) > 2)
ENGINE_WRITE_FW(engine,
RING_MI_MODE, _MASKED_BIT_DISABLE(STOP_RING));
@ -255,6 +265,19 @@ static int xcs_resume(struct intel_engine_cs *engine)
/* Papering over lost _interrupts_ immediately following the restart */
intel_engine_signal_breadcrumbs(engine);
return 0;
err:
drm_err(&engine->i915->drm,
"%s initialization failed; "
"ctl %08x (valid? %d) head %08x [%08x] tail %08x [%08x] start %08x [expected %08x]\n",
engine->name,
ENGINE_READ(engine, RING_CTL),
ENGINE_READ(engine, RING_CTL) & RING_VALID,
ENGINE_READ(engine, RING_HEAD), ring->head,
ENGINE_READ(engine, RING_TAIL), ring->tail,
ENGINE_READ(engine, RING_START),
i915_ggtt_offset(ring->vma));
return -EIO;
}
static void sanitize_hwsp(struct intel_engine_cs *engine)
@ -290,23 +313,6 @@ static void xcs_sanitize(struct intel_engine_cs *engine)
clflush_cache_range(engine->status_page.addr, PAGE_SIZE);
}
static bool stop_ring(struct intel_engine_cs *engine)
{
/* Empty the ring by skipping to the end */
ENGINE_WRITE_FW(engine, RING_HEAD, ENGINE_READ_FW(engine, RING_TAIL));
ENGINE_POSTING_READ(engine, RING_HEAD);
/* The ring must be empty before it is disabled */
ENGINE_WRITE_FW(engine, RING_CTL, 0);
ENGINE_POSTING_READ(engine, RING_CTL);
/* Then reset the disabled ring */
ENGINE_WRITE_FW(engine, RING_HEAD, 0);
ENGINE_WRITE_FW(engine, RING_TAIL, 0);
return (ENGINE_READ_FW(engine, RING_HEAD) & HEAD_ADDR) == 0;
}
static void reset_prepare(struct intel_engine_cs *engine)
{
/*
@ -329,25 +335,23 @@ static void reset_prepare(struct intel_engine_cs *engine)
if (!stop_ring(engine)) {
/* G45 ring initialization often fails to reset head to zero */
drm_dbg(&engine->i915->drm,
"%s head not reset to zero "
"ctl %08x head %08x tail %08x start %08x\n",
engine->name,
ENGINE_READ_FW(engine, RING_CTL),
ENGINE_READ_FW(engine, RING_HEAD),
ENGINE_READ_FW(engine, RING_TAIL),
ENGINE_READ_FW(engine, RING_START));
}
if (!stop_ring(engine)) {
drm_err(&engine->i915->drm,
"failed to set %s head to zero "
"ctl %08x head %08x tail %08x start %08x\n",
engine->name,
ENGINE_READ_FW(engine, RING_CTL),
ENGINE_READ_FW(engine, RING_HEAD),
ENGINE_READ_FW(engine, RING_TAIL),
ENGINE_READ_FW(engine, RING_START));
ENGINE_TRACE(engine,
"HEAD not reset to zero, "
"{ CTL:%08x, HEAD:%08x, TAIL:%08x, START:%08x }\n",
ENGINE_READ_FW(engine, RING_CTL),
ENGINE_READ_FW(engine, RING_HEAD),
ENGINE_READ_FW(engine, RING_TAIL),
ENGINE_READ_FW(engine, RING_START));
if (!stop_ring(engine)) {
drm_err(&engine->i915->drm,
"failed to set %s head to zero "
"ctl %08x head %08x tail %08x start %08x\n",
engine->name,
ENGINE_READ_FW(engine, RING_CTL),
ENGINE_READ_FW(engine, RING_HEAD),
ENGINE_READ_FW(engine, RING_TAIL),
ENGINE_READ_FW(engine, RING_START));
}
}
}