Skip to content

Commit

Permalink
drm/i915/gt: Call stop_ring() from ring resume, again
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Chris Wilson authored and Daniel Vetter committed Mar 24, 2021
1 parent eb5c10c commit 536f77b
Showing 1 changed file with 56 additions and 52 deletions.
108 changes: 56 additions & 52 deletions drivers/gpu/drm/i915/gt/intel_ring_submission.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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));

Expand All @@ -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)
Expand Down Expand Up @@ -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)
{
/*
Expand All @@ -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));
}
}
}

Expand Down

0 comments on commit 536f77b

Please sign in to comment.