[PATCH 49/49] request-suspend
Chris Wilson
chris at chris-wilson.co.uk
Mon Jan 25 12:07:54 UTC 2021
---
drivers/gpu/drm/i915/i915_request.h | 23 +++
drivers/gpu/drm/i915/i915_scheduler.c | 96 ++++++++--
drivers/gpu/drm/i915/selftests/i915_request.c | 168 ++++++++++++++++++
3 files changed, 272 insertions(+), 15 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_request.h b/drivers/gpu/drm/i915/i915_request.h
index a74d8204fca9..293c474da6ce 100644
--- a/drivers/gpu/drm/i915/i915_request.h
+++ b/drivers/gpu/drm/i915/i915_request.h
@@ -137,6 +137,11 @@ enum {
* the GPU. Here we track such boost requests on a per-request basis.
*/
I915_FENCE_FLAG_BOOST,
+
+ /*
+ * I915_FENCE_FLAG_SUSPENDED - this request should not be executed
+ */
+ I915_FENCE_FLAG_SUSPENDED,
};
/**
@@ -368,6 +373,9 @@ void i915_request_unsubmit(struct i915_request *request);
void i915_request_cancel(struct i915_request *rq, int error);
+void i915_request_suspend(struct i915_request *rq);
+void i915_request_resume(struct i915_request *rq);
+
long i915_request_wait(struct i915_request *rq,
unsigned int flags,
long timeout)
@@ -591,6 +599,21 @@ static inline void i915_request_clear_hold(struct i915_request *rq)
clear_bit(I915_FENCE_FLAG_HOLD, &rq->fence.flags);
}
+static inline bool i915_request_is_suspended(const struct i915_request *rq)
+{
+ return unlikely(test_bit(I915_FENCE_FLAG_SUSPENDED, &rq->fence.flags));
+}
+
+static inline bool i915_request_set_suspended(struct i915_request *rq)
+{
+ return !test_and_set_bit(I915_FENCE_FLAG_SUSPENDED, &rq->fence.flags);
+}
+
+static inline bool i915_request_clear_suspended(struct i915_request *rq)
+{
+ return test_and_clear_bit(I915_FENCE_FLAG_SUSPENDED, &rq->fence.flags);
+}
+
static inline struct intel_timeline *
i915_request_timeline(const struct i915_request *rq)
{
diff --git a/drivers/gpu/drm/i915/i915_scheduler.c b/drivers/gpu/drm/i915/i915_scheduler.c
index 076ae795d852..226bb9902dbf 100644
--- a/drivers/gpu/drm/i915/i915_scheduler.c
+++ b/drivers/gpu/drm/i915/i915_scheduler.c
@@ -8,6 +8,7 @@
#include <linux/mutex.h>
#include <linux/prandom.h>
+#include "gt/intel_engine_heartbeat.h"
#include "gt/intel_ring.h"
#include "gt/intel_lrc_reg.h"
@@ -945,6 +946,9 @@ static bool hold_request(const struct i915_request *rq)
static bool ancestor_on_hold(const struct intel_engine_cs *engine,
const struct i915_request *rq)
{
+ if (i915_request_is_suspended(rq))
+ return true;
+
GEM_BUG_ON(i915_request_on_hold(rq));
return unlikely(!list_empty(&engine->active.hold)) && hold_request(rq);
}
@@ -1019,6 +1023,53 @@ void i915_request_enqueue(struct i915_request *rq)
i915_sched_kick(se);
}
+void i915_request_suspend(struct i915_request *rq)
+{
+ struct intel_engine_cs *engine;
+ unsigned long flags;
+
+ if (i915_request_is_suspended(rq))
+ return;
+
+ RQ_TRACE(rq, "suspending, ready? %d, active? %d\n",
+ i915_request_is_ready(rq),
+ i915_request_is_active(rq));
+
+ engine = lock_engine_irqsave(rq, flags);
+ if (!i915_request_set_suspended(rq))
+ goto unlock;
+
+ if (!i915_request_is_ready(rq))
+ goto unlock;
+
+ if (!i915_request_is_active(rq))
+ __intel_engine_suspend_request(engine, rq);
+
+unlock:
+ spin_unlock_irqrestore(&engine->active.lock, flags);
+
+ if (i915_request_is_active(rq))
+ intel_engine_pulse(engine);
+}
+
+void i915_request_resume(struct i915_request *rq)
+{
+ struct intel_engine_cs *engine;
+ unsigned long flags;
+
+ if (!i915_request_is_suspended(rq))
+ return;
+
+ RQ_TRACE(rq, "resuming\n");
+
+ engine = lock_engine_irqsave(rq, flags);
+
+ if (i915_request_clear_suspended(rq))
+ __intel_engine_resume_request(engine, rq);
+
+ spin_unlock_irqrestore(&engine->active.lock, flags);
+}
+
struct i915_request *
__intel_engine_rewind_requests(struct intel_engine_cs *engine)
{
@@ -1038,22 +1089,26 @@ __intel_engine_rewind_requests(struct intel_engine_cs *engine)
__i915_request_unsubmit(rq);
- if (__i915_request_has_started(rq)) {
- rq->sched.deadline =
- min(rq_deadline(rq),
- next_virtual_deadline(rq_prio(rq)));
- }
- GEM_BUG_ON(rq_deadline(rq) == I915_DEADLINE_NEVER);
+ if (i915_request_is_suspended(rq)) {
+ __intel_engine_suspend_request(engine, rq);
+ } else {
+ if (__i915_request_has_started(rq)) {
+ rq->sched.deadline =
+ min(rq_deadline(rq),
+ next_virtual_deadline(rq_prio(rq)));
+ }
+ GEM_BUG_ON(rq_deadline(rq) == I915_DEADLINE_NEVER);
- if (rq_deadline(rq) != deadline) {
- deadline = rq_deadline(rq);
- pl = lookup_priolist(engine, deadline);
- }
- GEM_BUG_ON(i915_sched_is_idle(&engine->active));
+ if (rq_deadline(rq) != deadline) {
+ deadline = rq_deadline(rq);
+ pl = lookup_priolist(engine, deadline);
+ }
+ GEM_BUG_ON(i915_sched_is_idle(&engine->active));
- GEM_BUG_ON(i915_request_in_priority_queue(rq));
- list_move(&rq->sched.link, pl);
- set_bit(I915_FENCE_FLAG_PQUEUE, &rq->fence.flags);
+ GEM_BUG_ON(i915_request_in_priority_queue(rq));
+ list_move(&rq->sched.link, pl);
+ set_bit(I915_FENCE_FLAG_PQUEUE, &rq->fence.flags);
+ }
/* Check in case we rollback so far we wrap [size/2] */
if (intel_ring_direction(rq->ring,
@@ -1073,12 +1128,17 @@ bool __intel_engine_suspend_request(struct intel_engine_cs *engine,
LIST_HEAD(list);
lockdep_assert_held(&engine->active.lock);
- GEM_BUG_ON(i915_request_on_hold(rq));
GEM_BUG_ON(rq->engine != engine);
if (__i915_request_is_complete(rq)) /* too late! */
return false;
+ if (i915_request_on_hold(rq))
+ return false;
+
+ ENGINE_TRACE(engine, "suspending request %llx:%lld\n",
+ rq->fence.context, rq->fence.seqno);
+
/*
* Transfer this request onto the hold queue to prevent it
* being resumbitted to HW (and potentially completed) before we have
@@ -1150,6 +1210,12 @@ void __intel_engine_resume_request(struct intel_engine_cs *engine,
lockdep_assert_held(&engine->active.lock);
+ if (!i915_request_on_hold(rq))
+ return;
+
+ ENGINE_TRACE(engine, "resuming request %llx:%lld\n",
+ rq->fence.context, rq->fence.seqno);
+
/*
* Move this request back to the priority queue, and all of its
* children and grandchildren that were suspended along with it.
diff --git a/drivers/gpu/drm/i915/selftests/i915_request.c b/drivers/gpu/drm/i915/selftests/i915_request.c
index 66cdda2b9abf..e843d1ba5e04 100644
--- a/drivers/gpu/drm/i915/selftests/i915_request.c
+++ b/drivers/gpu/drm/i915/selftests/i915_request.c
@@ -854,6 +854,173 @@ static int live_cancel_request(void *arg)
return 0;
}
+static int __suspend_inactive(struct intel_engine_cs *engine)
+{
+ struct intel_context *ce;
+ struct igt_spinner spin;
+ struct i915_request *rq;
+ int err = 0;
+
+ if (igt_spinner_init(&spin, engine->gt))
+ return -ENOMEM;
+
+ ce = intel_context_create(engine);
+ if (IS_ERR(ce)) {
+ err = PTR_ERR(ce);
+ goto out_spin;
+ }
+
+ rq = intel_context_create_request(ce);
+ if (IS_ERR(rq)) {
+ err = PTR_ERR(rq);
+ goto out_ce;
+ }
+
+ pr_debug("%s: Suspending inactive request\n", engine->name);
+ i915_request_suspend(rq);
+ i915_request_get(rq);
+ i915_request_add(rq);
+
+ intel_engine_flush_submission(engine);
+ GEM_BUG_ON(!i915_request_is_ready(rq));
+
+ if (i915_request_is_active(rq)) {
+ GEM_TRACE_ERR("Suspended request executed!\n");
+ GEM_TRACE_DUMP();
+ err = -EINVAL;
+ goto out_rq;
+ }
+
+ i915_request_resume(rq);
+ if (i915_request_wait(rq, 0, HZ / 5) < 0) {
+ GEM_TRACE_ERR("Resumed request did not complete\n");
+ GEM_TRACE_DUMP();
+ err = -ETIME;
+ }
+
+out_rq:
+ i915_request_put(rq);
+out_ce:
+ intel_context_put(ce);
+out_spin:
+ igt_spinner_fini(&spin);
+ return err;
+}
+
+static int __suspend_active(struct intel_engine_cs *engine)
+{
+ struct intel_context *ce;
+ struct igt_spinner spin;
+ struct i915_request *rq;
+ int err = 0;
+
+ if (igt_spinner_init(&spin, engine->gt))
+ return -ENOMEM;
+
+ ce = intel_context_create(engine);
+ if (IS_ERR(ce)) {
+ err = PTR_ERR(ce);
+ goto out_spin;
+ }
+
+ rq = igt_spinner_create_request(&spin, ce, MI_ARB_CHECK);
+ if (IS_ERR(rq)) {
+ err = PTR_ERR(rq);
+ goto out_ce;
+ }
+
+ pr_debug("%s: Suspending active request\n", engine->name);
+ i915_request_get(rq);
+ i915_request_add(rq);
+ if (!igt_wait_for_spinner(&spin, rq)) {
+ struct drm_printer p = drm_info_printer(engine->i915->drm.dev);
+
+ pr_err("Failed to start spinner on %s\n", engine->name);
+ intel_engine_dump(engine, &p, "%s\n", engine->name);
+ err = -ETIME;
+ goto out_rq;
+ }
+ i915_request_suspend(rq);
+
+ intel_engine_flush_submission(engine);
+ igt_spinner_end(&spin);
+
+ if (i915_request_completed(rq)) {
+ GEM_TRACE_ERR("%s: Request completed before suspension\n",
+ engine->name);
+ GEM_TRACE_DUMP();
+ err = -EINVAL;
+ goto out_rq;
+ }
+
+ if (i915_request_is_active(rq)) {
+ GEM_TRACE_ERR("%s: Request is still active after suspension\n",
+ engine->name);
+ GEM_TRACE_DUMP();
+ err = -EINVAL;
+ goto out_rq;
+ }
+
+ i915_request_resume(rq);
+ if (i915_request_wait(rq, 0, HZ / 5) < 0) {
+ GEM_TRACE_ERR("%s: Failed to resume request\n", engine->name);
+ GEM_TRACE_DUMP();
+ err = -ETIME;
+ goto out_rq;
+ }
+
+out_rq:
+ i915_request_put(rq);
+out_ce:
+ intel_context_put(ce);
+out_spin:
+ igt_spinner_fini(&spin);
+ return err;
+}
+
+static int live_suspend_request(void *arg)
+{
+ struct drm_i915_private *i915 = arg;
+ struct intel_engine_cs *engine;
+
+ /*
+ * Check temporary suspend/resume of requests. If a suspend request
+ * is currently on the GPU, it and all of its dependents should be
+ * removed from the GPU and held until the oldest antecedent is
+ * resumed.
+ */
+
+ for_each_uabi_engine(engine, i915) {
+ struct igt_live_test t;
+ int err, err2;
+
+ if (!intel_engine_has_preemption(engine))
+ continue;
+
+ err = igt_live_test_begin(&t, i915, __func__, engine->name);
+ if (err)
+ return err;
+
+ err = __suspend_inactive(engine);
+ if (err == 0)
+ err = __suspend_active(engine);
+#if 0
+ if (err == 0)
+ err = __suspend_active_chain(engine);
+ if (err == 0)
+ err = __suspend_completed(engine);
+#endif
+
+ err2 = igt_live_test_end(&t);
+ if (err)
+ return err;
+ if (err2)
+ return err2;
+ }
+
+ return 0;
+}
+
static struct i915_vma *empty_batch(struct drm_i915_private *i915)
{
struct drm_i915_gem_object *obj;
@@ -1732,6 +1899,7 @@ int i915_request_live_selftests(struct drm_i915_private *i915)
SUBTEST(live_parallel_engines),
SUBTEST(live_empty_request),
SUBTEST(live_cancel_request),
+ SUBTEST(live_suspend_request),
SUBTEST(live_breadcrumbs_smoketest),
};
--
2.20.1
More information about the Intel-gfx-trybot
mailing list