[PATCH 47/51] drm/i915/selftests: Reimplement mock engine using a tasklet

Chris Wilson chris at chris-wilson.co.uk
Sat Feb 6 19:00:05 UTC 2021


Switch the mock_engine to using the scheduler as its basic primitive.

Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/gt/mock_engine.c         | 218 ++++++++----------
 drivers/gpu/drm/i915/gt/mock_engine.h         |  15 +-
 drivers/gpu/drm/i915/selftests/i915_request.c |  68 ------
 drivers/gpu/drm/i915/selftests/mock_request.c |  17 --
 drivers/gpu/drm/i915/selftests/mock_request.h |   2 -
 5 files changed, 98 insertions(+), 222 deletions(-)

diff --git a/drivers/gpu/drm/i915/gt/mock_engine.c b/drivers/gpu/drm/i915/gt/mock_engine.c
index 2b4219e3b3f8..6ae6ae539d35 100644
--- a/drivers/gpu/drm/i915/gt/mock_engine.c
+++ b/drivers/gpu/drm/i915/gt/mock_engine.c
@@ -3,6 +3,8 @@
  * Copyright © 2016 Intel Corporation
  */
 
+#include <linux/timer.h>
+
 #include "gem/i915_gem_context.h"
 #include "gt/intel_ring.h"
 
@@ -13,6 +15,12 @@
 #include "mock_engine.h"
 #include "selftests/mock_request.h"
 
+struct mock_sched {
+	struct i915_sched sched;
+
+	struct timer_list hw_delay;
+};
+
 static void mock_timeline_pin(struct intel_timeline *tl)
 {
 	atomic_inc(&tl->pin_count);
@@ -62,51 +70,59 @@ static void mock_ring_free(struct intel_ring *ring)
 	kfree(ring);
 }
 
-static struct i915_request *first_request(struct mock_engine *engine)
+static void dequeue(struct mock_sched *mock)
 {
-	return list_first_entry_or_null(&engine->hw_queue,
-					struct i915_request,
-					mock.link);
+	struct i915_request *rq, *rn;
+	struct i915_priolist *pl;
+
+	i915_sched_dequeue(&mock->sched, pl, rq, rn) {
+		__i915_request_submit(rq, mock->sched.priv);
+		if (rq->mock.delay && !rq->fence.error) {
+			mod_timer(&mock->hw_delay,
+				  jiffies + rq->mock.delay);
+			GEM_BUG_ON(list_empty(&mock->sched.requests));
+			return;
+		}
+		list_del_init(&rq->sched.link);
+		i915_request_mark_complete(rq);
+	}
 }
 
-static void advance(struct i915_request *request,
-		    struct mock_engine *engine)
+static void advance(struct mock_sched *mock)
 {
-	list_del_init(&request->mock.link);
-	i915_request_mark_complete(request);
-	GEM_BUG_ON(!i915_request_completed(request));
+	struct i915_request *rq;
 
-	intel_engine_signal_breadcrumbs(&engine->base);
+	if (!timer_expired(&mock->hw_delay))
+		return;
+
+	rq = list_first_entry(&mock->sched.requests, typeof(*rq), sched.link);
+	list_del_init(&rq->sched.link);
+	i915_request_mark_complete(rq);
+	intel_engine_signal_breadcrumbs(mock->sched.priv);
+
+	GEM_BUG_ON(!list_empty(&mock->sched.requests));
+}
+
+static void submission_tasklet(struct tasklet_struct *t)
+{
+	struct mock_sched *mock = from_tasklet(mock, t, sched.tasklet);
+
+	spin_lock_irq(&mock->sched.lock);
+
+	if (!list_empty(&mock->sched.requests))
+		advance(mock);
+
+	if (list_empty(&mock->sched.requests))
+		dequeue(mock);
+
+	spin_unlock_irq(&mock->sched.lock);
 }
 
 static void hw_delay_complete(struct timer_list *t)
 {
-	struct mock_engine *engine = from_timer(engine, t, hw_delay);
-	struct i915_request *request;
-	unsigned long flags;
+	struct mock_sched *mock = from_timer(mock, t, hw_delay);
 
-	spin_lock_irqsave(&engine->hw_lock, flags);
-
-	/* Timer fired, first request is complete */
-	request = first_request(engine);
-	if (request)
-		advance(request, engine);
-
-	/*
-	 * Also immediately signal any subsequent 0-delay requests, but
-	 * requeue the timer for the next delayed request.
-	 */
-	while ((request = first_request(engine))) {
-		if (request->mock.delay) {
-			mod_timer(&engine->hw_delay,
-				  jiffies + request->mock.delay);
-			break;
-		}
-
-		advance(request, engine);
-	}
-
-	spin_unlock_irqrestore(&engine->hw_lock, flags);
+	i915_sched_kick(&mock->sched);
 }
 
 static void mock_context_unpin(struct intel_context *ce)
