drm/i915/execlists: Flush the tasklet on parking

Tidy up the cleanup sequence by always ensure that the tasklet is
flushed on parking (before we cleanup). The parking provides a
convenient point to ensure that the backend is truly idle.

v2: Do the full check for idleness before parking, to be sure we flush
any residual interrupt.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20190503080942.30151-1-chris@chris-wilson.co.uk
This commit is contained in:
Chris Wilson 2019-05-03 09:09:42 +01:00
parent 818f5cb3e8
commit c34c5bca33
5 changed files with 35 additions and 14 deletions

View File

@ -1094,6 +1094,8 @@ bool intel_engine_is_idle(struct intel_engine_cs *engine)
if (READ_ONCE(engine->execlists.active)) { if (READ_ONCE(engine->execlists.active)) {
struct tasklet_struct *t = &engine->execlists.tasklet; struct tasklet_struct *t = &engine->execlists.tasklet;
synchronize_hardirq(engine->i915->drm.irq);
local_bh_disable(); local_bh_disable();
if (tasklet_trylock(t)) { if (tasklet_trylock(t)) {
/* Must wait for any GPU reset in progress. */ /* Must wait for any GPU reset in progress. */

View File

@ -10,7 +10,7 @@
#include "intel_engine_pm.h" #include "intel_engine_pm.h"
#include "intel_gt_pm.h" #include "intel_gt_pm.h"
static int intel_engine_unpark(struct intel_wakeref *wf) static int __engine_unpark(struct intel_wakeref *wf)
{ {
struct intel_engine_cs *engine = struct intel_engine_cs *engine =
container_of(wf, typeof(*engine), wakeref); container_of(wf, typeof(*engine), wakeref);
@ -37,7 +37,24 @@ static int intel_engine_unpark(struct intel_wakeref *wf)
void intel_engine_pm_get(struct intel_engine_cs *engine) void intel_engine_pm_get(struct intel_engine_cs *engine)
{ {
intel_wakeref_get(engine->i915, &engine->wakeref, intel_engine_unpark); intel_wakeref_get(engine->i915, &engine->wakeref, __engine_unpark);
}
void intel_engine_park(struct intel_engine_cs *engine)
{
/*
* We are committed now to parking this engine, make sure there
* will be no more interrupts arriving later and the engine
* is truly idle.
*/
if (wait_for(intel_engine_is_idle(engine), 10)) {
struct drm_printer p = drm_debug_printer(__func__);
dev_err(engine->i915->drm.dev,
"%s is not idle before parking\n",
engine->name);
intel_engine_dump(engine, &p, NULL);
}
} }
static bool switch_to_kernel_context(struct intel_engine_cs *engine) static bool switch_to_kernel_context(struct intel_engine_cs *engine)
@ -56,7 +73,7 @@ static bool switch_to_kernel_context(struct intel_engine_cs *engine)
* Note, we do this without taking the timeline->mutex. We cannot * Note, we do this without taking the timeline->mutex. We cannot
* as we may be called while retiring the kernel context and so * as we may be called while retiring the kernel context and so
* already underneath the timeline->mutex. Instead we rely on the * already underneath the timeline->mutex. Instead we rely on the
* exclusive property of the intel_engine_park that prevents anyone * exclusive property of the __engine_park that prevents anyone
* else from creating a request on this engine. This also requires * else from creating a request on this engine. This also requires
* that the ring is empty and we avoid any waits while constructing * that the ring is empty and we avoid any waits while constructing
* the context, as they assume protection by the timeline->mutex. * the context, as they assume protection by the timeline->mutex.
@ -76,7 +93,7 @@ static bool switch_to_kernel_context(struct intel_engine_cs *engine)
return false; return false;
} }
static int intel_engine_park(struct intel_wakeref *wf) static int __engine_park(struct intel_wakeref *wf)
{ {
struct intel_engine_cs *engine = struct intel_engine_cs *engine =
container_of(wf, typeof(*engine), wakeref); container_of(wf, typeof(*engine), wakeref);
@ -114,7 +131,7 @@ static int intel_engine_park(struct intel_wakeref *wf)
void intel_engine_pm_put(struct intel_engine_cs *engine) void intel_engine_pm_put(struct intel_engine_cs *engine)
{ {
intel_wakeref_put(engine->i915, &engine->wakeref, intel_engine_park); intel_wakeref_put(engine->i915, &engine->wakeref, __engine_park);
} }
void intel_engine_init__pm(struct intel_engine_cs *engine) void intel_engine_init__pm(struct intel_engine_cs *engine)

View File

@ -13,6 +13,8 @@ struct intel_engine_cs;
void intel_engine_pm_get(struct intel_engine_cs *engine); void intel_engine_pm_get(struct intel_engine_cs *engine);
void intel_engine_pm_put(struct intel_engine_cs *engine); void intel_engine_pm_put(struct intel_engine_cs *engine);
void intel_engine_park(struct intel_engine_cs *engine);
void intel_engine_init__pm(struct intel_engine_cs *engine); void intel_engine_init__pm(struct intel_engine_cs *engine);
int intel_engines_resume(struct drm_i915_private *i915); int intel_engines_resume(struct drm_i915_private *i915);

View File

@ -136,6 +136,7 @@
#include "i915_drv.h" #include "i915_drv.h"
#include "i915_gem_render_state.h" #include "i915_gem_render_state.h"
#include "i915_vgpu.h" #include "i915_vgpu.h"
#include "intel_engine_pm.h"
#include "intel_lrc_reg.h" #include "intel_lrc_reg.h"
#include "intel_mocs.h" #include "intel_mocs.h"
#include "intel_reset.h" #include "intel_reset.h"
@ -2331,6 +2332,11 @@ static int gen8_init_rcs_context(struct i915_request *rq)
return i915_gem_render_state_emit(rq); return i915_gem_render_state_emit(rq);
} }
static void execlists_park(struct intel_engine_cs *engine)
{
intel_engine_park(engine);
}
void intel_execlists_set_default_submission(struct intel_engine_cs *engine) void intel_execlists_set_default_submission(struct intel_engine_cs *engine)
{ {
engine->submit_request = execlists_submit_request; engine->submit_request = execlists_submit_request;
@ -2342,7 +2348,7 @@ void intel_execlists_set_default_submission(struct intel_engine_cs *engine)
engine->reset.reset = execlists_reset; engine->reset.reset = execlists_reset;
engine->reset.finish = execlists_reset_finish; engine->reset.finish = execlists_reset_finish;
engine->park = NULL; engine->park = execlists_park;
engine->unpark = NULL; engine->unpark = NULL;
engine->flags |= I915_ENGINE_SUPPORTS_STATS; engine->flags |= I915_ENGINE_SUPPORTS_STATS;
@ -2355,14 +2361,6 @@ void intel_execlists_set_default_submission(struct intel_engine_cs *engine)
static void execlists_destroy(struct intel_engine_cs *engine) static void execlists_destroy(struct intel_engine_cs *engine)
{ {
/*
* Tasklet cannot be active at this point due intel_mark_active/idle
* so this is just for documentation.
*/
if (GEM_DEBUG_WARN_ON(test_bit(TASKLET_STATE_SCHED,
&engine->execlists.tasklet.state)))
tasklet_kill(&engine->execlists.tasklet);
intel_engine_cleanup_common(engine); intel_engine_cleanup_common(engine);
lrc_destroy_wa_ctx(engine); lrc_destroy_wa_ctx(engine);
kfree(engine); kfree(engine);

View File

@ -25,6 +25,7 @@
#include <linux/circ_buf.h> #include <linux/circ_buf.h>
#include <trace/events/dma_fence.h> #include <trace/events/dma_fence.h>
#include "gt/intel_engine_pm.h"
#include "gt/intel_lrc_reg.h" #include "gt/intel_lrc_reg.h"
#include "intel_guc_submission.h" #include "intel_guc_submission.h"
@ -1363,6 +1364,7 @@ static void guc_interrupts_release(struct drm_i915_private *dev_priv)
static void guc_submission_park(struct intel_engine_cs *engine) static void guc_submission_park(struct intel_engine_cs *engine)
{ {
intel_engine_park(engine);
intel_engine_unpin_breadcrumbs_irq(engine); intel_engine_unpin_breadcrumbs_irq(engine);
engine->flags &= ~I915_ENGINE_NEEDS_BREADCRUMB_TASKLET; engine->flags &= ~I915_ENGINE_NEEDS_BREADCRUMB_TASKLET;
} }