Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 36a501a1 authored by Chris Wilson's avatar Chris Wilson
Browse files

drm/i915/breadcrumbs: Keep the fake irq armed across reset



Instead of synchronously cancelling the timer and re-enabling it inside
the reset callbacks, keep the timer enabled and let it die on its next
wakeup if no longer required. This allows
intel_engine_reset_breadcrumbs() to be used from an atomic
(timer/softirq) context such as required for resetting an engine.

It also allows us to react better to the user poking around debugfs for
testing missed irqs.

v2: Tighten the order of del_timer_sync as the fake_irq timer
may trigger the hangcheck timer, and so we should cancel it first and
then cancel the hangcheck (Mika)

Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com>
Reviewed-by: default avatarMika Kuoppala <mika.kuoppala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20180424142945.6787-1-chris@chris-wilson.co.uk
parent a3997159
Loading
Loading
Loading
Loading
+20 −9
Original line number Original line Diff line number Diff line
@@ -130,11 +130,12 @@ static void intel_breadcrumbs_hangcheck(struct timer_list *t)


static void intel_breadcrumbs_fake_irq(struct timer_list *t)
static void intel_breadcrumbs_fake_irq(struct timer_list *t)
{
{
	struct intel_engine_cs *engine = from_timer(engine, t,
	struct intel_engine_cs *engine =
						    breadcrumbs.fake_irq);
		from_timer(engine, t, breadcrumbs.fake_irq);
	struct intel_breadcrumbs *b = &engine->breadcrumbs;
	struct intel_breadcrumbs *b = &engine->breadcrumbs;


	/* The timer persists in case we cannot enable interrupts,
	/*
	 * The timer persists in case we cannot enable interrupts,
	 * or if we have previously seen seqno/interrupt incoherency
	 * or if we have previously seen seqno/interrupt incoherency
	 * ("missed interrupt" syndrome, better known as a "missed breadcrumb").
	 * ("missed interrupt" syndrome, better known as a "missed breadcrumb").
	 * Here the worker will wake up every jiffie in order to kick the
	 * Here the worker will wake up every jiffie in order to kick the
@@ -148,6 +149,12 @@ static void intel_breadcrumbs_fake_irq(struct timer_list *t)
	if (!b->irq_armed)
	if (!b->irq_armed)
		return;
		return;


	/* If the user has disabled the fake-irq, restore the hangchecking */
	if (!test_bit(engine->id, &engine->i915->gpu_error.missed_irq_rings)) {
		mod_timer(&b->hangcheck, wait_timeout());
		return;
	}

	mod_timer(&b->fake_irq, jiffies + 1);
	mod_timer(&b->fake_irq, jiffies + 1);
}
}


@@ -831,8 +838,8 @@ static void cancel_fake_irq(struct intel_engine_cs *engine)
{
{
	struct intel_breadcrumbs *b = &engine->breadcrumbs;
	struct intel_breadcrumbs *b = &engine->breadcrumbs;


	del_timer_sync(&b->fake_irq); /* may queue b->hangcheck */
	del_timer_sync(&b->hangcheck);
	del_timer_sync(&b->hangcheck);
	del_timer_sync(&b->fake_irq);
	clear_bit(engine->id, &engine->i915->gpu_error.missed_irq_rings);
	clear_bit(engine->id, &engine->i915->gpu_error.missed_irq_rings);
}
}


@@ -840,15 +847,22 @@ void intel_engine_reset_breadcrumbs(struct intel_engine_cs *engine)
{
{
	struct intel_breadcrumbs *b = &engine->breadcrumbs;
	struct intel_breadcrumbs *b = &engine->breadcrumbs;


	cancel_fake_irq(engine);
	spin_lock_irq(&b->irq_lock);
	spin_lock_irq(&b->irq_lock);


	/*
	 * Leave the fake_irq timer enabled (if it is running), but clear the
	 * bit so that it turns itself off on its next wake up and goes back
	 * to the long hangcheck interval if still required.
	 */
	clear_bit(engine->id, &engine->i915->gpu_error.missed_irq_rings);

	if (b->irq_enabled)
	if (b->irq_enabled)
		irq_enable(engine);
		irq_enable(engine);
	else
	else
		irq_disable(engine);
		irq_disable(engine);


	/* We set the IRQ_BREADCRUMB bit when we enable the irq presuming the
	/*
	 * We set the IRQ_BREADCRUMB bit when we enable the irq presuming the
	 * GPU is active and may have already executed the MI_USER_INTERRUPT
	 * GPU is active and may have already executed the MI_USER_INTERRUPT
	 * before the CPU is ready to receive. However, the engine is currently
	 * before the CPU is ready to receive. However, the engine is currently
	 * idle (we haven't started it yet), there is no possibility for a
	 * idle (we haven't started it yet), there is no possibility for a
@@ -857,9 +871,6 @@ void intel_engine_reset_breadcrumbs(struct intel_engine_cs *engine)
	 */
	 */
	clear_bit(ENGINE_IRQ_BREADCRUMB, &engine->irq_posted);
	clear_bit(ENGINE_IRQ_BREADCRUMB, &engine->irq_posted);


	if (b->irq_armed)
		enable_fake_irq(b);

	spin_unlock_irq(&b->irq_lock);
	spin_unlock_irq(&b->irq_lock);
}
}