[PATCH 25/33] drm/i915: Move finding the current active request to the scheduler
Chris Wilson
chris at chris-wilson.co.uk
Sun Jan 31 13:59:24 UTC 2021
Since finding the currently active request starts by walking the
scheduler lists under the scheduler lock, move the routine to the
scheduler.
Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
---
drivers/gpu/drm/i915/gt/intel_engine.h | 3 -
drivers/gpu/drm/i915/gt/intel_engine_cs.c | 71 ++-----------------
.../drm/i915/gt/intel_execlists_submission.c | 17 ++++-
drivers/gpu/drm/i915/i915_gpu_error.c | 18 +++--
drivers/gpu/drm/i915/i915_gpu_error.h | 4 +-
drivers/gpu/drm/i915/i915_scheduler.c | 43 +++++++++++
drivers/gpu/drm/i915/i915_scheduler_types.h | 3 +
7 files changed, 79 insertions(+), 80 deletions(-)
diff --git a/drivers/gpu/drm/i915/gt/intel_engine.h b/drivers/gpu/drm/i915/gt/intel_engine.h
index da7cdfbb5bec..e6b511b5363c 100644
--- a/drivers/gpu/drm/i915/gt/intel_engine.h
+++ b/drivers/gpu/drm/i915/gt/intel_engine.h
@@ -229,9 +229,6 @@ void intel_engine_dump(struct intel_engine_cs *engine,
ktime_t intel_engine_get_busy_time(struct intel_engine_cs *engine,
ktime_t *now);
-struct i915_request *
-intel_engine_find_active_request(struct intel_engine_cs *engine);
-
u32 intel_engine_context_size(struct intel_gt *gt, u8 class);
void intel_engine_init_active(struct intel_engine_cs *engine,
diff --git a/drivers/gpu/drm/i915/gt/intel_engine_cs.c b/drivers/gpu/drm/i915/gt/intel_engine_cs.c
index 947c003afd21..c0c69a3410d3 100644
--- a/drivers/gpu/drm/i915/gt/intel_engine_cs.c
+++ b/drivers/gpu/drm/i915/gt/intel_engine_cs.c
@@ -1277,7 +1277,7 @@ bool intel_engine_can_store_dword(struct intel_engine_cs *engine)
}
}
-static struct intel_timeline *get_timeline(struct i915_request *rq)
+static struct intel_timeline *get_timeline(const struct i915_request *rq)
{
struct intel_timeline *tl;
@@ -1506,7 +1506,8 @@ static void intel_engine_print_registers(struct intel_engine_cs *engine,
}
}
-static void print_request_ring(struct drm_printer *m, struct i915_request *rq)
+static void
+print_request_ring(struct drm_printer *m, const struct i915_request *rq)
{
void *ring;
int size;
@@ -1591,7 +1592,7 @@ void intel_engine_dump(struct intel_engine_cs *engine,
{
struct i915_gpu_error * const error = &engine->i915->gpu_error;
struct i915_sched_engine *se = intel_engine_get_scheduler(engine);
- struct i915_request *rq;
+ const struct i915_request *rq;
intel_wakeref_t wakeref;
unsigned long flags;
ktime_t dummy;
@@ -1632,8 +1633,9 @@ void intel_engine_dump(struct intel_engine_cs *engine,
drm_printf(m, "\tRequests:\n");
+ rcu_read_lock();
spin_lock_irqsave(&se->lock, flags);
- rq = intel_engine_find_active_request(engine);
+ rq = se->active_request(se);
if (rq) {
struct intel_timeline *tl = get_timeline(rq);
@@ -1665,6 +1667,7 @@ void intel_engine_dump(struct intel_engine_cs *engine,
}
drm_printf(m, "\tOn hold?: %lu\n", list_count(&se->hold));
spin_unlock_irqrestore(&se->lock, flags);
+ rcu_read_unlock();
drm_printf(m, "\tMMIO base: 0x%08x\n", engine->mmio_base);
wakeref = intel_runtime_pm_get_if_in_use(engine->uncore->rpm);
@@ -1713,66 +1716,6 @@ ktime_t intel_engine_get_busy_time(struct intel_engine_cs *engine, ktime_t *now)
return ktime_add(total, start);
}
-static bool match_ring(struct i915_request *rq)
-{
- u32 ring = ENGINE_READ(rq->engine, RING_START);
-
- return ring == i915_ggtt_offset(rq->ring->vma);
-}
-
-struct i915_request *
-intel_engine_find_active_request(struct intel_engine_cs *engine)
-{
- struct i915_sched_engine *se = intel_engine_get_scheduler(engine);
- struct i915_request *request, *active = NULL;
-
- /*
- * We are called by the error capture, reset and to dump engine
- * state at random points in time. In particular, note that neither is
- * crucially ordered with an interrupt. After a hang, the GPU is dead
- * and we assume that no more writes can happen (we waited long enough
- * for all writes that were in transaction to be flushed) - adding an
- * extra delay for a recent interrupt is pointless. Hence, we do
- * not need an engine->irq_seqno_barrier() before the seqno reads.
- * At all other times, we must assume the GPU is still running, but
- * we only care about the snapshot of this moment.
- */
- lockdep_assert_held(&se->lock);
-
- rcu_read_lock();
- request = execlists_active(&engine->execlists);
- if (request) {
- struct intel_timeline *tl = request->context->timeline;
-
- list_for_each_entry_from_reverse(request, &tl->requests, link) {
- if (__i915_request_is_complete(request))
- break;
-
- active = request;
- }
- }
- rcu_read_unlock();
- if (active)
- return active;
-
- list_for_each_entry(request, &se->requests, sched.link) {
- if (__i915_request_is_complete(request))
- continue;
-
- if (!__i915_request_has_started(request))
- continue;
-
- /* More than one preemptible request may match! */
- if (!match_ring(request))
- continue;
-
- active = request;
- break;
- }
-
- return active;
-}
-
#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
#include "mock_engine.c"
#include "selftest_engine.c"
diff --git a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
index c29a1e0749ce..f7ab49fc4099 100644
--- a/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
+++ b/drivers/gpu/drm/i915/gt/intel_execlists_submission.c
@@ -2336,7 +2336,7 @@ static void sanitize_hwsp(struct intel_engine_cs *engine)
static void execlists_sanitize(struct intel_engine_cs *engine)
{
- GEM_BUG_ON(execlists_active(&engine->execlists));
+ GEM_BUG_ON(*engine->execlists.active);
/*
* Poison residual state on resume, in case the suspend didn't!
@@ -2759,6 +2759,20 @@ static void execlists_park(struct intel_engine_cs *engine)
cancel_timer(&engine->execlists.preempt);
}
+static const struct i915_request *
+execlists_active_request(struct i915_sched_engine *se)
+{
+ struct intel_engine_cs *engine =
+ container_of(se, typeof(*engine), sched);
+ struct i915_request *rq;
+
+ rq = execlists_active(&engine->execlists);
+ if (rq)
+ rq = active_request(rq->context->timeline, rq);
+
+ return rq;
+}
+
static bool can_preempt(struct intel_engine_cs *engine)
{
if (INTEL_GEN(engine->i915) > 8)
@@ -2894,6 +2908,7 @@ int intel_execlists_submission_setup(struct intel_engine_cs *engine)
struct intel_uncore *uncore = engine->uncore;
u32 base = engine->mmio_base;
+ engine->sched.active_request = execlists_active_request;
tasklet_setup(&engine->sched.tasklet, execlists_submission_tasklet);
timer_setup(&engine->execlists.timer, execlists_timeslice, 0);
timer_setup(&engine->execlists.preempt, execlists_preempt, 0);
diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c
index 47249bff6705..895376a5c035 100644
--- a/drivers/gpu/drm/i915/i915_gpu_error.c
+++ b/drivers/gpu/drm/i915/i915_gpu_error.c
@@ -1262,15 +1262,11 @@ static bool record_context(struct i915_gem_context_coredump *e,
struct i915_gem_context *ctx;
bool simulated;
- rcu_read_lock();
-
ctx = rcu_dereference(rq->context->gem_context);
if (ctx && !kref_get_unless_zero(&ctx->ref))
ctx = NULL;
- if (!ctx) {
- rcu_read_unlock();
+ if (!ctx)
return true;
- }
if (I915_SELFTEST_ONLY(!ctx->client)) {
strcpy(e->comm, "[kernel]");
@@ -1279,8 +1275,6 @@ static bool record_context(struct i915_gem_context_coredump *e,
e->pid = pid_nr(i915_drm_client_pid(ctx->client));
}
- rcu_read_unlock();
-
e->sched_attr = ctx->sched;
e->guilty = atomic_read(&ctx->guilty_count);
e->active = atomic_read(&ctx->active_count);
@@ -1368,12 +1362,14 @@ intel_engine_coredump_alloc(struct intel_engine_cs *engine, gfp_t gfp)
struct intel_engine_capture_vma *
intel_engine_coredump_add_request(struct intel_engine_coredump *ee,
- struct i915_request *rq,
+ const struct i915_request *rq,
gfp_t gfp)
{
struct intel_engine_capture_vma *vma = NULL;
+ rcu_read_lock();
ee->simulated |= record_context(&ee->context, rq);
+ rcu_read_unlock();
if (ee->simulated)
return NULL;
@@ -1436,19 +1432,21 @@ capture_engine(struct intel_engine_cs *engine,
struct intel_engine_capture_vma *capture = NULL;
struct i915_sched_engine *se = intel_engine_get_scheduler(engine);
struct intel_engine_coredump *ee;
- struct i915_request *rq;
+ const struct i915_request *rq;
unsigned long flags;
ee = intel_engine_coredump_alloc(engine, GFP_KERNEL);
if (!ee)
return NULL;
+ rcu_read_lock();
spin_lock_irqsave(&se->lock, flags);
- rq = intel_engine_find_active_request(engine);
+ rq = se->active_request(se);
if (rq)
capture = intel_engine_coredump_add_request(ee, rq,
ATOMIC_MAYFAIL);
spin_unlock_irqrestore(&se->lock, flags);
+ rcu_read_unlock();
if (!capture) {
kfree(ee);
return NULL;
diff --git a/drivers/gpu/drm/i915/i915_gpu_error.h b/drivers/gpu/drm/i915/i915_gpu_error.h
index 1764fd254df3..2d8debabfe28 100644
--- a/drivers/gpu/drm/i915/i915_gpu_error.h
+++ b/drivers/gpu/drm/i915/i915_gpu_error.h
@@ -235,7 +235,7 @@ intel_engine_coredump_alloc(struct intel_engine_cs *engine, gfp_t gfp);
struct intel_engine_capture_vma *
intel_engine_coredump_add_request(struct intel_engine_coredump *ee,
- struct i915_request *rq,
+ const struct i915_request *rq,
gfp_t gfp);
void intel_engine_coredump_add_vma(struct intel_engine_coredump *ee,
@@ -299,7 +299,7 @@ intel_engine_coredump_alloc(struct intel_engine_cs *engine, gfp_t gfp)
static inline struct intel_engine_capture_vma *
intel_engine_coredump_add_request(struct intel_engine_coredump *ee,
- struct i915_request *rq,
+ const struct i915_request *rq,
gfp_t gfp)
{
return NULL;
diff --git a/drivers/gpu/drm/i915/i915_scheduler.c b/drivers/gpu/drm/i915/i915_scheduler.c
index 4ff5fe91cfcd..b181f9b3ad3d 100644
--- a/drivers/gpu/drm/i915/i915_scheduler.c
+++ b/drivers/gpu/drm/i915/i915_scheduler.c
@@ -91,6 +91,48 @@ static void i915_sched_init_ipi(struct i915_sched_ipi *ipi)
ipi->list = NULL;
}
+static bool match_ring(struct i915_request *rq)
+{
+ u32 ring = ENGINE_READ(rq->engine, RING_START);
+
+ return ring == i915_ggtt_offset(rq->ring->vma);
+}
+
+static const struct i915_request *active_request(struct i915_sched_engine *se)
+{
+ struct i915_request *request, *active = NULL;
+
+ /*
+ * We are called by the error capture, reset and to dump engine
+ * state at random points in time. In particular, note that neither is
+ * crucially ordered with an interrupt. After a hang, the GPU is dead
+ * and we assume that no more writes can happen (we waited long enough
+ * for all writes that were in transaction to be flushed) - adding an
+ * extra delay for a recent interrupt is pointless. Hence, we do
+ * not need an engine->irq_seqno_barrier() before the seqno reads.
+ * At all other times, we must assume the GPU is still running, but
+ * we only care about the snapshot of this moment.
+ */
+ lockdep_assert_held(&se->lock);
+
+ list_for_each_entry(request, &se->requests, sched.link) {
+ if (__i915_request_is_complete(request))
+ continue;
+
+ if (!__i915_request_has_started(request))
+ continue;
+
+ /* More than one preemptible request may match! */
+ if (!match_ring(request))
+ continue;
+
+ active = request;
+ break;
+ }
+
+ return active;
+}
+
void i915_sched_init_engine(struct i915_sched_engine *se,
struct device *dev,
const char *name,
@@ -112,6 +154,7 @@ void i915_sched_init_engine(struct i915_sched_engine *se,
i915_sched_init_ipi(&se->ipi);
se->submit_request = i915_request_enqueue;
+ se->active_request = active_request;
/*
* Due to an interesting quirk in lockdep's internal debug tracking,
diff --git a/drivers/gpu/drm/i915/i915_scheduler_types.h b/drivers/gpu/drm/i915/i915_scheduler_types.h
index bdce2785d03c..9bd8a19d0737 100644
--- a/drivers/gpu/drm/i915/i915_scheduler_types.h
+++ b/drivers/gpu/drm/i915/i915_scheduler_types.h
@@ -35,6 +35,9 @@ struct i915_sched_engine {
*/
void (*submit_request)(struct i915_request *rq);
+ const struct i915_request *
+ (*active_request)(struct i915_sched_engine *se);
+
struct list_head requests; /* active request, on HW */
struct list_head hold; /* ready requests, but on hold */
/**
--
2.20.1
More information about the Intel-gfx-trybot
mailing list