@@ -167,9 +183,7 @@ static void mock_context_reset(struct intel_context *ce)
 static int
 mock_context_request(struct intel_context *ce, struct i915_request *rq)
 {
-	INIT_LIST_HEAD(&rq->mock.link);
 	rq->mock.delay = 0;
-
 	return 0;
 }
 
@@ -203,28 +217,6 @@ static u32 *mock_emit_breadcrumb(const struct intel_engine_cs *engine,
 	return cs;
 }
 
-static void mock_submit_request(struct i915_request *request)
-{
-	struct mock_engine *engine =
-		container_of(i915_request_get_engine(request),
-			     typeof(*engine),
-			     base);
-	unsigned long flags;
-
-	i915_request_submit(request, &engine->base);
-
-	spin_lock_irqsave(&engine->hw_lock, flags);
-	list_add_tail(&request->mock.link, &engine->hw_queue);
-	if (list_is_first(&request->mock.link, &engine->hw_queue)) {
-		if (request->mock.delay)
-			mod_timer(&engine->hw_delay,
-				  jiffies + request->mock.delay);
-		else
-			advance(request, engine);
-	}
-	spin_unlock_irqrestore(&engine->hw_lock, flags);
-}
-
 static void mock_reset_prepare(struct intel_engine_cs *engine)
 {
 }
@@ -236,30 +228,14 @@ static void mock_reset_rewind(struct intel_engine_cs *engine, bool stalled)
 
 static void mock_reset_cancel(struct intel_engine_cs *engine)
 {
-	struct mock_engine *mock =
-		container_of(engine, typeof(*mock), base);
 	struct i915_sched *se = intel_engine_get_scheduler(engine);
-	struct i915_request *rq;
 	unsigned long flags;
 
-	del_timer_sync(&mock->hw_delay);
-
 	spin_lock_irqsave(&se->lock, flags);
-
 	__i915_sched_cancel_queue(se);
-
-	/* Cancel and submit all pending requests. */
-	list_for_each_entry(rq, &mock->hw_queue, mock.link) {
-		if (i915_request_mark_eio(rq)) {
-			__i915_request_submit(rq, engine);
-			i915_request_put(rq);
-		}
-	}
-	INIT_LIST_HEAD(&mock->hw_queue);
+	spin_unlock_irqrestore(&se->lock, flags);
 
 	intel_engine_signal_breadcrumbs(engine);
-
-	spin_unlock_irqrestore(&se->lock, flags);
 }
 
 static void mock_reset_finish(struct intel_engine_cs *engine)
@@ -268,10 +244,10 @@ static void mock_reset_finish(struct intel_engine_cs *engine)
 
 static void mock_engine_release(struct intel_engine_cs *engine)
 {
-	struct mock_engine *mock =
-		container_of(engine, typeof(*mock), base);
+	struct mock_sched *mock =
+		container_of(engine->sched, typeof(*mock), sched);
 
-	GEM_BUG_ON(timer_pending(&mock->hw_delay));
+	del_timer_sync(&mock->hw_delay);
 
 	intel_breadcrumbs_free(engine->breadcrumbs);
 
@@ -285,7 +261,7 @@ struct intel_engine_cs *mock_engine(struct drm_i915_private *i915,
 				    const char *name,
 				    int id)
 {
-	struct mock_engine *engine;
+	struct intel_engine_cs *engine;
 
 	GEM_BUG_ON(id >= I915_NUM_ENGINES);
 	GEM_BUG_ON(!i915->gt.uncore);
@@ -295,54 +271,55 @@ struct intel_engine_cs *mock_engine(struct drm_i915_private *i915,
 		return NULL;
 
 	/* minimal engine setup for requests */
-	engine->base.i915 = i915;
-	engine->base.gt = &i915->gt;
-	engine->base.uncore = i915->gt.uncore;
-	snprintf(engine->base.name, sizeof(engine->base.name), "%s", name);
-	engine->base.id = id;
-	engine->base.mask = BIT(id);
-	engine->base.legacy_idx = INVALID_ENGINE;
-	engine->base.instance = id;
-	engine->base.status_page.addr = (void *)(engine + 1);
+	engine->i915 = i915;
+	engine->gt = &i915->gt;
+	engine->uncore = i915->gt.uncore;
+	snprintf(engine->name, sizeof(engine->name), "%s", name);
+	engine->id = id;
+	engine->mask = BIT(id);
+	engine->legacy_idx = INVALID_ENGINE;
+	engine->instance = id;
+	engine->status_page.addr = (void *)(engine + 1);
 
-	engine->base.cops = &mock_context_ops;
-	engine->base.emit_flush = mock_emit_flush;
-	engine->base.emit_fini_breadcrumb = mock_emit_breadcrumb;
+	engine->cops = &mock_context_ops;
+	engine->emit_flush = mock_emit_flush;
+	engine->emit_fini_breadcrumb = mock_emit_breadcrumb;
 
-	engine->base.reset.prepare = mock_reset_prepare;
-	engine->base.reset.rewind = mock_reset_rewind;
-	engine->base.reset.cancel = mock_reset_cancel;
-	engine->base.reset.finish = mock_reset_finish;
+	engine->reset.prepare = mock_reset_prepare;
+	engine->reset.rewind = mock_reset_rewind;
+	engine->reset.cancel = mock_reset_cancel;
+	engine->reset.finish = mock_reset_finish;
 
-	engine->base.release = mock_engine_release;
+	engine->release = mock_engine_release;
 
-	i915->gt.engine[id] = &engine->base;
-	i915->gt.engine_class[0][id] = &engine->base;
+	i915->gt.engine[id] = engine;
+	i915->gt.engine_class[0][id] = engine;
 
-	/* fake hw queue */
-	spin_lock_init(&engine->hw_lock);
-	timer_setup(&engine->hw_delay, hw_delay_complete, 0);
-	INIT_LIST_HEAD(&engine->hw_queue);
+	intel_engine_add_user(engine);
 
-	intel_engine_add_user(&engine->base);
-
-	return &engine->base;
+	return engine;
 }
 
 int mock_engine_init(struct intel_engine_cs *engine)
 {
 	struct intel_context *ce;
+	struct mock_sched *se;
 
-	engine->sched =
-		i915_sched_create(engine->i915->drm.dev,
-				  engine->name,
-				  engine->mask,
-				  NULL, engine,
-				  ENGINE_MOCK);
-	if (!engine->sched)
+	se = kzalloc(sizeof(*se), GFP_KERNEL);
+	if (!se)
 		return -ENOMEM;
 
-	engine->sched->submit_request = mock_submit_request;
+	timer_setup(&se->hw_delay, hw_delay_complete, 0);
+
+	i915_sched_init(&se->sched,
+			engine->i915->drm.dev,
+			engine->name,
+			engine->mask,
+			submission_tasklet, engine,
+			ENGINE_MOCK);
+
+	i915_sched_enable(&se->sched);
+	engine->sched = &se->sched;
 
 	intel_engine_init__pm(engine);
 	intel_engine_init_retire(engine);
@@ -370,16 +347,13 @@ int mock_engine_init(struct intel_engine_cs *engine)
 
 void mock_engine_flush(struct intel_engine_cs *engine)
 {
-	struct mock_engine *mock =
-		container_of(engine, typeof(*mock), base);
-	struct i915_request *request, *rn;
+	struct mock_sched *mock =
+		container_of(engine->sched, typeof(*mock), sched);
+
+	mock_reset_cancel(engine);
 
 	del_timer_sync(&mock->hw_delay);
-
-	spin_lock_irq(&mock->hw_lock);
-	list_for_each_entry_safe(request, rn, &mock->hw_queue, mock.link)
-		advance(request, mock);
-	spin_unlock_irq(&mock->hw_lock);
+	i915_sched_flush(&mock->sched);
 }
 
 void mock_engine_reset(struct intel_engine_cs *engine)
diff --git a/drivers/gpu/drm/i915/gt/mock_engine.h b/drivers/gpu/drm/i915/gt/mock_engine.h
index cc5ab6e1f37e..fdcb9eab3f4f 100644
--- a/drivers/gpu/drm/i915/gt/mock_engine.h
+++ b/drivers/gpu/drm/i915/gt/mock_engine.h
@@ -6,19 +6,8 @@
 #ifndef __MOCK_ENGINE_H__
 #define __MOCK_ENGINE_H__
 
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/timer.h>
-
-#include "gt/intel_engine.h"
-
-struct mock_engine {
-	struct intel_engine_cs base;
-
-	spinlock_t hw_lock;
-	struct list_head hw_queue;
-	struct timer_list hw_delay;
-};
+struct drm_i915_private;
+struct intel_engine_cs;
 
 struct intel_engine_cs *mock_engine(struct drm_i915_private *i915,
 				    const char *name,
diff --git a/drivers/gpu/drm/i915/selftests/i915_request.c b/drivers/gpu/drm/i915/selftests/i915_request.c
index 5d747c2d937b..8c9d60359324 100644
--- a/drivers/gpu/drm/i915/selftests/i915_request.c
+++ b/drivers/gpu/drm/i915/selftests/i915_request.c
@@ -200,73 +200,6 @@ static int igt_fence_wait(void *arg)
 	return err;
 }
 
-static int igt_request_rewind(void *arg)
-{
-	struct drm_i915_private *i915 = arg;
-	struct i915_request *request, *vip;
-	struct i915_gem_context *ctx[2];
-	struct intel_context *ce;
-	int err = -EINVAL;
-
-	ctx[0] = mock_context(i915, "A");
-
-	ce = i915_gem_context_get_engine(ctx[0], RCS0);
-	GEM_BUG_ON(IS_ERR(ce));
-	request = mock_request(ce, 2 * HZ);
-	intel_context_put(ce);
-	if (!request) {
-		err = -ENOMEM;
-		goto err_context_0;
-	}
-
-	i915_request_get(request);
-	i915_request_add(request);
-
-	ctx[1] = mock_context(i915, "B");
-
-	ce = i915_gem_context_get_engine(ctx[1], RCS0);
-	GEM_BUG_ON(IS_ERR(ce));
-	vip = mock_request(ce, 0);
-	intel_context_put(ce);
-	if (!vip) {
-		err = -ENOMEM;
-		goto err_context_1;
-	}
-
-	/* Simulate preemption by manual reordering */
-	if (!mock_cancel_request(request)) {
-		pr_err("failed to cancel request (already executed)!\n");
-		i915_request_add(vip);
-		goto err_context_1;
-	}
-	i915_request_get(vip);
-	i915_request_add(vip);
-	rcu_read_lock();
-	i915_request_get_scheduler(request)->submit_request(request);
-	rcu_read_unlock();
-
-	if (i915_request_wait(vip, 0, HZ) == -ETIME) {
-		pr_err("timed out waiting for high priority request\n");
-		goto err;
-	}
-
-	if (i915_request_completed(request)) {
-		pr_err("low priority request already completed\n");
-		goto err;
-	}
-
-	err = 0;
-err:
-	i915_request_put(vip);
-err_context_1:
-	mock_context_close(ctx[1]);
-	i915_request_put(request);
-err_context_0:
-	mock_context_close(ctx[0]);
-	mock_device_flush(i915);
-	return err;
-}
-
 struct smoketest {
 	struct intel_engine_cs *engine;
 	struct i915_gem_context **contexts;
@@ -513,7 +446,6 @@ int i915_request_mock_selftests(void)
 		SUBTEST(igt_add_request),
 		SUBTEST(igt_wait_request),
 		SUBTEST(igt_fence_wait),
-		SUBTEST(igt_request_rewind),
 		SUBTEST(mock_breadcrumbs_smoketest),
 	};
 	struct drm_i915_private *i915;
diff --git a/drivers/gpu/drm/i915/selftests/mock_request.c b/drivers/gpu/drm/i915/selftests/mock_request.c
index 49f3bddfcb95..8aa28e8d1c89 100644
--- a/drivers/gpu/drm/i915/selftests/mock_request.c
+++ b/drivers/gpu/drm/i915/selftests/mock_request.c
@@ -40,20 +40,3 @@ mock_request(struct intel_context *ce, unsigned long delay)
 	request->mock.delay = delay;
 	return request;
 }
-
-bool mock_cancel_request(struct i915_request *request)
-{
-	struct mock_engine *engine =
-		container_of(i915_request_get_engine(request), typeof(*engine), base);
-	bool was_queued;
-
-	spin_lock_irq(&engine->hw_lock);
-	was_queued = !list_empty(&request->mock.link);
-	list_del_init(&request->mock.link);
-	spin_unlock_irq(&engine->hw_lock);
-
-	if (was_queued)
-		i915_request_unsubmit(request);
-
-	return was_queued;
-}
diff --git a/drivers/gpu/drm/i915/selftests/mock_request.h b/drivers/gpu/drm/i915/selftests/mock_request.h
index 8907b60c290d..3d4bac9bcfe2 100644
--- a/drivers/gpu/drm/i915/selftests/mock_request.h
+++ b/drivers/gpu/drm/i915/selftests/mock_request.h
@@ -32,6 +32,4 @@
 struct i915_request *
 mock_request(struct intel_context *ce, unsigned long delay);
 
-bool mock_cancel_request(struct i915_request *request);
-
 #endif /* !__MOCK_REQUEST__ */
-- 
2.20.1



More information about the Intel-gfx-trybot mailing list