mirror of https://gitee.com/openkylin/linux.git
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: Chris Wilson <chris@chris-wilson.co.uk> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180424142945.6787-1-chris@chris-wilson.co.uk
This commit is contained in:
parent
a399715913
commit
36a501a199
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue