All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/6] drm/i915: Stop tracking timeline->inflight_seqnos
@ 2018-04-23 10:13 Chris Wilson
  2018-04-23 10:13 ` [PATCH 2/6] drm/i915: Retire requests along rings Chris Wilson
                   ` (7 more replies)
  0 siblings, 8 replies; 20+ messages in thread
From: Chris Wilson @ 2018-04-23 10:13 UTC (permalink / raw)
  To: intel-gfx

In commit 9b6586ae9f6b ("drm/i915: Keep a global seqno per-engine"), we
moved from a global inflight counter to per-engine counters in the
hope that will be easy to run concurrently in future. However, with the
advent of the desire to move requests between engines, we do need a
global counter to preserve the semantics that no engine wraps in the
middle of a submit. (Although this semantic is now only required for gen7
semaphore support, which only supports greater-then comparisons!)

References: 9b6586ae9f6b ("drm/i915: Keep a global seqno per-engine")
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>
---
 drivers/gpu/drm/i915/i915_debugfs.c      |  5 ++---
 drivers/gpu/drm/i915/i915_gem_timeline.h |  6 ------
 drivers/gpu/drm/i915/i915_request.c      | 12 +++---------
 drivers/gpu/drm/i915/intel_engine_cs.c   |  5 ++---
 4 files changed, 7 insertions(+), 21 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 2f05f5262bba..547e97102b85 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -1340,10 +1340,9 @@ static int i915_hangcheck_info(struct seq_file *m, void *unused)
 		struct rb_node *rb;
 
 		seq_printf(m, "%s:\n", engine->name);
-		seq_printf(m, "\tseqno = %x [current %x, last %x], inflight %d\n",
+		seq_printf(m, "\tseqno = %x [current %x, last %x]\n",
 			   engine->hangcheck.seqno, seqno[id],
-			   intel_engine_last_submit(engine),
-			   engine->timeline->inflight_seqnos);
+			   intel_engine_last_submit(engine));
 		seq_printf(m, "\twaiters? %s, fake irq active? %s, stalled? %s\n",
 			   yesno(intel_engine_has_waiter(engine)),
 			   yesno(test_bit(engine->id,
diff --git a/drivers/gpu/drm/i915/i915_gem_timeline.h b/drivers/gpu/drm/i915/i915_gem_timeline.h
index 33e01bf6aa36..6e82119e2cd8 100644
--- a/drivers/gpu/drm/i915/i915_gem_timeline.h
+++ b/drivers/gpu/drm/i915/i915_gem_timeline.h
@@ -37,12 +37,6 @@ struct intel_timeline {
 	u64 fence_context;
 	u32 seqno;
 
-	/**
-	 * Count of outstanding requests, from the time they are constructed
-	 * to the moment they are retired. Loosely coupled to hardware.
-	 */
-	u32 inflight_seqnos;
-
 	spinlock_t lock;
 
 	/**
diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c
index b692a9f7c357..1437538d5bfa 100644
--- a/drivers/gpu/drm/i915/i915_request.c
+++ b/drivers/gpu/drm/i915/i915_request.c
@@ -260,17 +260,14 @@ int i915_gem_set_global_seqno(struct drm_device *dev, u32 seqno)
 static int reserve_engine(struct intel_engine_cs *engine)
 {
 	struct drm_i915_private *i915 = engine->i915;
-	u32 active = ++engine->timeline->inflight_seqnos;
-	u32 seqno = engine->timeline->seqno;
 	int ret;
 
 	/* Reservation is fine until we need to wrap around */
-	if (unlikely(add_overflows(seqno, active))) {
+	if (unlikely(add_overflows(engine->timeline->seqno,
+				   i915->gt.active_requests + 1))) {
 		ret = reset_all_global_seqno(i915, 0);
-		if (ret) {
-			engine->timeline->inflight_seqnos--;
+		if (ret)
 			return ret;
-		}
 	}
 
 	if (!i915->gt.active_requests++)
@@ -285,9 +282,6 @@ static void unreserve_engine(struct intel_engine_cs *engine)
 
 	if (!--i915->gt.active_requests)
 		i915_gem_park(i915);
-
-	GEM_BUG_ON(!engine->timeline->inflight_seqnos);
-	engine->timeline->inflight_seqnos--;
 }
 
 void i915_gem_retire_noop(struct i915_gem_active *active,
diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c
index be608f7111f5..a55a849b81b6 100644
--- a/drivers/gpu/drm/i915/intel_engine_cs.c
+++ b/drivers/gpu/drm/i915/intel_engine_cs.c
@@ -1318,12 +1318,11 @@ void intel_engine_dump(struct intel_engine_cs *engine,
 	if (i915_terminally_wedged(&engine->i915->gpu_error))
 		drm_printf(m, "*** WEDGED ***\n");
 
-	drm_printf(m, "\tcurrent seqno %x, last %x, hangcheck %x [%d ms], inflight %d\n",
+	drm_printf(m, "\tcurrent seqno %x, last %x, hangcheck %x [%d ms]\n",
 		   intel_engine_get_seqno(engine),
 		   intel_engine_last_submit(engine),
 		   engine->hangcheck.seqno,
-		   jiffies_to_msecs(jiffies - engine->hangcheck.action_timestamp),
-		   engine->timeline->inflight_seqnos);
+		   jiffies_to_msecs(jiffies - engine->hangcheck.action_timestamp));
 	drm_printf(m, "\tReset count: %d (global %d)\n",
 		   i915_reset_engine_count(error, engine),
 		   i915_reset_count(error));
-- 
2.17.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 2/6] drm/i915: Retire requests along rings
  2018-04-23 10:13 [PATCH 1/6] drm/i915: Stop tracking timeline->inflight_seqnos Chris Wilson
@ 2018-04-23 10:13 ` Chris Wilson
  2018-04-23 10:18   ` Tvrtko Ursulin
  2018-04-23 10:13 ` [PATCH 3/6] drm/i915: Only track live rings for retiring Chris Wilson
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 20+ messages in thread
From: Chris Wilson @ 2018-04-23 10:13 UTC (permalink / raw)
  To: intel-gfx

In the next patch, rings are the central timeline as requests may jump
between engines. Therefore in the future as we retire in order along the
engine timeline, we may retire out-of-order within a ring (as the ring now
occurs along multiple engines), leading to much hilarity in miscomputing
the position of ring->head.

As an added bonus, retiring along the ring reduces the penalty of having
one execlists client do cleanup for another (old legacy submission
shares a ring between all clients). The downside is that slow and
irregular (off the critical path) process of cleaning up stale requests
after userspace becomes a modicum less efficient.

In the long run, it will become apparent that the ordered
ring->request_list matches the ring->timeline, a fun challenge for the
future will be unifying the two lists to avoid duplication!

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h               |  3 +-
 drivers/gpu/drm/i915/i915_gem.c               |  1 +
 drivers/gpu/drm/i915/i915_request.c           | 43 ++++++++-----------
 drivers/gpu/drm/i915/intel_ringbuffer.c       |  5 +++
 drivers/gpu/drm/i915/intel_ringbuffer.h       |  1 +
 drivers/gpu/drm/i915/selftests/mock_engine.c  | 27 +++++++++---
 .../gpu/drm/i915/selftests/mock_gem_device.c  |  2 +
 7 files changed, 50 insertions(+), 32 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 8444ca8d5aa3..73936be90aed 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2058,8 +2058,9 @@ struct drm_i915_private {
 		void (*resume)(struct drm_i915_private *);
 		void (*cleanup_engine)(struct intel_engine_cs *engine);
 
-		struct list_head timelines;
 		struct i915_gem_timeline global_timeline;
+		struct list_head timelines;
+		struct list_head rings;
 		u32 active_requests;
 
 		/**
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 795ca83aed7a..906e2395c245 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -5600,6 +5600,7 @@ int i915_gem_init_early(struct drm_i915_private *dev_priv)
 		goto err_dependencies;
 
 	mutex_lock(&dev_priv->drm.struct_mutex);
+	INIT_LIST_HEAD(&dev_priv->gt.rings);
 	INIT_LIST_HEAD(&dev_priv->gt.timelines);
 	err = i915_gem_timeline_init__global(dev_priv);
 	mutex_unlock(&dev_priv->drm.struct_mutex);
diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c
index 1437538d5bfa..0bf949ec9f1a 100644
--- a/drivers/gpu/drm/i915/i915_request.c
+++ b/drivers/gpu/drm/i915/i915_request.c
@@ -292,6 +292,7 @@ void i915_gem_retire_noop(struct i915_gem_active *active,
 
 static void advance_ring(struct i915_request *request)
 {
+	struct intel_ring *ring = request->ring;
 	unsigned int tail;
 
 	/*
@@ -303,7 +304,9 @@ static void advance_ring(struct i915_request *request)
 	 * Note this requires that we are always called in request
 	 * completion order.
 	 */
-	if (list_is_last(&request->ring_link, &request->ring->request_list)) {
+	GEM_BUG_ON(request != list_first_entry(&ring->request_list,
+					       typeof(*request), ring_link));
+	if (list_is_last(&request->ring_link, &ring->request_list)) {
 		/*
 		 * We may race here with execlists resubmitting this request
 		 * as we retire it. The resubmission will move the ring->tail
@@ -318,7 +321,7 @@ static void advance_ring(struct i915_request *request)
 	}
 	list_del(&request->ring_link);
 
-	request->ring->head = tail;
+	ring->head = tail;
 }
 
 static void free_capture_list(struct i915_request *request)
@@ -424,18 +427,18 @@ static void i915_request_retire(struct i915_request *request)
 
 void i915_request_retire_upto(struct i915_request *rq)
 {
-	struct intel_engine_cs *engine = rq->engine;
+	struct intel_ring *ring = rq->ring;
 	struct i915_request *tmp;
 
 	lockdep_assert_held(&rq->i915->drm.struct_mutex);
 	GEM_BUG_ON(!i915_request_completed(rq));
 
-	if (list_empty(&rq->link))
+	if (list_empty(&rq->ring_link))
 		return;
 
 	do {
-		tmp = list_first_entry(&engine->timeline->requests,
-				       typeof(*tmp), link);
+		tmp = list_first_entry(&ring->request_list,
+				       typeof(*tmp), ring_link);
 
 		i915_request_retire(tmp);
 	} while (tmp != rq);
@@ -644,9 +647,9 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx)
 	if (ret)
 		goto err_unreserve;
 
-	/* Move the oldest request to the slab-cache (if not in use!) */
-	rq = list_first_entry_or_null(&engine->timeline->requests,
-				      typeof(*rq), link);
+	/* Move our oldest request to the slab-cache (if not in use!) */
+	rq = list_first_entry_or_null(&ring->request_list,
+				      typeof(*rq), ring_link);
 	if (rq && i915_request_completed(rq))
 		i915_request_retire(rq);
 
@@ -1350,38 +1353,30 @@ long i915_request_wait(struct i915_request *rq,
 	return timeout;
 }
 
-static void engine_retire_requests(struct intel_engine_cs *engine)
+static void ring_retire_requests(struct intel_ring *ring)
 {
 	struct i915_request *request, *next;
-	u32 seqno = intel_engine_get_seqno(engine);
-	LIST_HEAD(retire);
 
-	spin_lock_irq(&engine->timeline->lock);
 	list_for_each_entry_safe(request, next,
-				 &engine->timeline->requests, link) {
-		if (!i915_seqno_passed(seqno, request->global_seqno))
+				 &ring->request_list, ring_link) {
+		if (!i915_request_completed(request))
 			break;
 
-		list_move_tail(&request->link, &retire);
-	}
-	spin_unlock_irq(&engine->timeline->lock);
-
-	list_for_each_entry_safe(request, next, &retire, link)
 		i915_request_retire(request);
+	}
 }
 
 void i915_retire_requests(struct drm_i915_private *i915)
 {
-	struct intel_engine_cs *engine;
-	enum intel_engine_id id;
+	struct intel_ring *ring, *next;
 
 	lockdep_assert_held(&i915->drm.struct_mutex);
 
 	if (!i915->gt.active_requests)
 		return;
 
-	for_each_engine(engine, i915, id)
-		engine_retire_requests(engine);
+	list_for_each_entry_safe(ring, next, &i915->gt.rings, link)
+		ring_retire_requests(ring);
 }
 
 #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index c68ac605b8a9..792a2ca95872 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -1124,6 +1124,7 @@ intel_engine_create_ring(struct intel_engine_cs *engine, int size)
 
 	GEM_BUG_ON(!is_power_of_2(size));
 	GEM_BUG_ON(RING_CTL_SIZE(size) & ~RING_NR_PAGES);
+	lockdep_assert_held(&engine->i915->drm.struct_mutex);
 
 	ring = kzalloc(sizeof(*ring), GFP_KERNEL);
 	if (!ring)
@@ -1149,6 +1150,8 @@ intel_engine_create_ring(struct intel_engine_cs *engine, int size)
 	}
 	ring->vma = vma;
 
+	list_add(&ring->link, &engine->i915->gt.rings);
+
 	return ring;
 }
 
@@ -1160,6 +1163,8 @@ intel_ring_free(struct intel_ring *ring)
 	i915_vma_close(ring->vma);
 	__i915_gem_object_release_unless_active(obj);
 
+	list_del(&ring->link);
+
 	kfree(ring);
 }
 
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index c5e27905b0e1..d816f8dea245 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -129,6 +129,7 @@ struct intel_ring {
 	void *vaddr;
 
 	struct list_head request_list;
+	struct list_head link;
 
 	u32 head;
 	u32 tail;
diff --git a/drivers/gpu/drm/i915/selftests/mock_engine.c b/drivers/gpu/drm/i915/selftests/mock_engine.c
index 78a89efa1119..a0bc324edadd 100644
--- a/drivers/gpu/drm/i915/selftests/mock_engine.c
+++ b/drivers/gpu/drm/i915/selftests/mock_engine.c
@@ -140,9 +140,18 @@ static struct intel_ring *mock_ring(struct intel_engine_cs *engine)
 	INIT_LIST_HEAD(&ring->request_list);
 	intel_ring_update_space(ring);
 
+	list_add(&ring->link, &engine->i915->gt.rings);
+
 	return ring;
 }
 
+static void mock_ring_free(struct intel_ring *ring)
+{
+	list_del(&ring->link);
+
+	kfree(ring);
+}
+
 struct intel_engine_cs *mock_engine(struct drm_i915_private *i915,
 				    const char *name,
 				    int id)
@@ -155,12 +164,6 @@ struct intel_engine_cs *mock_engine(struct drm_i915_private *i915,
 	if (!engine)
 		return NULL;
 
-	engine->base.buffer = mock_ring(&engine->base);
-	if (!engine->base.buffer) {
-		kfree(engine);
-		return NULL;
-	}
-
 	/* minimal engine setup for requests */
 	engine->base.i915 = i915;
 	snprintf(engine->base.name, sizeof(engine->base.name), "%s", name);
@@ -185,7 +188,16 @@ struct intel_engine_cs *mock_engine(struct drm_i915_private *i915,
 	timer_setup(&engine->hw_delay, hw_delay_complete, 0);
 	INIT_LIST_HEAD(&engine->hw_queue);
 
+	engine->base.buffer = mock_ring(&engine->base);
+	if (!engine->base.buffer)
+		goto err_breadcrumbs;
+
 	return &engine->base;
+
+err_breadcrumbs:
+	intel_engine_fini_breadcrumbs(&engine->base);
+	kfree(engine);
+	return NULL;
 }
 
 void mock_engine_flush(struct intel_engine_cs *engine)
@@ -219,8 +231,9 @@ void mock_engine_free(struct intel_engine_cs *engine)
 	if (engine->last_retired_context)
 		engine->context_unpin(engine, engine->last_retired_context);
 
+	mock_ring_free(engine->buffer);
+
 	intel_engine_fini_breadcrumbs(engine);
 
-	kfree(engine->buffer);
 	kfree(engine);
 }
diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_device.c b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
index e6d4b882599a..ac4bacf8b5b9 100644
--- a/drivers/gpu/drm/i915/selftests/mock_gem_device.c
+++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
@@ -44,6 +44,7 @@ void mock_device_flush(struct drm_i915_private *i915)
 		mock_engine_flush(engine);
 
 	i915_retire_requests(i915);
+	GEM_BUG_ON(i915->gt.active_requests);
 }
 
 static void mock_device_release(struct drm_device *dev)
@@ -224,6 +225,7 @@ struct drm_i915_private *mock_gem_device(void)
 		goto err_dependencies;
 
 	mutex_lock(&i915->drm.struct_mutex);
+	INIT_LIST_HEAD(&i915->gt.rings);
 	INIT_LIST_HEAD(&i915->gt.timelines);
 	err = i915_gem_timeline_init__global(i915);
 	if (err) {
-- 
2.17.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 3/6] drm/i915: Only track live rings for retiring
  2018-04-23 10:13 [PATCH 1/6] drm/i915: Stop tracking timeline->inflight_seqnos Chris Wilson
  2018-04-23 10:13 ` [PATCH 2/6] drm/i915: Retire requests along rings Chris Wilson
@ 2018-04-23 10:13 ` Chris Wilson
  2018-04-23 10:25   ` Tvrtko Ursulin
  2018-04-23 10:13 ` [PATCH 4/6] drm/i915: Move timeline from GTT to ring Chris Wilson
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 20+ messages in thread
From: Chris Wilson @ 2018-04-23 10:13 UTC (permalink / raw)
  To: intel-gfx

We don't need to track every ring for its lifetime as they are managed
by the contexts/engines. What we do want to track are the live rings so
that we can sporadically clean up requests if userspace falls behind. We
can simply restrict the gt->rings list to being only gt->live_rings.

Suggested-by: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h                  | 2 +-
 drivers/gpu/drm/i915/i915_gem.c                  | 3 ++-
 drivers/gpu/drm/i915/i915_request.c              | 6 +++++-
 drivers/gpu/drm/i915/i915_utils.h                | 6 ++++++
 drivers/gpu/drm/i915/intel_ringbuffer.c          | 4 ----
 drivers/gpu/drm/i915/intel_ringbuffer.h          | 2 +-
 drivers/gpu/drm/i915/selftests/mock_engine.c     | 4 ----
 drivers/gpu/drm/i915/selftests/mock_gem_device.c | 2 +-
 8 files changed, 16 insertions(+), 13 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 73936be90aed..a7787c2cb53c 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2060,7 +2060,7 @@ struct drm_i915_private {
 
 		struct i915_gem_timeline global_timeline;
 		struct list_head timelines;
-		struct list_head rings;
+		struct list_head live_rings;
 		u32 active_requests;
 
 		/**
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 906e2395c245..0097a77fae8d 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -141,6 +141,7 @@ static u32 __i915_gem_park(struct drm_i915_private *i915)
 {
 	lockdep_assert_held(&i915->drm.struct_mutex);
 	GEM_BUG_ON(i915->gt.active_requests);
+	GEM_BUG_ON(!list_empty(&i915->gt.live_rings));
 
 	if (!i915->gt.awake)
 		return I915_EPOCH_INVALID;
@@ -5600,7 +5601,7 @@ int i915_gem_init_early(struct drm_i915_private *dev_priv)
 		goto err_dependencies;
 
 	mutex_lock(&dev_priv->drm.struct_mutex);
-	INIT_LIST_HEAD(&dev_priv->gt.rings);
+	INIT_LIST_HEAD(&dev_priv->gt.live_rings);
 	INIT_LIST_HEAD(&dev_priv->gt.timelines);
 	err = i915_gem_timeline_init__global(dev_priv);
 	mutex_unlock(&dev_priv->drm.struct_mutex);
diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c
index 0bf949ec9f1a..534b8d684cef 100644
--- a/drivers/gpu/drm/i915/i915_request.c
+++ b/drivers/gpu/drm/i915/i915_request.c
@@ -316,6 +316,7 @@ static void advance_ring(struct i915_request *request)
 		 * noops - they are safe to be replayed on a reset.
 		 */
 		tail = READ_ONCE(request->tail);
+		list_del(&ring->live);
 	} else {
 		tail = request->postfix;
 	}
@@ -1046,6 +1047,8 @@ void __i915_request_add(struct i915_request *request, bool flush_caches)
 	i915_gem_active_set(&timeline->last_request, request);
 
 	list_add_tail(&request->ring_link, &ring->request_list);
+	if (list_is_first(&request->ring_link, &ring->request_list))
+		list_add(&ring->live, &request->i915->gt.live_rings);
 	request->emitted_jiffies = jiffies;
 
 	/*
@@ -1375,7 +1378,8 @@ void i915_retire_requests(struct drm_i915_private *i915)
 	if (!i915->gt.active_requests)
 		return;
 
-	list_for_each_entry_safe(ring, next, &i915->gt.rings, link)
+	GEM_BUG_ON(list_empty(&i915->gt.live_rings));
+	list_for_each_entry_safe(ring, next, &i915->gt.live_rings, live)
 		ring_retire_requests(ring);
 }
 
diff --git a/drivers/gpu/drm/i915/i915_utils.h b/drivers/gpu/drm/i915/i915_utils.h
index 0695717522ea..00165ad55fb3 100644
--- a/drivers/gpu/drm/i915/i915_utils.h
+++ b/drivers/gpu/drm/i915/i915_utils.h
@@ -120,6 +120,12 @@ static inline u64 ptr_to_u64(const void *ptr)
 
 #include <linux/list.h>
 
+static inline int list_is_first(const struct list_head *list,
+				const struct list_head *head)
+{
+	return head->next == list;
+}
+
 static inline void __list_del_many(struct list_head *head,
 				   struct list_head *first)
 {
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index 792a2ca95872..3453e7426f6b 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -1150,8 +1150,6 @@ intel_engine_create_ring(struct intel_engine_cs *engine, int size)
 	}
 	ring->vma = vma;
 
-	list_add(&ring->link, &engine->i915->gt.rings);
-
 	return ring;
 }
 
@@ -1163,8 +1161,6 @@ intel_ring_free(struct intel_ring *ring)
 	i915_vma_close(ring->vma);
 	__i915_gem_object_release_unless_active(obj);
 
-	list_del(&ring->link);
-
 	kfree(ring);
 }
 
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index d816f8dea245..fd5a6363ab1d 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -129,7 +129,7 @@ struct intel_ring {
 	void *vaddr;
 
 	struct list_head request_list;
-	struct list_head link;
+	struct list_head live;
 
 	u32 head;
 	u32 tail;
diff --git a/drivers/gpu/drm/i915/selftests/mock_engine.c b/drivers/gpu/drm/i915/selftests/mock_engine.c
index a0bc324edadd..74a88913623f 100644
--- a/drivers/gpu/drm/i915/selftests/mock_engine.c
+++ b/drivers/gpu/drm/i915/selftests/mock_engine.c
@@ -140,15 +140,11 @@ static struct intel_ring *mock_ring(struct intel_engine_cs *engine)
 	INIT_LIST_HEAD(&ring->request_list);
 	intel_ring_update_space(ring);
 
-	list_add(&ring->link, &engine->i915->gt.rings);
-
 	return ring;
 }
 
 static void mock_ring_free(struct intel_ring *ring)
 {
-	list_del(&ring->link);
-
 	kfree(ring);
 }
 
diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_device.c b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
index ac4bacf8b5b9..9335b09d8b04 100644
--- a/drivers/gpu/drm/i915/selftests/mock_gem_device.c
+++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
@@ -225,7 +225,7 @@ struct drm_i915_private *mock_gem_device(void)
 		goto err_dependencies;
 
 	mutex_lock(&i915->drm.struct_mutex);
-	INIT_LIST_HEAD(&i915->gt.rings);
+	INIT_LIST_HEAD(&i915->gt.live_rings);
 	INIT_LIST_HEAD(&i915->gt.timelines);
 	err = i915_gem_timeline_init__global(i915);
 	if (err) {
-- 
2.17.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 4/6] drm/i915: Move timeline from GTT to ring
  2018-04-23 10:13 [PATCH 1/6] drm/i915: Stop tracking timeline->inflight_seqnos Chris Wilson
  2018-04-23 10:13 ` [PATCH 2/6] drm/i915: Retire requests along rings Chris Wilson
  2018-04-23 10:13 ` [PATCH 3/6] drm/i915: Only track live rings for retiring Chris Wilson
@ 2018-04-23 10:13 ` Chris Wilson
  2018-04-23 10:44   ` Tvrtko Ursulin
  2018-04-23 10:13 ` [PATCH 5/6] drm/i915: Split i915_gem_timeline into individual timelines Chris Wilson
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 20+ messages in thread
From: Chris Wilson @ 2018-04-23 10:13 UTC (permalink / raw)
  To: intel-gfx

In the future, we want to move a request between engines. To achieve
this, we first realise that we have two timelines in effect here. The
first runs through the GTT is required for ordering vma access, which is
tracked currently by engine. The second is implied by sequential
execution of commands inside the ringbuffer. This timeline is one that
maps to userspace's expectations when submitting requests (i.e. given the
same context, batch A is executed before batch B). As the rings's
timelines map to userspace and the GTT timeline an implementation
detail, move the timeline from the GTT into the ring itself (per-context
in logical-ring-contexts/execlists, or a global per-engine timeline for
the shared ringbuffers in legacy submission.

The two timelines are still assumed to be equivalent at the moment (no
migrating requests between engines yet) and so we can simply move from
one to the other without adding extra ordering.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h               | 13 +----
 drivers/gpu/drm/i915/i915_gem.c               |  9 ++--
 drivers/gpu/drm/i915/i915_gem_context.c       | 15 +++++-
 drivers/gpu/drm/i915/i915_gem_context.h       |  2 +
 drivers/gpu/drm/i915/i915_gem_gtt.c           |  3 --
 drivers/gpu/drm/i915/i915_gem_gtt.h           |  1 -
 drivers/gpu/drm/i915/i915_gem_timeline.c      | 54 +++++++++++++++++--
 drivers/gpu/drm/i915/i915_gem_timeline.h      |  4 ++
 drivers/gpu/drm/i915/i915_request.c           | 15 +++---
 drivers/gpu/drm/i915/intel_engine_cs.c        |  3 +-
 drivers/gpu/drm/i915/intel_lrc.c              |  2 +-
 drivers/gpu/drm/i915/intel_ringbuffer.c       |  9 +++-
 drivers/gpu/drm/i915/intel_ringbuffer.h       |  5 +-
 drivers/gpu/drm/i915/selftests/mock_engine.c  |  3 +-
 .../gpu/drm/i915/selftests/mock_gem_device.c  |  4 +-
 drivers/gpu/drm/i915/selftests/mock_gtt.c     |  1 -
 16 files changed, 101 insertions(+), 42 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index a7787c2cb53c..66123cf0eda3 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2058,7 +2058,8 @@ struct drm_i915_private {
 		void (*resume)(struct drm_i915_private *);
 		void (*cleanup_engine)(struct intel_engine_cs *engine);
 
-		struct i915_gem_timeline global_timeline;
+		struct i915_gem_timeline execution_timeline;
+		struct i915_gem_timeline legacy_timeline;
 		struct list_head timelines;
 		struct list_head live_rings;
 		u32 active_requests;
@@ -3232,16 +3233,6 @@ i915_gem_context_lookup(struct drm_i915_file_private *file_priv, u32 id)
 	return ctx;
 }
 
-static inline struct intel_timeline *
-i915_gem_context_lookup_timeline(struct i915_gem_context *ctx,
-				 struct intel_engine_cs *engine)
-{
-	struct i915_address_space *vm;
-
-	vm = ctx->ppgtt ? &ctx->ppgtt->base : &ctx->i915->ggtt.base;
-	return &vm->timeline.engine[engine->id];
-}
-
 int i915_perf_open_ioctl(struct drm_device *dev, void *data,
 			 struct drm_file *file);
 int i915_perf_add_config_ioctl(struct drm_device *dev, void *data,
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 0097a77fae8d..1635975dbc16 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -3110,10 +3110,10 @@ static void engine_skip_context(struct i915_request *request)
 {
 	struct intel_engine_cs *engine = request->engine;
 	struct i915_gem_context *hung_ctx = request->ctx;
-	struct intel_timeline *timeline;
+	struct intel_timeline *timeline = request->timeline;
 	unsigned long flags;
 
-	timeline = i915_gem_context_lookup_timeline(hung_ctx, engine);
+	GEM_BUG_ON(timeline == engine->timeline);
 
 	spin_lock_irqsave(&engine->timeline->lock, flags);
 	spin_lock(&timeline->lock);
@@ -3782,7 +3782,7 @@ int i915_gem_wait_for_idle(struct drm_i915_private *i915, unsigned int flags)
 
 		ret = wait_for_engines(i915);
 	} else {
-		ret = wait_for_timeline(&i915->gt.global_timeline, flags);
+		ret = wait_for_timeline(&i915->gt.execution_timeline, flags);
 	}
 
 	return ret;
@@ -5651,7 +5651,8 @@ void i915_gem_cleanup_early(struct drm_i915_private *dev_priv)
 	WARN_ON(dev_priv->mm.object_count);
 
 	mutex_lock(&dev_priv->drm.struct_mutex);
-	i915_gem_timeline_fini(&dev_priv->gt.global_timeline);
+	i915_gem_timeline_fini(&dev_priv->gt.legacy_timeline);
+	i915_gem_timeline_fini(&dev_priv->gt.execution_timeline);
 	WARN_ON(!list_empty(&dev_priv->gt.timelines));
 	mutex_unlock(&dev_priv->drm.struct_mutex);
 
diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
index 74435affe23f..58b185abe652 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/i915_gem_context.c
@@ -122,6 +122,7 @@ static void i915_gem_context_free(struct i915_gem_context *ctx)
 	lockdep_assert_held(&ctx->i915->drm.struct_mutex);
 	GEM_BUG_ON(!i915_gem_context_is_closed(ctx));
 
+	i915_gem_timeline_free(ctx->timeline);
 	i915_ppgtt_put(ctx->ppgtt);
 
 	for (i = 0; i < I915_NUM_ENGINES; i++) {
@@ -376,6 +377,18 @@ i915_gem_create_context(struct drm_i915_private *dev_priv,
 		ctx->desc_template = default_desc_template(dev_priv, ppgtt);
 	}
 
+	if (HAS_EXECLISTS(dev_priv)) {
+		struct i915_gem_timeline *timeline;
+
+		timeline = i915_gem_timeline_create(dev_priv, ctx->name);
+		if (IS_ERR(timeline)) {
+			__destroy_hw_context(ctx, file_priv);
+			return ERR_CAST(timeline);
+		}
+
+		ctx->timeline = timeline;
+	}
+
 	trace_i915_context_create(ctx);
 
 	return ctx;
@@ -584,7 +597,7 @@ static bool engine_has_idle_kernel_context(struct intel_engine_cs *engine)
 	list_for_each_entry(timeline, &engine->i915->gt.timelines, link) {
 		struct intel_timeline *tl;
 
-		if (timeline == &engine->i915->gt.global_timeline)
+		if (timeline == &engine->i915->gt.execution_timeline)
 			continue;
 
 		tl = &timeline->engine[engine->id];
diff --git a/drivers/gpu/drm/i915/i915_gem_context.h b/drivers/gpu/drm/i915/i915_gem_context.h
index b12a8a8c5af9..140edcb424df 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.h
+++ b/drivers/gpu/drm/i915/i915_gem_context.h
@@ -58,6 +58,8 @@ struct i915_gem_context {
 	/** file_priv: owning file descriptor */
 	struct drm_i915_file_private *file_priv;
 
+	struct i915_gem_timeline *timeline;
+
 	/**
 	 * @ppgtt: unique address space (GTT)
 	 *
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index 21d72f695adb..e9d828324f67 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -2111,8 +2111,6 @@ static void i915_address_space_init(struct i915_address_space *vm,
 				    struct drm_i915_private *dev_priv,
 				    const char *name)
 {
-	i915_gem_timeline_init(dev_priv, &vm->timeline, name);
-
 	drm_mm_init(&vm->mm, 0, vm->total);
 	vm->mm.head_node.color = I915_COLOR_UNEVICTABLE;
 
@@ -2129,7 +2127,6 @@ static void i915_address_space_fini(struct i915_address_space *vm)
 	if (pagevec_count(&vm->free_pages))
 		vm_free_pages_release(vm, true);
 
-	i915_gem_timeline_fini(&vm->timeline);
 	drm_mm_takedown(&vm->mm);
 	list_del(&vm->global_link);
 }
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h
index 6efc017e8bb3..98107925de48 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.h
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.h
@@ -257,7 +257,6 @@ struct i915_pml4 {
 
 struct i915_address_space {
 	struct drm_mm mm;
-	struct i915_gem_timeline timeline;
 	struct drm_i915_private *i915;
 	struct device *dma;
 	/* Every address space belongs to a struct file - except for the global
diff --git a/drivers/gpu/drm/i915/i915_gem_timeline.c b/drivers/gpu/drm/i915/i915_gem_timeline.c
index e9fd87604067..24f4068cc137 100644
--- a/drivers/gpu/drm/i915/i915_gem_timeline.c
+++ b/drivers/gpu/drm/i915/i915_gem_timeline.c
@@ -95,12 +95,28 @@ int i915_gem_timeline_init(struct drm_i915_private *i915,
 
 int i915_gem_timeline_init__global(struct drm_i915_private *i915)
 {
-	static struct lock_class_key class;
+	static struct lock_class_key class1, class2;
+	int err;
+
+	err = __i915_gem_timeline_init(i915,
+				       &i915->gt.execution_timeline,
+				       "[execution]", &class1,
+				       "i915_execution_timeline");
+	if (err)
+		return err;
+
+	err = __i915_gem_timeline_init(i915,
+				       &i915->gt.legacy_timeline,
+				       "[global]", &class2,
+				       "i915_global_timeline");
+	if (err)
+		goto err_exec_timeline;
+
+	return 0;
 
-	return __i915_gem_timeline_init(i915,
-					&i915->gt.global_timeline,
-					"[execution]",
-					&class, "&global_timeline->lock");
+err_exec_timeline:
+	i915_gem_timeline_fini(&i915->gt.execution_timeline);
+	return err;
 }
 
 /**
@@ -148,6 +164,34 @@ void i915_gem_timeline_fini(struct i915_gem_timeline *timeline)
 	kfree(timeline->name);
 }
 
+struct i915_gem_timeline *
+i915_gem_timeline_create(struct drm_i915_private *i915, const char *name)
+{
+	struct i915_gem_timeline *timeline;
+	int err;
+
+	timeline = kzalloc(sizeof(*timeline), GFP_KERNEL);
+	if (!timeline)
+		return ERR_PTR(-ENOMEM);
+
+	err = i915_gem_timeline_init(i915, timeline, name);
+	if (err) {
+		kfree(timeline);
+		return ERR_PTR(err);
+	}
+
+	return timeline;
+}
+
+void i915_gem_timeline_free(struct i915_gem_timeline *timeline)
+{
+	if (!timeline)
+		return;
+
+	i915_gem_timeline_fini(timeline);
+	kfree(timeline);
+}
+
 #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
 #include "selftests/mock_timeline.c"
 #include "selftests/i915_gem_timeline.c"
diff --git a/drivers/gpu/drm/i915/i915_gem_timeline.h b/drivers/gpu/drm/i915/i915_gem_timeline.h
index 6e82119e2cd8..780ed465c4fc 100644
--- a/drivers/gpu/drm/i915/i915_gem_timeline.h
+++ b/drivers/gpu/drm/i915/i915_gem_timeline.h
@@ -90,6 +90,10 @@ int i915_gem_timeline_init__global(struct drm_i915_private *i915);
 void i915_gem_timelines_park(struct drm_i915_private *i915);
 void i915_gem_timeline_fini(struct i915_gem_timeline *tl);
 
+struct i915_gem_timeline *
+i915_gem_timeline_create(struct drm_i915_private *i915, const char *name);
+void i915_gem_timeline_free(struct i915_gem_timeline *timeline);
+
 static inline int __intel_timeline_sync_set(struct intel_timeline *tl,
 					    u64 context, u32 seqno)
 {
diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c
index 534b8d684cef..35869afdb199 100644
--- a/drivers/gpu/drm/i915/i915_request.c
+++ b/drivers/gpu/drm/i915/i915_request.c
@@ -639,6 +639,7 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx)
 	if (IS_ERR(ring))
 		return ERR_CAST(ring);
 	GEM_BUG_ON(!ring);
+	GEM_BUG_ON(ring->timeline == engine->timeline);
 
 	ret = reserve_engine(engine);
 	if (ret)
@@ -711,8 +712,12 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx)
 		}
 	}
 
-	rq->timeline = i915_gem_context_lookup_timeline(ctx, engine);
-	GEM_BUG_ON(rq->timeline == engine->timeline);
+	INIT_LIST_HEAD(&rq->active_list);
+	rq->i915 = i915;
+	rq->engine = engine;
+	rq->ctx = ctx;
+	rq->ring = ring;
+	rq->timeline = ring->timeline;
 
 	spin_lock_init(&rq->lock);
 	dma_fence_init(&rq->fence,
@@ -727,12 +732,6 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx)
 
 	i915_sched_node_init(&rq->sched);
 
-	INIT_LIST_HEAD(&rq->active_list);
-	rq->i915 = i915;
-	rq->engine = engine;
-	rq->ctx = ctx;
-	rq->ring = ring;
-
 	/* No zalloc, must clear what we need by hand */
 	rq->global_seqno = 0;
 	rq->signaling.wait.seqno = 0;
diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c
index a55a849b81b6..d44a8eb83379 100644
--- a/drivers/gpu/drm/i915/intel_engine_cs.c
+++ b/drivers/gpu/drm/i915/intel_engine_cs.c
@@ -453,7 +453,8 @@ void intel_engine_init_global_seqno(struct intel_engine_cs *engine, u32 seqno)
 
 static void intel_engine_init_timeline(struct intel_engine_cs *engine)
 {
-	engine->timeline = &engine->i915->gt.global_timeline.engine[engine->id];
+	engine->timeline =
+		&engine->i915->gt.execution_timeline.engine[engine->id];
 }
 
 static void intel_engine_init_batch_pool(struct intel_engine_cs *engine)
diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index 029901a8fa38..fd3539034665 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -2584,7 +2584,7 @@ static int execlists_context_deferred_alloc(struct i915_gem_context *ctx,
 		goto error_deref_obj;
 	}
 
-	ring = intel_engine_create_ring(engine, ctx->ring_size);
+	ring = intel_engine_create_ring(engine, ctx->timeline, ctx->ring_size);
 	if (IS_ERR(ring)) {
 		ret = PTR_ERR(ring);
 		goto error_deref_obj;
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index 3453e7426f6b..4559fe1c574e 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -1117,7 +1117,9 @@ intel_ring_create_vma(struct drm_i915_private *dev_priv, int size)
 }
 
 struct intel_ring *
-intel_engine_create_ring(struct intel_engine_cs *engine, int size)
+intel_engine_create_ring(struct intel_engine_cs *engine,
+			 struct i915_gem_timeline *timeline,
+			 int size)
 {
 	struct intel_ring *ring;
 	struct i915_vma *vma;
@@ -1131,6 +1133,7 @@ intel_engine_create_ring(struct intel_engine_cs *engine, int size)
 		return ERR_PTR(-ENOMEM);
 
 	INIT_LIST_HEAD(&ring->request_list);
+	ring->timeline = &timeline->engine[engine->id];
 
 	ring->size = size;
 	/* Workaround an erratum on the i830 which causes a hang if
@@ -1327,7 +1330,9 @@ static int intel_init_ring_buffer(struct intel_engine_cs *engine)
 	if (err)
 		goto err;
 
-	ring = intel_engine_create_ring(engine, 32 * PAGE_SIZE);
+	ring = intel_engine_create_ring(engine,
+					&engine->i915->gt.legacy_timeline,
+					32 * PAGE_SIZE);
 	if (IS_ERR(ring)) {
 		err = PTR_ERR(ring);
 		goto err;
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index fd5a6363ab1d..3f63499734f7 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -128,6 +128,7 @@ struct intel_ring {
 	struct i915_vma *vma;
 	void *vaddr;
 
+	struct intel_timeline *timeline;
 	struct list_head request_list;
 	struct list_head live;
 
@@ -767,7 +768,9 @@ intel_write_status_page(struct intel_engine_cs *engine, int reg, u32 value)
 #define CNL_HWS_CSB_WRITE_INDEX		0x2f
 
 struct intel_ring *
-intel_engine_create_ring(struct intel_engine_cs *engine, int size);
+intel_engine_create_ring(struct intel_engine_cs *engine,
+			 struct i915_gem_timeline *timeline,
+			 int size);
 int intel_ring_pin(struct intel_ring *ring,
 		   struct drm_i915_private *i915,
 		   unsigned int offset_bias);
diff --git a/drivers/gpu/drm/i915/selftests/mock_engine.c b/drivers/gpu/drm/i915/selftests/mock_engine.c
index 74a88913623f..6a10cb734c35 100644
--- a/drivers/gpu/drm/i915/selftests/mock_engine.c
+++ b/drivers/gpu/drm/i915/selftests/mock_engine.c
@@ -173,8 +173,7 @@ struct intel_engine_cs *mock_engine(struct drm_i915_private *i915,
 	engine->base.emit_breadcrumb = mock_emit_breadcrumb;
 	engine->base.submit_request = mock_submit_request;
 
-	engine->base.timeline =
-		&i915->gt.global_timeline.engine[engine->base.id];
+	intel_engine_init_timeline(&engine->base);
 
 	intel_engine_init_breadcrumbs(&engine->base);
 	engine->base.breadcrumbs.mock = true; /* prevent touching HW for irqs */
diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_device.c b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
index 9335b09d8b04..ed1bf3b2e47f 100644
--- a/drivers/gpu/drm/i915/selftests/mock_gem_device.c
+++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
@@ -73,7 +73,9 @@ static void mock_device_release(struct drm_device *dev)
 
 	mutex_lock(&i915->drm.struct_mutex);
 	mock_fini_ggtt(i915);
-	i915_gem_timeline_fini(&i915->gt.global_timeline);
+	i915_gem_timeline_fini(&i915->gt.legacy_timeline);
+	i915_gem_timeline_fini(&i915->gt.execution_timeline);
+	WARN_ON(!list_empty(&i915->gt.timelines));
 	mutex_unlock(&i915->drm.struct_mutex);
 
 	destroy_workqueue(i915->wq);
diff --git a/drivers/gpu/drm/i915/selftests/mock_gtt.c b/drivers/gpu/drm/i915/selftests/mock_gtt.c
index e96873f96116..36c112088940 100644
--- a/drivers/gpu/drm/i915/selftests/mock_gtt.c
+++ b/drivers/gpu/drm/i915/selftests/mock_gtt.c
@@ -76,7 +76,6 @@ mock_ppgtt(struct drm_i915_private *i915,
 
 	INIT_LIST_HEAD(&ppgtt->base.global_link);
 	drm_mm_init(&ppgtt->base.mm, 0, ppgtt->base.total);
-	i915_gem_timeline_init(i915, &ppgtt->base.timeline, name);
 
 	ppgtt->base.clear_range = nop_clear_range;
 	ppgtt->base.insert_page = mock_insert_page;
-- 
2.17.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 5/6] drm/i915: Split i915_gem_timeline into individual timelines
  2018-04-23 10:13 [PATCH 1/6] drm/i915: Stop tracking timeline->inflight_seqnos Chris Wilson
                   ` (2 preceding siblings ...)
  2018-04-23 10:13 ` [PATCH 4/6] drm/i915: Move timeline from GTT to ring Chris Wilson
@ 2018-04-23 10:13 ` Chris Wilson
  2018-04-23 12:33   ` Tvrtko Ursulin
  2018-04-23 10:14 ` [PATCH 6/6] drm/i915: Lazily unbind vma on close Chris Wilson
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 20+ messages in thread
From: Chris Wilson @ 2018-04-23 10:13 UTC (permalink / raw)
  To: intel-gfx

We need to move to a more flexible timeline that doesn't assume one
fence context per engine, and so allow for a single timeline to be used
across a combination of engines. This means that preallocating a fence
context per engine is now a hindrance, and so we want to introduce the
singular timeline. From the code perspective, this has the notable
advantage of clearing up a lot of mirky semantics and some clumsy
pointer chasing.

By splitting the timeline up into a single entity rather than an array
of per-engine timelines, we can realise the goal of the previous patch
of tracking the timeline alongside the ring.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
---
 drivers/gpu/drm/i915/Makefile                 |   2 +-
 drivers/gpu/drm/i915/i915_drv.h               |   4 +-
 drivers/gpu/drm/i915/i915_gem.c               | 117 +++++------
 drivers/gpu/drm/i915/i915_gem_context.c       |  49 ++---
 drivers/gpu/drm/i915/i915_gem_context.h       |   2 -
 drivers/gpu/drm/i915/i915_gem_gtt.h           |   3 +-
 drivers/gpu/drm/i915/i915_gem_timeline.c      | 198 ------------------
 drivers/gpu/drm/i915/i915_gpu_error.c         |   4 +-
 drivers/gpu/drm/i915/i915_perf.c              |  10 +-
 drivers/gpu/drm/i915/i915_request.c           |  65 +++---
 drivers/gpu/drm/i915/i915_request.h           |   3 +-
 drivers/gpu/drm/i915/i915_timeline.c          | 105 ++++++++++
 .../{i915_gem_timeline.h => i915_timeline.h}  |  67 +++---
 drivers/gpu/drm/i915/intel_engine_cs.c        |  27 ++-
 drivers/gpu/drm/i915/intel_guc_submission.c   |   4 +-
 drivers/gpu/drm/i915/intel_lrc.c              |  48 +++--
 drivers/gpu/drm/i915/intel_ringbuffer.c       |  23 +-
 drivers/gpu/drm/i915/intel_ringbuffer.h       |  11 +-
 .../{i915_gem_timeline.c => i915_timeline.c}  |  94 +++------
 drivers/gpu/drm/i915/selftests/mock_engine.c  |  32 ++-
 .../gpu/drm/i915/selftests/mock_gem_device.c  |  11 +-
 .../gpu/drm/i915/selftests/mock_timeline.c    |  45 ++--
 .../gpu/drm/i915/selftests/mock_timeline.h    |  28 +--
 23 files changed, 389 insertions(+), 563 deletions(-)
 delete mode 100644 drivers/gpu/drm/i915/i915_gem_timeline.c
 create mode 100644 drivers/gpu/drm/i915/i915_timeline.c
 rename drivers/gpu/drm/i915/{i915_gem_timeline.h => i915_timeline.h} (68%)
 rename drivers/gpu/drm/i915/selftests/{i915_gem_timeline.c => i915_timeline.c} (70%)

diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index 9bee52a949a9..120db21fcd50 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -67,11 +67,11 @@ i915-y += i915_cmd_parser.o \
 	  i915_gem_shrinker.o \
 	  i915_gem_stolen.o \
 	  i915_gem_tiling.o \
-	  i915_gem_timeline.o \
 	  i915_gem_userptr.o \
 	  i915_gemfs.o \
 	  i915_query.o \
 	  i915_request.o \
+	  i915_timeline.o \
 	  i915_trace_points.o \
 	  i915_vma.o \
 	  intel_breadcrumbs.o \
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 66123cf0eda3..89cb74c30a00 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -72,10 +72,10 @@
 #include "i915_gem_fence_reg.h"
 #include "i915_gem_object.h"
 #include "i915_gem_gtt.h"
-#include "i915_gem_timeline.h"
 #include "i915_gpu_error.h"
 #include "i915_request.h"
 #include "i915_scheduler.h"
+#include "i915_timeline.h"
 #include "i915_vma.h"
 
 #include "intel_gvt.h"
@@ -2058,8 +2058,6 @@ struct drm_i915_private {
 		void (*resume)(struct drm_i915_private *);
 		void (*cleanup_engine)(struct intel_engine_cs *engine);
 
-		struct i915_gem_timeline execution_timeline;
-		struct i915_gem_timeline legacy_timeline;
 		struct list_head timelines;
 		struct list_head live_rings;
 		u32 active_requests;
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 1635975dbc16..f07556693cfe 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -162,7 +162,7 @@ static u32 __i915_gem_park(struct drm_i915_private *i915)
 	synchronize_irq(i915->drm.irq);
 
 	intel_engines_park(i915);
-	i915_gem_timelines_park(i915);
+	i915_timelines_park(i915);
 
 	i915_pmu_gt_parked(i915);
 
@@ -2977,8 +2977,8 @@ i915_gem_find_active_request(struct intel_engine_cs *engine)
 	 * extra delay for a recent interrupt is pointless. Hence, we do
 	 * not need an engine->irq_seqno_barrier() before the seqno reads.
 	 */
-	spin_lock_irqsave(&engine->timeline->lock, flags);
-	list_for_each_entry(request, &engine->timeline->requests, link) {
+	spin_lock_irqsave(&engine->timeline.lock, flags);
+	list_for_each_entry(request, &engine->timeline.requests, link) {
 		if (__i915_request_completed(request, request->global_seqno))
 			continue;
 
@@ -2989,7 +2989,7 @@ i915_gem_find_active_request(struct intel_engine_cs *engine)
 		active = request;
 		break;
 	}
-	spin_unlock_irqrestore(&engine->timeline->lock, flags);
+	spin_unlock_irqrestore(&engine->timeline.lock, flags);
 
 	return active;
 }
@@ -3110,15 +3110,15 @@ static void engine_skip_context(struct i915_request *request)
 {
 	struct intel_engine_cs *engine = request->engine;
 	struct i915_gem_context *hung_ctx = request->ctx;
-	struct intel_timeline *timeline = request->timeline;
+	struct i915_timeline *timeline = request->timeline;
 	unsigned long flags;
 
-	GEM_BUG_ON(timeline == engine->timeline);
+	GEM_BUG_ON(timeline == &engine->timeline);
 
-	spin_lock_irqsave(&engine->timeline->lock, flags);
+	spin_lock_irqsave(&engine->timeline.lock, flags);
 	spin_lock(&timeline->lock);
 
-	list_for_each_entry_continue(request, &engine->timeline->requests, link)
+	list_for_each_entry_continue(request, &engine->timeline.requests, link)
 		if (request->ctx == hung_ctx)
 			skip_request(request);
 
@@ -3126,7 +3126,7 @@ static void engine_skip_context(struct i915_request *request)
 		skip_request(request);
 
 	spin_unlock(&timeline->lock);
-	spin_unlock_irqrestore(&engine->timeline->lock, flags);
+	spin_unlock_irqrestore(&engine->timeline.lock, flags);
 }
 
 /* Returns the request if it was guilty of the hang */
@@ -3183,11 +3183,11 @@ i915_gem_reset_request(struct intel_engine_cs *engine,
 			dma_fence_set_error(&request->fence, -EAGAIN);
 
 			/* Rewind the engine to replay the incomplete rq */
-			spin_lock_irq(&engine->timeline->lock);
+			spin_lock_irq(&engine->timeline.lock);
 			request = list_prev_entry(request, link);
-			if (&request->link == &engine->timeline->requests)
+			if (&request->link == &engine->timeline.requests)
 				request = NULL;
-			spin_unlock_irq(&engine->timeline->lock);
+			spin_unlock_irq(&engine->timeline.lock);
 		}
 	}
 
@@ -3300,10 +3300,10 @@ static void nop_complete_submit_request(struct i915_request *request)
 		  request->fence.context, request->fence.seqno);
 	dma_fence_set_error(&request->fence, -EIO);
 
-	spin_lock_irqsave(&request->engine->timeline->lock, flags);
+	spin_lock_irqsave(&request->engine->timeline.lock, flags);
 	__i915_request_submit(request);
 	intel_engine_init_global_seqno(request->engine, request->global_seqno);
-	spin_unlock_irqrestore(&request->engine->timeline->lock, flags);
+	spin_unlock_irqrestore(&request->engine->timeline.lock, flags);
 }
 
 void i915_gem_set_wedged(struct drm_i915_private *i915)
@@ -3372,10 +3372,10 @@ void i915_gem_set_wedged(struct drm_i915_private *i915)
 		 * (lockless) lookup doesn't try and wait upon the request as we
 		 * reset it.
 		 */
-		spin_lock_irqsave(&engine->timeline->lock, flags);
+		spin_lock_irqsave(&engine->timeline.lock, flags);
 		intel_engine_init_global_seqno(engine,
 					       intel_engine_last_submit(engine));
-		spin_unlock_irqrestore(&engine->timeline->lock, flags);
+		spin_unlock_irqrestore(&engine->timeline.lock, flags);
 
 		i915_gem_reset_finish_engine(engine);
 	}
@@ -3387,8 +3387,7 @@ void i915_gem_set_wedged(struct drm_i915_private *i915)
 
 bool i915_gem_unset_wedged(struct drm_i915_private *i915)
 {
-	struct i915_gem_timeline *tl;
-	int i;
+	struct i915_timeline *tl;
 
 	lockdep_assert_held(&i915->drm.struct_mutex);
 	if (!test_bit(I915_WEDGED, &i915->gpu_error.flags))
@@ -3407,29 +3406,27 @@ bool i915_gem_unset_wedged(struct drm_i915_private *i915)
 	 * No more can be submitted until we reset the wedged bit.
 	 */
 	list_for_each_entry(tl, &i915->gt.timelines, link) {
-		for (i = 0; i < ARRAY_SIZE(tl->engine); i++) {
-			struct i915_request *rq;
+		struct i915_request *rq;
 
-			rq = i915_gem_active_peek(&tl->engine[i].last_request,
-						  &i915->drm.struct_mutex);
-			if (!rq)
-				continue;
+		rq = i915_gem_active_peek(&tl->last_request,
+					  &i915->drm.struct_mutex);
+		if (!rq)
+			continue;
 
-			/*
-			 * We can't use our normal waiter as we want to
-			 * avoid recursively trying to handle the current
-			 * reset. The basic dma_fence_default_wait() installs
-			 * a callback for dma_fence_signal(), which is
-			 * triggered by our nop handler (indirectly, the
-			 * callback enables the signaler thread which is
-			 * woken by the nop_submit_request() advancing the seqno
-			 * and when the seqno passes the fence, the signaler
-			 * then signals the fence waking us up).
-			 */
-			if (dma_fence_default_wait(&rq->fence, true,
-						   MAX_SCHEDULE_TIMEOUT) < 0)
-				return false;
-		}
+		/*
+		 * We can't use our normal waiter as we want to
+		 * avoid recursively trying to handle the current
+		 * reset. The basic dma_fence_default_wait() installs
+		 * a callback for dma_fence_signal(), which is
+		 * triggered by our nop handler (indirectly, the
+		 * callback enables the signaler thread which is
+		 * woken by the nop_submit_request() advancing the seqno
+		 * and when the seqno passes the fence, the signaler
+		 * then signals the fence waking us up).
+		 */
+		if (dma_fence_default_wait(&rq->fence, true,
+					   MAX_SCHEDULE_TIMEOUT) < 0)
+			return false;
 	}
 	i915_retire_requests(i915);
 	GEM_BUG_ON(i915->gt.active_requests);
@@ -3734,19 +3731,6 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
 	return ret;
 }
 
-static int wait_for_timeline(struct i915_gem_timeline *tl, unsigned int flags)
-{
-	int ret, i;
-
-	for (i = 0; i < ARRAY_SIZE(tl->engine); i++) {
-		ret = i915_gem_active_wait(&tl->engine[i].last_request, flags);
-		if (ret)
-			return ret;
-	}
-
-	return 0;
-}
-
 static int wait_for_engines(struct drm_i915_private *i915)
 {
 	if (wait_for(intel_engines_are_idle(i915), I915_IDLE_ENGINES_TIMEOUT)) {
@@ -3769,12 +3753,12 @@ int i915_gem_wait_for_idle(struct drm_i915_private *i915, unsigned int flags)
 		return 0;
 
 	if (flags & I915_WAIT_LOCKED) {
-		struct i915_gem_timeline *tl;
+		struct i915_timeline *tl;
 
 		lockdep_assert_held(&i915->drm.struct_mutex);
 
 		list_for_each_entry(tl, &i915->gt.timelines, link) {
-			ret = wait_for_timeline(tl, flags);
+			ret = i915_gem_active_wait(&tl->last_request, flags);
 			if (ret)
 				return ret;
 		}
@@ -3782,7 +3766,16 @@ int i915_gem_wait_for_idle(struct drm_i915_private *i915, unsigned int flags)
 
 		ret = wait_for_engines(i915);
 	} else {
-		ret = wait_for_timeline(&i915->gt.execution_timeline, flags);
+		struct intel_engine_cs *engine;
+		enum intel_engine_id id;
+
+		for_each_engine(engine, i915, id) {
+			struct i915_timeline *tl = &engine->timeline;
+
+			ret = i915_gem_active_wait(&tl->last_request, flags);
+			if (ret)
+				return ret;
+		}
 	}
 
 	return ret;
@@ -4954,7 +4947,7 @@ static void assert_kernel_context_is_current(struct drm_i915_private *i915)
 	enum intel_engine_id id;
 
 	for_each_engine(engine, i915, id) {
-		GEM_BUG_ON(__i915_gem_active_peek(&engine->timeline->last_request));
+		GEM_BUG_ON(__i915_gem_active_peek(&engine->timeline.last_request));
 		GEM_BUG_ON(engine->last_retired_context != kernel_context);
 	}
 }
@@ -5600,13 +5593,8 @@ int i915_gem_init_early(struct drm_i915_private *dev_priv)
 	if (!dev_priv->priorities)
 		goto err_dependencies;
 
-	mutex_lock(&dev_priv->drm.struct_mutex);
 	INIT_LIST_HEAD(&dev_priv->gt.live_rings);
 	INIT_LIST_HEAD(&dev_priv->gt.timelines);
-	err = i915_gem_timeline_init__global(dev_priv);
-	mutex_unlock(&dev_priv->drm.struct_mutex);
-	if (err)
-		goto err_priorities;
 
 	i915_gem_init__mm(dev_priv);
 
@@ -5627,8 +5615,6 @@ int i915_gem_init_early(struct drm_i915_private *dev_priv)
 
 	return 0;
 
-err_priorities:
-	kmem_cache_destroy(dev_priv->priorities);
 err_dependencies:
 	kmem_cache_destroy(dev_priv->dependencies);
 err_requests:
@@ -5649,12 +5635,7 @@ void i915_gem_cleanup_early(struct drm_i915_private *dev_priv)
 	GEM_BUG_ON(!llist_empty(&dev_priv->mm.free_list));
 	GEM_BUG_ON(atomic_read(&dev_priv->mm.free_count));
 	WARN_ON(dev_priv->mm.object_count);
-
-	mutex_lock(&dev_priv->drm.struct_mutex);
-	i915_gem_timeline_fini(&dev_priv->gt.legacy_timeline);
-	i915_gem_timeline_fini(&dev_priv->gt.execution_timeline);
 	WARN_ON(!list_empty(&dev_priv->gt.timelines));
-	mutex_unlock(&dev_priv->drm.struct_mutex);
 
 	kmem_cache_destroy(dev_priv->priorities);
 	kmem_cache_destroy(dev_priv->dependencies);
diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
index 58b185abe652..027b7ddae1d3 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/i915_gem_context.c
@@ -122,7 +122,6 @@ static void i915_gem_context_free(struct i915_gem_context *ctx)
 	lockdep_assert_held(&ctx->i915->drm.struct_mutex);
 	GEM_BUG_ON(!i915_gem_context_is_closed(ctx));
 
-	i915_gem_timeline_free(ctx->timeline);
 	i915_ppgtt_put(ctx->ppgtt);
 
 	for (i = 0; i < I915_NUM_ENGINES; i++) {
@@ -377,18 +376,6 @@ i915_gem_create_context(struct drm_i915_private *dev_priv,
 		ctx->desc_template = default_desc_template(dev_priv, ppgtt);
 	}
 
-	if (HAS_EXECLISTS(dev_priv)) {
-		struct i915_gem_timeline *timeline;
-
-		timeline = i915_gem_timeline_create(dev_priv, ctx->name);
-		if (IS_ERR(timeline)) {
-			__destroy_hw_context(ctx, file_priv);
-			return ERR_CAST(timeline);
-		}
-
-		ctx->timeline = timeline;
-	}
-
 	trace_i915_context_create(ctx);
 
 	return ctx;
@@ -590,21 +577,30 @@ void i915_gem_context_close(struct drm_file *file)
 	idr_destroy(&file_priv->context_idr);
 }
 
-static bool engine_has_idle_kernel_context(struct intel_engine_cs *engine)
+static struct i915_request *
+last_timeline_request(struct i915_timeline *timeline,
+		      struct intel_engine_cs *engine)
 {
-	struct i915_gem_timeline *timeline;
+	struct i915_request *rq;
 
-	list_for_each_entry(timeline, &engine->i915->gt.timelines, link) {
-		struct intel_timeline *tl;
+	if (timeline == &engine->timeline)
+		return NULL;
 
-		if (timeline == &engine->i915->gt.execution_timeline)
-			continue;
+	rq = i915_gem_active_raw(&timeline->last_request,
+				 &engine->i915->drm.struct_mutex);
+	if (rq && rq->engine == engine)
+		return rq;
+
+	return NULL;
+}
 
-		tl = &timeline->engine[engine->id];
-		if (i915_gem_active_peek(&tl->last_request,
-					 &engine->i915->drm.struct_mutex))
+static bool engine_has_idle_kernel_context(struct intel_engine_cs *engine)
+{
+	struct i915_timeline *timeline;
+
+	list_for_each_entry(timeline, &engine->i915->gt.timelines, link)
+		if (last_timeline_request(timeline, engine))
 			return false;
-	}
 
 	return intel_engine_has_kernel_context(engine);
 }
@@ -612,7 +608,7 @@ static bool engine_has_idle_kernel_context(struct intel_engine_cs *engine)
 int i915_gem_switch_to_kernel_context(struct drm_i915_private *dev_priv)
 {
 	struct intel_engine_cs *engine;
-	struct i915_gem_timeline *timeline;
+	struct i915_timeline *timeline;
 	enum intel_engine_id id;
 
 	lockdep_assert_held(&dev_priv->drm.struct_mutex);
@@ -632,11 +628,8 @@ int i915_gem_switch_to_kernel_context(struct drm_i915_private *dev_priv)
 		/* Queue this switch after all other activity */
 		list_for_each_entry(timeline, &dev_priv->gt.timelines, link) {
 			struct i915_request *prev;
-			struct intel_timeline *tl;
 
-			tl = &timeline->engine[engine->id];
-			prev = i915_gem_active_raw(&tl->last_request,
-						   &dev_priv->drm.struct_mutex);
+			prev = last_timeline_request(timeline, engine);
 			if (prev)
 				i915_sw_fence_await_sw_fence_gfp(&rq->submit,
 								 &prev->submit,
diff --git a/drivers/gpu/drm/i915/i915_gem_context.h b/drivers/gpu/drm/i915/i915_gem_context.h
index 140edcb424df..b12a8a8c5af9 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.h
+++ b/drivers/gpu/drm/i915/i915_gem_context.h
@@ -58,8 +58,6 @@ struct i915_gem_context {
 	/** file_priv: owning file descriptor */
 	struct drm_i915_file_private *file_priv;
 
-	struct i915_gem_timeline *timeline;
-
 	/**
 	 * @ppgtt: unique address space (GTT)
 	 *
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h
index 98107925de48..1db0dedb4059 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.h
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.h
@@ -38,10 +38,9 @@
 #include <linux/mm.h>
 #include <linux/pagevec.h>
 
-#include "i915_gem_timeline.h"
-
 #include "i915_request.h"
 #include "i915_selftest.h"
+#include "i915_timeline.h"
 
 #define I915_GTT_PAGE_SIZE_4K BIT(12)
 #define I915_GTT_PAGE_SIZE_64K BIT(16)
diff --git a/drivers/gpu/drm/i915/i915_gem_timeline.c b/drivers/gpu/drm/i915/i915_gem_timeline.c
deleted file mode 100644
index 24f4068cc137..000000000000
--- a/drivers/gpu/drm/i915/i915_gem_timeline.c
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright © 2016 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- *
- */
-
-#include "i915_drv.h"
-#include "i915_syncmap.h"
-
-static void __intel_timeline_init(struct intel_timeline *tl,
-				  struct i915_gem_timeline *parent,
-				  u64 context,
-				  struct lock_class_key *lockclass,
-				  const char *lockname)
-{
-	tl->fence_context = context;
-	tl->common = parent;
-	spin_lock_init(&tl->lock);
-	lockdep_set_class_and_name(&tl->lock, lockclass, lockname);
-	init_request_active(&tl->last_request, NULL);
-	INIT_LIST_HEAD(&tl->requests);
-	i915_syncmap_init(&tl->sync);
-}
-
-static void __intel_timeline_fini(struct intel_timeline *tl)
-{
-	GEM_BUG_ON(!list_empty(&tl->requests));
-
-	i915_syncmap_free(&tl->sync);
-}
-
-static int __i915_gem_timeline_init(struct drm_i915_private *i915,
-				    struct i915_gem_timeline *timeline,
-				    const char *name,
-				    struct lock_class_key *lockclass,
-				    const char *lockname)
-{
-	unsigned int i;
-	u64 fences;
-
-	lockdep_assert_held(&i915->drm.struct_mutex);
-
-	/*
-	 * Ideally we want a set of engines on a single leaf as we expect
-	 * to mostly be tracking synchronisation between engines. It is not
-	 * a huge issue if this is not the case, but we may want to mitigate
-	 * any page crossing penalties if they become an issue.
-	 */
-	BUILD_BUG_ON(KSYNCMAP < I915_NUM_ENGINES);
-
-	timeline->i915 = i915;
-	timeline->name = kstrdup(name ?: "[kernel]", GFP_KERNEL);
-	if (!timeline->name)
-		return -ENOMEM;
-
-	list_add(&timeline->link, &i915->gt.timelines);
-
-	/* Called during early_init before we know how many engines there are */
-	fences = dma_fence_context_alloc(ARRAY_SIZE(timeline->engine));
-	for (i = 0; i < ARRAY_SIZE(timeline->engine); i++)
-		__intel_timeline_init(&timeline->engine[i],
-				      timeline, fences++,
-				      lockclass, lockname);
-
-	return 0;
-}
-
-int i915_gem_timeline_init(struct drm_i915_private *i915,
-			   struct i915_gem_timeline *timeline,
-			   const char *name)
-{
-	static struct lock_class_key class;
-
-	return __i915_gem_timeline_init(i915, timeline, name,
-					&class, "&timeline->lock");
-}
-
-int i915_gem_timeline_init__global(struct drm_i915_private *i915)
-{
-	static struct lock_class_key class1, class2;
-	int err;
-
-	err = __i915_gem_timeline_init(i915,
-				       &i915->gt.execution_timeline,
-				       "[execution]", &class1,
-				       "i915_execution_timeline");
-	if (err)
-		return err;
-
-	err = __i915_gem_timeline_init(i915,
-				       &i915->gt.legacy_timeline,
-				       "[global]", &class2,
-				       "i915_global_timeline");
-	if (err)
-		goto err_exec_timeline;
-
-	return 0;
-
-err_exec_timeline:
-	i915_gem_timeline_fini(&i915->gt.execution_timeline);
-	return err;
-}
-
-/**
- * i915_gem_timelines_park - called when the driver idles
- * @i915: the drm_i915_private device
- *
- * When the driver is completely idle, we know that all of our sync points
- * have been signaled and our tracking is then entirely redundant. Any request
- * to wait upon an older sync point will be completed instantly as we know
- * the fence is signaled and therefore we will not even look them up in the
- * sync point map.
- */
-void i915_gem_timelines_park(struct drm_i915_private *i915)
-{
-	struct i915_gem_timeline *timeline;
-	int i;
-
-	lockdep_assert_held(&i915->drm.struct_mutex);
-
-	list_for_each_entry(timeline, &i915->gt.timelines, link) {
-		for (i = 0; i < ARRAY_SIZE(timeline->engine); i++) {
-			struct intel_timeline *tl = &timeline->engine[i];
-
-			/*
-			 * All known fences are completed so we can scrap
-			 * the current sync point tracking and start afresh,
-			 * any attempt to wait upon a previous sync point
-			 * will be skipped as the fence was signaled.
-			 */
-			i915_syncmap_free(&tl->sync);
-		}
-	}
-}
-
-void i915_gem_timeline_fini(struct i915_gem_timeline *timeline)
-{
-	int i;
-
-	lockdep_assert_held(&timeline->i915->drm.struct_mutex);
-
-	for (i = 0; i < ARRAY_SIZE(timeline->engine); i++)
-		__intel_timeline_fini(&timeline->engine[i]);
-
-	list_del(&timeline->link);
-	kfree(timeline->name);
-}
-
-struct i915_gem_timeline *
-i915_gem_timeline_create(struct drm_i915_private *i915, const char *name)
-{
-	struct i915_gem_timeline *timeline;
-	int err;
-
-	timeline = kzalloc(sizeof(*timeline), GFP_KERNEL);
-	if (!timeline)
-		return ERR_PTR(-ENOMEM);
-
-	err = i915_gem_timeline_init(i915, timeline, name);
-	if (err) {
-		kfree(timeline);
-		return ERR_PTR(err);
-	}
-
-	return timeline;
-}
-
-void i915_gem_timeline_free(struct i915_gem_timeline *timeline)
-{
-	if (!timeline)
-		return;
-
-	i915_gem_timeline_fini(timeline);
-	kfree(timeline);
-}
-
-#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
-#include "selftests/mock_timeline.c"
-#include "selftests/i915_gem_timeline.c"
-#endif
diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c
index 671ffa37614e..71bb8230cb97 100644
--- a/drivers/gpu/drm/i915/i915_gpu_error.c
+++ b/drivers/gpu/drm/i915/i915_gpu_error.c
@@ -1299,7 +1299,7 @@ static void engine_record_requests(struct intel_engine_cs *engine,
 
 	count = 0;
 	request = first;
-	list_for_each_entry_from(request, &engine->timeline->requests, link)
+	list_for_each_entry_from(request, &engine->timeline.requests, link)
 		count++;
 	if (!count)
 		return;
@@ -1312,7 +1312,7 @@ static void engine_record_requests(struct intel_engine_cs *engine,
 
 	count = 0;
 	request = first;
-	list_for_each_entry_from(request, &engine->timeline->requests, link) {
+	list_for_each_entry_from(request, &engine->timeline.requests, link) {
 		if (count >= ee->num_requests) {
 			/*
 			 * If the ring request list was changed in
diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c
index bfc906cd4e5e..5dcd76e27c68 100644
--- a/drivers/gpu/drm/i915/i915_perf.c
+++ b/drivers/gpu/drm/i915/i915_perf.c
@@ -1695,7 +1695,7 @@ static int gen8_switch_to_updated_kernel_context(struct drm_i915_private *dev_pr
 						 const struct i915_oa_config *oa_config)
 {
 	struct intel_engine_cs *engine = dev_priv->engine[RCS];
-	struct i915_gem_timeline *timeline;
+	struct i915_timeline *timeline;
 	struct i915_request *rq;
 	int ret;
 
@@ -1716,15 +1716,11 @@ static int gen8_switch_to_updated_kernel_context(struct drm_i915_private *dev_pr
 	/* Queue this switch after all other activity */
 	list_for_each_entry(timeline, &dev_priv->gt.timelines, link) {
 		struct i915_request *prev;
-		struct intel_timeline *tl;
 
-		tl = &timeline->engine[engine->id];
-		prev = i915_gem_active_raw(&tl->last_request,
+		prev = i915_gem_active_raw(&timeline->last_request,
 					   &dev_priv->drm.struct_mutex);
 		if (prev)
-			i915_sw_fence_await_sw_fence_gfp(&rq->submit,
-							 &prev->submit,
-							 GFP_KERNEL);
+			i915_request_await_dma_fence(rq, &prev->fence);
 	}
 
 	i915_request_add(rq);
diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c
index 35869afdb199..4e6c1022519c 100644
--- a/drivers/gpu/drm/i915/i915_request.c
+++ b/drivers/gpu/drm/i915/i915_request.c
@@ -49,7 +49,7 @@ static const char *i915_fence_get_timeline_name(struct dma_fence *fence)
 	if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags))
 		return "signaled";
 
-	return to_request(fence)->timeline->common->name;
+	return to_request(fence)->timeline->name;
 }
 
 static bool i915_fence_signaled(struct dma_fence *fence)
@@ -199,6 +199,7 @@ i915_sched_node_init(struct i915_sched_node *node)
 static int reset_all_global_seqno(struct drm_i915_private *i915, u32 seqno)
 {
 	struct intel_engine_cs *engine;
+	struct i915_timeline *timeline;
 	enum intel_engine_id id;
 	int ret;
 
@@ -213,16 +214,13 @@ static int reset_all_global_seqno(struct drm_i915_private *i915, u32 seqno)
 
 	/* If the seqno wraps around, we need to clear the breadcrumb rbtree */
 	for_each_engine(engine, i915, id) {
-		struct i915_gem_timeline *timeline;
-		struct intel_timeline *tl = engine->timeline;
-
 		GEM_TRACE("%s seqno %d (current %d) -> %d\n",
 			  engine->name,
-			  tl->seqno,
+			  engine->timeline.seqno,
 			  intel_engine_get_seqno(engine),
 			  seqno);
 
-		if (!i915_seqno_passed(seqno, tl->seqno)) {
+		if (!i915_seqno_passed(seqno, engine->timeline.seqno)) {
 			/* Flush any waiters before we reuse the seqno */
 			intel_engine_disarm_breadcrumbs(engine);
 			GEM_BUG_ON(!list_empty(&engine->breadcrumbs.signals));
@@ -230,17 +228,16 @@ static int reset_all_global_seqno(struct drm_i915_private *i915, u32 seqno)
 
 		/* Check we are idle before we fiddle with hw state! */
 		GEM_BUG_ON(!intel_engine_is_idle(engine));
-		GEM_BUG_ON(i915_gem_active_isset(&engine->timeline->last_request));
+		GEM_BUG_ON(i915_gem_active_isset(&engine->timeline.last_request));
 
 		/* Finally reset hw state */
 		intel_engine_init_global_seqno(engine, seqno);
-		tl->seqno = seqno;
-
-		list_for_each_entry(timeline, &i915->gt.timelines, link)
-			memset(timeline->engine[id].global_sync, 0,
-			       sizeof(timeline->engine[id].global_sync));
+		engine->timeline.seqno = seqno;
 	}
 
+	list_for_each_entry(timeline, &i915->gt.timelines, link)
+		memset(timeline->global_sync, 0, sizeof(timeline->global_sync));
+
 	return 0;
 }
 
@@ -263,7 +260,7 @@ static int reserve_engine(struct intel_engine_cs *engine)
 	int ret;
 
 	/* Reservation is fine until we need to wrap around */
-	if (unlikely(add_overflows(engine->timeline->seqno,
+	if (unlikely(add_overflows(engine->timeline.seqno,
 				   i915->gt.active_requests + 1))) {
 		ret = reset_all_global_seqno(i915, 0);
 		if (ret)
@@ -356,9 +353,9 @@ static void i915_request_retire(struct i915_request *request)
 
 	trace_i915_request_retire(request);
 
-	spin_lock_irq(&engine->timeline->lock);
+	spin_lock_irq(&engine->timeline.lock);
 	list_del_init(&request->link);
-	spin_unlock_irq(&engine->timeline->lock);
+	spin_unlock_irq(&engine->timeline.lock);
 
 	unreserve_engine(request->engine);
 	advance_ring(request);
@@ -445,16 +442,16 @@ void i915_request_retire_upto(struct i915_request *rq)
 	} while (tmp != rq);
 }
 
-static u32 timeline_get_seqno(struct intel_timeline *tl)
+static u32 timeline_get_seqno(struct i915_timeline *tl)
 {
 	return ++tl->seqno;
 }
 
 static void move_to_timeline(struct i915_request *request,
-			     struct intel_timeline *timeline)
+			     struct i915_timeline *timeline)
 {
-	GEM_BUG_ON(request->timeline == request->engine->timeline);
-	lockdep_assert_held(&request->engine->timeline->lock);
+	GEM_BUG_ON(request->timeline == &request->engine->timeline);
+	lockdep_assert_held(&request->engine->timeline.lock);
 
 	spin_lock(&request->timeline->lock);
 	list_move_tail(&request->link, &timeline->requests);
@@ -469,15 +466,15 @@ void __i915_request_submit(struct i915_request *request)
 	GEM_TRACE("%s fence %llx:%d -> global=%d, current %d\n",
 		  engine->name,
 		  request->fence.context, request->fence.seqno,
-		  engine->timeline->seqno + 1,
+		  engine->timeline.seqno + 1,
 		  intel_engine_get_seqno(engine));
 
 	GEM_BUG_ON(!irqs_disabled());
-	lockdep_assert_held(&engine->timeline->lock);
+	lockdep_assert_held(&engine->timeline.lock);
 
 	GEM_BUG_ON(request->global_seqno);
 
-	seqno = timeline_get_seqno(engine->timeline);
+	seqno = timeline_get_seqno(&engine->timeline);
 	GEM_BUG_ON(!seqno);
 	GEM_BUG_ON(i915_seqno_passed(intel_engine_get_seqno(engine), seqno));
 
@@ -492,7 +489,7 @@ void __i915_request_submit(struct i915_request *request)
 				request->ring->vaddr + request->postfix);
 
 	/* Transfer from per-context onto the global per-engine timeline */
-	move_to_timeline(request, engine->timeline);
+	move_to_timeline(request, &engine->timeline);
 
 	trace_i915_request_execute(request);
 
@@ -505,11 +502,11 @@ void i915_request_submit(struct i915_request *request)
 	unsigned long flags;
 
 	/* Will be called from irq-context when using foreign fences. */
-	spin_lock_irqsave(&engine->timeline->lock, flags);
+	spin_lock_irqsave(&engine->timeline.lock, flags);
 
 	__i915_request_submit(request);
 
-	spin_unlock_irqrestore(&engine->timeline->lock, flags);
+	spin_unlock_irqrestore(&engine->timeline.lock, flags);
 }
 
 void __i915_request_unsubmit(struct i915_request *request)
@@ -523,17 +520,17 @@ void __i915_request_unsubmit(struct i915_request *request)
 		  intel_engine_get_seqno(engine));
 
 	GEM_BUG_ON(!irqs_disabled());
-	lockdep_assert_held(&engine->timeline->lock);
+	lockdep_assert_held(&engine->timeline.lock);
 
 	/*
 	 * Only unwind in reverse order, required so that the per-context list
 	 * is kept in seqno/ring order.
 	 */
 	GEM_BUG_ON(!request->global_seqno);
-	GEM_BUG_ON(request->global_seqno != engine->timeline->seqno);
+	GEM_BUG_ON(request->global_seqno != engine->timeline.seqno);
 	GEM_BUG_ON(i915_seqno_passed(intel_engine_get_seqno(engine),
 				     request->global_seqno));
-	engine->timeline->seqno--;
+	engine->timeline.seqno--;
 
 	/* We may be recursing from the signal callback of another i915 fence */
 	spin_lock_nested(&request->lock, SINGLE_DEPTH_NESTING);
@@ -560,11 +557,11 @@ void i915_request_unsubmit(struct i915_request *request)
 	unsigned long flags;
 
 	/* Will be called from irq-context when using foreign fences. */
-	spin_lock_irqsave(&engine->timeline->lock, flags);
+	spin_lock_irqsave(&engine->timeline.lock, flags);
 
 	__i915_request_unsubmit(request);
 
-	spin_unlock_irqrestore(&engine->timeline->lock, flags);
+	spin_unlock_irqrestore(&engine->timeline.lock, flags);
 }
 
 static int __i915_sw_fence_call
@@ -639,7 +636,7 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx)
 	if (IS_ERR(ring))
 		return ERR_CAST(ring);
 	GEM_BUG_ON(!ring);
-	GEM_BUG_ON(ring->timeline == engine->timeline);
+	GEM_BUG_ON(ring->timeline == &engine->timeline);
 
 	ret = reserve_engine(engine);
 	if (ret)
@@ -879,7 +876,7 @@ i915_request_await_dma_fence(struct i915_request *rq, struct dma_fence *fence)
 
 		/* Squash repeated waits to the same timelines */
 		if (fence->context != rq->i915->mm.unordered_timeline &&
-		    intel_timeline_sync_is_later(rq->timeline, fence))
+		    i915_timeline_sync_is_later(rq->timeline, fence))
 			continue;
 
 		if (dma_fence_is_i915(fence))
@@ -893,7 +890,7 @@ i915_request_await_dma_fence(struct i915_request *rq, struct dma_fence *fence)
 
 		/* Record the latest fence used against each timeline */
 		if (fence->context != rq->i915->mm.unordered_timeline)
-			intel_timeline_sync_set(rq->timeline, fence);
+			i915_timeline_sync_set(rq->timeline, fence);
 	} while (--nchild);
 
 	return 0;
@@ -970,7 +967,7 @@ void __i915_request_add(struct i915_request *request, bool flush_caches)
 {
 	struct intel_engine_cs *engine = request->engine;
 	struct intel_ring *ring = request->ring;
-	struct intel_timeline *timeline = request->timeline;
+	struct i915_timeline *timeline = request->timeline;
 	struct i915_request *prev;
 	u32 *cs;
 	int err;
diff --git a/drivers/gpu/drm/i915/i915_request.h b/drivers/gpu/drm/i915/i915_request.h
index 8f31ca8272f8..eddbd4245cb3 100644
--- a/drivers/gpu/drm/i915/i915_request.h
+++ b/drivers/gpu/drm/i915/i915_request.h
@@ -37,6 +37,7 @@
 struct drm_file;
 struct drm_i915_gem_object;
 struct i915_request;
+struct i915_timeline;
 
 struct intel_wait {
 	struct rb_node node;
@@ -95,7 +96,7 @@ struct i915_request {
 	struct i915_gem_context *ctx;
 	struct intel_engine_cs *engine;
 	struct intel_ring *ring;
-	struct intel_timeline *timeline;
+	struct i915_timeline *timeline;
 	struct intel_signal_node signaling;
 
 	/*
diff --git a/drivers/gpu/drm/i915/i915_timeline.c b/drivers/gpu/drm/i915/i915_timeline.c
new file mode 100644
index 000000000000..4667cc08c416
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_timeline.c
@@ -0,0 +1,105 @@
+/*
+ * SPDX-License-Identifier: MIT
+ *
+ * Copyright © 2016-2018 Intel Corporation
+ */
+
+#include "i915_drv.h"
+
+#include "i915_timeline.h"
+#include "i915_syncmap.h"
+
+void i915_timeline_init(struct drm_i915_private *i915,
+			struct i915_timeline *timeline,
+			const char *name)
+{
+	lockdep_assert_held(&i915->drm.struct_mutex);
+
+	/*
+	 * Ideally we want a set of engines on a single leaf as we expect
+	 * to mostly be tracking synchronisation between engines. It is not
+	 * a huge issue if this is not the case, but we may want to mitigate
+	 * any page crossing penalties if they become an issue.
+	 */
+	BUILD_BUG_ON(KSYNCMAP < I915_NUM_ENGINES);
+
+	timeline->name = name;
+
+	list_add(&timeline->link, &i915->gt.timelines);
+
+	/* Called during early_init before we know how many engines there are */
+
+	timeline->fence_context = dma_fence_context_alloc(1);
+
+	spin_lock_init(&timeline->lock);
+
+	init_request_active(&timeline->last_request, NULL);
+	INIT_LIST_HEAD(&timeline->requests);
+
+	i915_syncmap_init(&timeline->sync);
+}
+
+/**
+ * i915_timelines_park - called when the driver idles
+ * @i915: the drm_i915_private device
+ *
+ * When the driver is completely idle, we know that all of our sync points
+ * have been signaled and our tracking is then entirely redundant. Any request
+ * to wait upon an older sync point will be completed instantly as we know
+ * the fence is signaled and therefore we will not even look them up in the
+ * sync point map.
+ */
+void i915_timelines_park(struct drm_i915_private *i915)
+{
+	struct i915_timeline *timeline;
+
+	lockdep_assert_held(&i915->drm.struct_mutex);
+
+	list_for_each_entry(timeline, &i915->gt.timelines, link) {
+		/*
+		 * All known fences are completed so we can scrap
+		 * the current sync point tracking and start afresh,
+		 * any attempt to wait upon a previous sync point
+		 * will be skipped as the fence was signaled.
+		 */
+		i915_syncmap_free(&timeline->sync);
+	}
+}
+
+void i915_timeline_fini(struct i915_timeline *timeline)
+{
+	GEM_BUG_ON(!list_empty(&timeline->requests));
+
+	i915_syncmap_free(&timeline->sync);
+
+	list_del(&timeline->link);
+}
+
+struct i915_timeline *
+i915_timeline_create(struct drm_i915_private *i915, const char *name)
+{
+	struct i915_timeline *timeline;
+
+	timeline = kzalloc(sizeof(*timeline), GFP_KERNEL);
+	if (!timeline)
+		return ERR_PTR(-ENOMEM);
+
+	i915_timeline_init(i915, timeline, name);
+	kref_init(&timeline->kref);
+
+	return timeline;
+}
+
+void __i915_timeline_free(struct kref *kref)
+{
+	struct i915_timeline *timeline =
+		container_of(kref, typeof(*timeline), kref);
+
+	i915_timeline_fini(timeline);
+	kfree(timeline);
+}
+
+#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
+#include "selftests/mock_timeline.c"
+#include "selftests/i915_timeline.c"
+#endif
diff --git a/drivers/gpu/drm/i915/i915_gem_timeline.h b/drivers/gpu/drm/i915/i915_timeline.h
similarity index 68%
rename from drivers/gpu/drm/i915/i915_gem_timeline.h
rename to drivers/gpu/drm/i915/i915_timeline.h
index 780ed465c4fc..dc2a4632faa7 100644
--- a/drivers/gpu/drm/i915/i915_gem_timeline.h
+++ b/drivers/gpu/drm/i915/i915_timeline.h
@@ -22,18 +22,17 @@
  *
  */
 
-#ifndef I915_GEM_TIMELINE_H
-#define I915_GEM_TIMELINE_H
+#ifndef I915_TIMELINE_H
+#define I915_TIMELINE_H
 
 #include <linux/list.h>
+#include <linux/kref.h>
 
 #include "i915_request.h"
 #include "i915_syncmap.h"
 #include "i915_utils.h"
 
-struct i915_gem_timeline;
-
-struct intel_timeline {
+struct i915_timeline {
 	u64 fence_context;
 	u32 seqno;
 
@@ -71,51 +70,57 @@ struct intel_timeline {
 	 */
 	u32 global_sync[I915_NUM_ENGINES];
 
-	struct i915_gem_timeline *common;
-};
-
-struct i915_gem_timeline {
 	struct list_head link;
-
-	struct drm_i915_private *i915;
 	const char *name;
 
-	struct intel_timeline engine[I915_NUM_ENGINES];
+	struct kref kref;
 };
 
-int i915_gem_timeline_init(struct drm_i915_private *i915,
-			   struct i915_gem_timeline *tl,
-			   const char *name);
-int i915_gem_timeline_init__global(struct drm_i915_private *i915);
-void i915_gem_timelines_park(struct drm_i915_private *i915);
-void i915_gem_timeline_fini(struct i915_gem_timeline *tl);
+void i915_timeline_init(struct drm_i915_private *i915,
+			struct i915_timeline *tl,
+			const char *name);
+void i915_timeline_fini(struct i915_timeline *tl);
 
-struct i915_gem_timeline *
-i915_gem_timeline_create(struct drm_i915_private *i915, const char *name);
-void i915_gem_timeline_free(struct i915_gem_timeline *timeline);
+struct i915_timeline *
+i915_timeline_create(struct drm_i915_private *i915, const char *name);
 
-static inline int __intel_timeline_sync_set(struct intel_timeline *tl,
-					    u64 context, u32 seqno)
+static inline struct i915_timeline *
+i915_timeline_get(struct i915_timeline *timeline)
+{
+	kref_get(&timeline->kref);
+	return timeline;
+}
+
+void __i915_timeline_free(struct kref *kref);
+static inline void i915_timeline_put(struct i915_timeline *timeline)
+{
+	kref_put(&timeline->kref, __i915_timeline_free);
+}
+
+static inline int __i915_timeline_sync_set(struct i915_timeline *tl,
+					   u64 context, u32 seqno)
 {
 	return i915_syncmap_set(&tl->sync, context, seqno);
 }
 
-static inline int intel_timeline_sync_set(struct intel_timeline *tl,
-					  const struct dma_fence *fence)
+static inline int i915_timeline_sync_set(struct i915_timeline *tl,
+					 const struct dma_fence *fence)
 {
-	return __intel_timeline_sync_set(tl, fence->context, fence->seqno);
+	return __i915_timeline_sync_set(tl, fence->context, fence->seqno);
 }
 
-static inline bool __intel_timeline_sync_is_later(struct intel_timeline *tl,
-						  u64 context, u32 seqno)
+static inline bool __i915_timeline_sync_is_later(struct i915_timeline *tl,
+						 u64 context, u32 seqno)
 {
 	return i915_syncmap_is_later(&tl->sync, context, seqno);
 }
 
-static inline bool intel_timeline_sync_is_later(struct intel_timeline *tl,
-						const struct dma_fence *fence)
+static inline bool i915_timeline_sync_is_later(struct i915_timeline *tl,
+					       const struct dma_fence *fence)
 {
-	return __intel_timeline_sync_is_later(tl, fence->context, fence->seqno);
+	return __i915_timeline_sync_is_later(tl, fence->context, fence->seqno);
 }
 
+void i915_timelines_park(struct drm_i915_private *i915);
+
 #endif
diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c
index d44a8eb83379..dcfdd4439935 100644
--- a/drivers/gpu/drm/i915/intel_engine_cs.c
+++ b/drivers/gpu/drm/i915/intel_engine_cs.c
@@ -451,12 +451,6 @@ void intel_engine_init_global_seqno(struct intel_engine_cs *engine, u32 seqno)
 	GEM_BUG_ON(intel_engine_get_seqno(engine) != seqno);
 }
 
-static void intel_engine_init_timeline(struct intel_engine_cs *engine)
-{
-	engine->timeline =
-		&engine->i915->gt.execution_timeline.engine[engine->id];
-}
-
 static void intel_engine_init_batch_pool(struct intel_engine_cs *engine)
 {
 	i915_gem_batch_pool_init(&engine->batch_pool, engine);
@@ -508,8 +502,9 @@ static void intel_engine_init_execlist(struct intel_engine_cs *engine)
  */
 void intel_engine_setup_common(struct intel_engine_cs *engine)
 {
+	i915_timeline_init(engine->i915, &engine->timeline, engine->name);
+
 	intel_engine_init_execlist(engine);
-	intel_engine_init_timeline(engine);
 	intel_engine_init_hangcheck(engine);
 	intel_engine_init_batch_pool(engine);
 	intel_engine_init_cmd_parser(engine);
@@ -757,6 +752,8 @@ void intel_engine_cleanup_common(struct intel_engine_cs *engine)
 	if (engine->i915->preempt_context)
 		engine->context_unpin(engine, engine->i915->preempt_context);
 	engine->context_unpin(engine, engine->i915->kernel_context);
+
+	i915_timeline_fini(&engine->timeline);
 }
 
 u64 intel_engine_get_active_head(const struct intel_engine_cs *engine)
@@ -1009,7 +1006,7 @@ bool intel_engine_has_kernel_context(const struct intel_engine_cs *engine)
 	 * the last request that remains in the timeline. When idle, it is
 	 * the last executed context as tracked by retirement.
 	 */
-	rq = __i915_gem_active_peek(&engine->timeline->last_request);
+	rq = __i915_gem_active_peek(&engine->timeline.last_request);
 	if (rq)
 		return rq->ctx == kernel_context;
 	else
@@ -1332,14 +1329,14 @@ void intel_engine_dump(struct intel_engine_cs *engine,
 
 	drm_printf(m, "\tRequests:\n");
 
-	rq = list_first_entry(&engine->timeline->requests,
+	rq = list_first_entry(&engine->timeline.requests,
 			      struct i915_request, link);
-	if (&rq->link != &engine->timeline->requests)
+	if (&rq->link != &engine->timeline.requests)
 		print_request(m, rq, "\t\tfirst  ");
 
-	rq = list_last_entry(&engine->timeline->requests,
+	rq = list_last_entry(&engine->timeline.requests,
 			     struct i915_request, link);
-	if (&rq->link != &engine->timeline->requests)
+	if (&rq->link != &engine->timeline.requests)
 		print_request(m, rq, "\t\tlast   ");
 
 	rq = i915_gem_find_active_request(engine);
@@ -1371,8 +1368,8 @@ void intel_engine_dump(struct intel_engine_cs *engine,
 		drm_printf(m, "\tDevice is asleep; skipping register dump\n");
 	}
 
-	spin_lock_irq(&engine->timeline->lock);
-	list_for_each_entry(rq, &engine->timeline->requests, link)
+	spin_lock_irq(&engine->timeline.lock);
+	list_for_each_entry(rq, &engine->timeline.requests, link)
 		print_request(m, rq, "\t\tE ");
 	drm_printf(m, "\t\tQueue priority: %d\n", execlists->queue_priority);
 	for (rb = execlists->first; rb; rb = rb_next(rb)) {
@@ -1382,7 +1379,7 @@ void intel_engine_dump(struct intel_engine_cs *engine,
 		list_for_each_entry(rq, &p->requests, sched.link)
 			print_request(m, rq, "\t\tQ ");
 	}
-	spin_unlock_irq(&engine->timeline->lock);
+	spin_unlock_irq(&engine->timeline.lock);
 
 	spin_lock_irq(&b->rb_lock);
 	for (rb = rb_first(&b->waiters); rb; rb = rb_next(rb)) {
diff --git a/drivers/gpu/drm/i915/intel_guc_submission.c b/drivers/gpu/drm/i915/intel_guc_submission.c
index 02da05875aa7..cb4fcde1ffdc 100644
--- a/drivers/gpu/drm/i915/intel_guc_submission.c
+++ b/drivers/gpu/drm/i915/intel_guc_submission.c
@@ -677,7 +677,7 @@ static void guc_dequeue(struct intel_engine_cs *engine)
 	bool submit = false;
 	struct rb_node *rb;
 
-	spin_lock_irq(&engine->timeline->lock);
+	spin_lock_irq(&engine->timeline.lock);
 	rb = execlists->first;
 	GEM_BUG_ON(rb_first(&execlists->queue) != rb);
 
@@ -748,7 +748,7 @@ static void guc_dequeue(struct intel_engine_cs *engine)
 	GEM_BUG_ON(execlists->first && !port_isset(execlists->port));
 
 unlock:
-	spin_unlock_irq(&engine->timeline->lock);
+	spin_unlock_irq(&engine->timeline.lock);
 }
 
 static void guc_submission_tasklet(unsigned long data)
diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index fd3539034665..fa802d791804 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -330,10 +330,10 @@ static void __unwind_incomplete_requests(struct intel_engine_cs *engine)
 	struct i915_priolist *uninitialized_var(p);
 	int last_prio = I915_PRIORITY_INVALID;
 
-	lockdep_assert_held(&engine->timeline->lock);
+	lockdep_assert_held(&engine->timeline.lock);
 
 	list_for_each_entry_safe_reverse(rq, rn,
-					 &engine->timeline->requests,
+					 &engine->timeline.requests,
 					 link) {
 		if (i915_request_completed(rq))
 			return;
@@ -357,9 +357,9 @@ execlists_unwind_incomplete_requests(struct intel_engine_execlists *execlists)
 	struct intel_engine_cs *engine =
 		container_of(execlists, typeof(*engine), execlists);
 
-	spin_lock_irq(&engine->timeline->lock);
+	spin_lock_irq(&engine->timeline.lock);
 	__unwind_incomplete_requests(engine);
-	spin_unlock_irq(&engine->timeline->lock);
+	spin_unlock_irq(&engine->timeline.lock);
 }
 
 static inline void
@@ -583,7 +583,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
 	 * and context switches) submission.
 	 */
 
-	spin_lock_irq(&engine->timeline->lock);
+	spin_lock_irq(&engine->timeline.lock);
 	rb = execlists->first;
 	GEM_BUG_ON(rb_first(&execlists->queue) != rb);
 
@@ -743,7 +743,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
 	GEM_BUG_ON(execlists->first && !port_isset(execlists->port));
 
 unlock:
-	spin_unlock_irq(&engine->timeline->lock);
+	spin_unlock_irq(&engine->timeline.lock);
 
 	if (submit) {
 		execlists_user_begin(execlists, execlists->port);
@@ -868,10 +868,10 @@ static void execlists_cancel_requests(struct intel_engine_cs *engine)
 	execlists_cancel_port_requests(execlists);
 	reset_irq(engine);
 
-	spin_lock(&engine->timeline->lock);
+	spin_lock(&engine->timeline.lock);
 
 	/* Mark all executing requests as skipped. */
-	list_for_each_entry(rq, &engine->timeline->requests, link) {
+	list_for_each_entry(rq, &engine->timeline.requests, link) {
 		GEM_BUG_ON(!rq->global_seqno);
 		if (!i915_request_completed(rq))
 			dma_fence_set_error(&rq->fence, -EIO);
@@ -903,7 +903,7 @@ static void execlists_cancel_requests(struct intel_engine_cs *engine)
 	execlists->first = NULL;
 	GEM_BUG_ON(port_isset(execlists->port));
 
-	spin_unlock(&engine->timeline->lock);
+	spin_unlock(&engine->timeline.lock);
 
 	local_irq_restore(flags);
 }
@@ -1141,7 +1141,7 @@ static void execlists_submit_request(struct i915_request *request)
 	unsigned long flags;
 
 	/* Will be called from irq-context when using foreign fences. */
-	spin_lock_irqsave(&engine->timeline->lock, flags);
+	spin_lock_irqsave(&engine->timeline.lock, flags);
 
 	queue_request(engine, &request->sched, rq_prio(request));
 	submit_queue(engine, rq_prio(request));
@@ -1149,7 +1149,7 @@ static void execlists_submit_request(struct i915_request *request)
 	GEM_BUG_ON(!engine->execlists.first);
 	GEM_BUG_ON(list_empty(&request->sched.link));
 
-	spin_unlock_irqrestore(&engine->timeline->lock, flags);
+	spin_unlock_irqrestore(&engine->timeline.lock, flags);
 }
 
 static struct i915_request *sched_to_request(struct i915_sched_node *node)
@@ -1165,8 +1165,8 @@ sched_lock_engine(struct i915_sched_node *node, struct intel_engine_cs *locked)
 	GEM_BUG_ON(!locked);
 
 	if (engine != locked) {
-		spin_unlock(&locked->timeline->lock);
-		spin_lock(&engine->timeline->lock);
+		spin_unlock(&locked->timeline.lock);
+		spin_lock(&engine->timeline.lock);
 	}
 
 	return engine;
@@ -1249,7 +1249,7 @@ static void execlists_schedule(struct i915_request *request,
 	}
 
 	engine = request->engine;
-	spin_lock_irq(&engine->timeline->lock);
+	spin_lock_irq(&engine->timeline.lock);
 
 	/* Fifo and depth-first replacement ensure our deps execute before us */
 	list_for_each_entry_safe_reverse(dep, p, &dfs, dfs_link) {
@@ -1273,7 +1273,7 @@ static void execlists_schedule(struct i915_request *request,
 			__submit_queue(engine, prio);
 	}
 
-	spin_unlock_irq(&engine->timeline->lock);
+	spin_unlock_irq(&engine->timeline.lock);
 }
 
 static int __context_pin(struct i915_gem_context *ctx, struct i915_vma *vma)
@@ -1802,9 +1802,9 @@ static void reset_common_ring(struct intel_engine_cs *engine,
 	reset_irq(engine);
 
 	/* Push back any incomplete requests for replay after the reset. */
-	spin_lock(&engine->timeline->lock);
+	spin_lock(&engine->timeline.lock);
 	__unwind_incomplete_requests(engine);
-	spin_unlock(&engine->timeline->lock);
+	spin_unlock(&engine->timeline.lock);
 
 	local_irq_restore(flags);
 
@@ -2559,6 +2559,7 @@ static int execlists_context_deferred_alloc(struct i915_gem_context *ctx,
 	struct i915_vma *vma;
 	uint32_t context_size;
 	struct intel_ring *ring;
+	struct i915_timeline *timeline;
 	int ret;
 
 	if (ce->state)
@@ -2574,8 +2575,8 @@ static int execlists_context_deferred_alloc(struct i915_gem_context *ctx,
 
 	ctx_obj = i915_gem_object_create(ctx->i915, context_size);
 	if (IS_ERR(ctx_obj)) {
-		DRM_DEBUG_DRIVER("Alloc LRC backing obj failed.\n");
-		return PTR_ERR(ctx_obj);
+		ret = PTR_ERR(ctx_obj);
+		goto error_deref_obj;
 	}
 
 	vma = i915_vma_instance(ctx_obj, &ctx->i915->ggtt.base, NULL);
@@ -2584,7 +2585,14 @@ static int execlists_context_deferred_alloc(struct i915_gem_context *ctx,
 		goto error_deref_obj;
 	}
 
-	ring = intel_engine_create_ring(engine, ctx->timeline, ctx->ring_size);
+	timeline = i915_timeline_create(ctx->i915, ctx->name);
+	if (IS_ERR(timeline)) {
+		ret = PTR_ERR(timeline);
+		goto error_deref_obj;
+	}
+
+	ring = intel_engine_create_ring(engine, timeline, ctx->ring_size);
+	i915_timeline_put(timeline);
 	if (IS_ERR(ring)) {
 		ret = PTR_ERR(ring);
 		goto error_deref_obj;
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index 4559fe1c574e..e85abfafeaf0 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -696,17 +696,17 @@ static void cancel_requests(struct intel_engine_cs *engine)
 	struct i915_request *request;
 	unsigned long flags;
 
-	spin_lock_irqsave(&engine->timeline->lock, flags);
+	spin_lock_irqsave(&engine->timeline.lock, flags);
 
 	/* Mark all submitted requests as skipped. */
-	list_for_each_entry(request, &engine->timeline->requests, link) {
+	list_for_each_entry(request, &engine->timeline.requests, link) {
 		GEM_BUG_ON(!request->global_seqno);
 		if (!i915_request_completed(request))
 			dma_fence_set_error(&request->fence, -EIO);
 	}
 	/* Remaining _unready_ requests will be nop'ed when submitted */
 
-	spin_unlock_irqrestore(&engine->timeline->lock, flags);
+	spin_unlock_irqrestore(&engine->timeline.lock, flags);
 }
 
 static void i9xx_submit_request(struct i915_request *request)
@@ -1118,7 +1118,7 @@ intel_ring_create_vma(struct drm_i915_private *dev_priv, int size)
 
 struct intel_ring *
 intel_engine_create_ring(struct intel_engine_cs *engine,
-			 struct i915_gem_timeline *timeline,
+			 struct i915_timeline *timeline,
 			 int size)
 {
 	struct intel_ring *ring;
@@ -1133,7 +1133,7 @@ intel_engine_create_ring(struct intel_engine_cs *engine,
 		return ERR_PTR(-ENOMEM);
 
 	INIT_LIST_HEAD(&ring->request_list);
-	ring->timeline = &timeline->engine[engine->id];
+	ring->timeline = i915_timeline_get(timeline);
 
 	ring->size = size;
 	/* Workaround an erratum on the i830 which causes a hang if
@@ -1164,6 +1164,7 @@ intel_ring_free(struct intel_ring *ring)
 	i915_vma_close(ring->vma);
 	__i915_gem_object_release_unless_active(obj);
 
+	i915_timeline_put(ring->timeline);
 	kfree(ring);
 }
 
@@ -1322,6 +1323,7 @@ static void intel_ring_context_unpin(struct intel_engine_cs *engine,
 static int intel_init_ring_buffer(struct intel_engine_cs *engine)
 {
 	struct intel_ring *ring;
+	struct i915_timeline *timeline;
 	int err;
 
 	intel_engine_setup_common(engine);
@@ -1330,9 +1332,14 @@ static int intel_init_ring_buffer(struct intel_engine_cs *engine)
 	if (err)
 		goto err;
 
-	ring = intel_engine_create_ring(engine,
-					&engine->i915->gt.legacy_timeline,
-					32 * PAGE_SIZE);
+	timeline = i915_timeline_create(engine->i915, engine->name);
+	if (IS_ERR(timeline)) {
+		err = PTR_ERR(timeline);
+		goto err;
+	}
+
+	ring = intel_engine_create_ring(engine, timeline, 32 * PAGE_SIZE);
+	i915_timeline_put(timeline);
 	if (IS_ERR(ring)) {
 		err = PTR_ERR(ring);
 		goto err;
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index 3f63499734f7..539eefb31cb6 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -5,12 +5,12 @@
 #include <linux/hashtable.h>
 
 #include "i915_gem_batch_pool.h"
-#include "i915_gem_timeline.h"
 
 #include "i915_reg.h"
 #include "i915_pmu.h"
 #include "i915_request.h"
 #include "i915_selftest.h"
+#include "i915_timeline.h"
 #include "intel_gpu_commands.h"
 
 struct drm_printer;
@@ -128,7 +128,7 @@ struct intel_ring {
 	struct i915_vma *vma;
 	void *vaddr;
 
-	struct intel_timeline *timeline;
+	struct i915_timeline *timeline;
 	struct list_head request_list;
 	struct list_head live;
 
@@ -337,7 +337,8 @@ struct intel_engine_cs {
 	u32 mmio_base;
 
 	struct intel_ring *buffer;
-	struct intel_timeline *timeline;
+
+	struct i915_timeline timeline;
 
 	struct drm_i915_gem_object *default_state;
 
@@ -769,7 +770,7 @@ intel_write_status_page(struct intel_engine_cs *engine, int reg, u32 value)
 
 struct intel_ring *
 intel_engine_create_ring(struct intel_engine_cs *engine,
-			 struct i915_gem_timeline *timeline,
+			 struct i915_timeline *timeline,
 			 int size);
 int intel_ring_pin(struct intel_ring *ring,
 		   struct drm_i915_private *i915,
@@ -888,7 +889,7 @@ static inline u32 intel_engine_last_submit(struct intel_engine_cs *engine)
 	 * wtih serialising this hint with anything, so document it as
 	 * a hint and nothing more.
 	 */
-	return READ_ONCE(engine->timeline->seqno);
+	return READ_ONCE(engine->timeline.seqno);
 }
 
 void intel_engine_get_instdone(struct intel_engine_cs *engine,
diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_timeline.c b/drivers/gpu/drm/i915/selftests/i915_timeline.c
similarity index 70%
rename from drivers/gpu/drm/i915/selftests/i915_gem_timeline.c
rename to drivers/gpu/drm/i915/selftests/i915_timeline.c
index 3000e6a7d82d..19f1c6a5c8fb 100644
--- a/drivers/gpu/drm/i915/selftests/i915_gem_timeline.c
+++ b/drivers/gpu/drm/i915/selftests/i915_timeline.c
@@ -1,25 +1,7 @@
 /*
- * Copyright © 2017 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
+ * SPDX-License-Identifier: MIT
  *
+ * Copyright © 2017-2018 Intel Corporation
  */
 
 #include "../i915_selftest.h"
@@ -35,21 +17,21 @@ struct __igt_sync {
 	bool set;
 };
 
-static int __igt_sync(struct intel_timeline *tl,
+static int __igt_sync(struct i915_timeline *tl,
 		      u64 ctx,
 		      const struct __igt_sync *p,
 		      const char *name)
 {
 	int ret;
 
-	if (__intel_timeline_sync_is_later(tl, ctx, p->seqno) != p->expected) {
+	if (__i915_timeline_sync_is_later(tl, ctx, p->seqno) != p->expected) {
 		pr_err("%s: %s(ctx=%llu, seqno=%u) expected passed %s but failed\n",
 		       name, p->name, ctx, p->seqno, yesno(p->expected));
 		return -EINVAL;
 	}
 
 	if (p->set) {
-		ret = __intel_timeline_sync_set(tl, ctx, p->seqno);
+		ret = __i915_timeline_sync_set(tl, ctx, p->seqno);
 		if (ret)
 			return ret;
 	}
@@ -77,37 +59,31 @@ static int igt_sync(void *arg)
 		{ "unwrap", UINT_MAX, true, false },
 		{},
 	}, *p;
-	struct intel_timeline *tl;
+	struct i915_timeline tl;
 	int order, offset;
 	int ret = -ENODEV;
 
-	tl = mock_timeline(0);
-	if (!tl)
-		return -ENOMEM;
-
+	mock_timeline_init(&tl, 0);
 	for (p = pass; p->name; p++) {
 		for (order = 1; order < 64; order++) {
 			for (offset = -1; offset <= (order > 1); offset++) {
 				u64 ctx = BIT_ULL(order) + offset;
 
-				ret = __igt_sync(tl, ctx, p, "1");
+				ret = __igt_sync(&tl, ctx, p, "1");
 				if (ret)
 					goto out;
 			}
 		}
 	}
-	mock_timeline_destroy(tl);
-
-	tl = mock_timeline(0);
-	if (!tl)
-		return -ENOMEM;
+	mock_timeline_fini(&tl);
 
+	mock_timeline_init(&tl, 0);
 	for (order = 1; order < 64; order++) {
 		for (offset = -1; offset <= (order > 1); offset++) {
 			u64 ctx = BIT_ULL(order) + offset;
 
 			for (p = pass; p->name; p++) {
-				ret = __igt_sync(tl, ctx, p, "2");
+				ret = __igt_sync(&tl, ctx, p, "2");
 				if (ret)
 					goto out;
 			}
@@ -115,7 +91,7 @@ static int igt_sync(void *arg)
 	}
 
 out:
-	mock_timeline_destroy(tl);
+	mock_timeline_fini(&tl);
 	return ret;
 }
 
@@ -127,15 +103,13 @@ static unsigned int random_engine(struct rnd_state *rnd)
 static int bench_sync(void *arg)
 {
 	struct rnd_state prng;
-	struct intel_timeline *tl;
+	struct i915_timeline tl;
 	unsigned long end_time, count;
 	u64 prng32_1M;
 	ktime_t kt;
 	int order, last_order;
 
-	tl = mock_timeline(0);
-	if (!tl)
-		return -ENOMEM;
+	mock_timeline_init(&tl, 0);
 
 	/* Lookups from cache are very fast and so the random number generation
 	 * and the loop itself becomes a significant factor in the per-iteration
@@ -167,7 +141,7 @@ static int bench_sync(void *arg)
 	do {
 		u64 id = i915_prandom_u64_state(&prng);
 
-		__intel_timeline_sync_set(tl, id, 0);
+		__i915_timeline_sync_set(&tl, id, 0);
 		count++;
 	} while (!time_after(jiffies, end_time));
 	kt = ktime_sub(ktime_get(), kt);
@@ -182,8 +156,8 @@ static int bench_sync(void *arg)
 	while (end_time--) {
 		u64 id = i915_prandom_u64_state(&prng);
 
-		if (!__intel_timeline_sync_is_later(tl, id, 0)) {
-			mock_timeline_destroy(tl);
+		if (!__i915_timeline_sync_is_later(&tl, id, 0)) {
+			mock_timeline_fini(&tl);
 			pr_err("Lookup of %llu failed\n", id);
 			return -EINVAL;
 		}
@@ -193,19 +167,17 @@ static int bench_sync(void *arg)
 	pr_info("%s: %lu random lookups, %lluns/lookup\n",
 		__func__, count, (long long)div64_ul(ktime_to_ns(kt), count));
 
-	mock_timeline_destroy(tl);
+	mock_timeline_fini(&tl);
 	cond_resched();
 
-	tl = mock_timeline(0);
-	if (!tl)
-		return -ENOMEM;
+	mock_timeline_init(&tl, 0);
 
 	/* Benchmark setting the first N (in order) contexts */
 	count = 0;
 	kt = ktime_get();
 	end_time = jiffies + HZ/10;
 	do {
-		__intel_timeline_sync_set(tl, count++, 0);
+		__i915_timeline_sync_set(&tl, count++, 0);
 	} while (!time_after(jiffies, end_time));
 	kt = ktime_sub(ktime_get(), kt);
 	pr_info("%s: %lu in-order insertions, %lluns/insert\n",
@@ -215,9 +187,9 @@ static int bench_sync(void *arg)
 	end_time = count;
 	kt = ktime_get();
 	while (end_time--) {
-		if (!__intel_timeline_sync_is_later(tl, end_time, 0)) {
+		if (!__i915_timeline_sync_is_later(&tl, end_time, 0)) {
 			pr_err("Lookup of %lu failed\n", end_time);
-			mock_timeline_destroy(tl);
+			mock_timeline_fini(&tl);
 			return -EINVAL;
 		}
 	}
@@ -225,12 +197,10 @@ static int bench_sync(void *arg)
 	pr_info("%s: %lu in-order lookups, %lluns/lookup\n",
 		__func__, count, (long long)div64_ul(ktime_to_ns(kt), count));
 
-	mock_timeline_destroy(tl);
+	mock_timeline_fini(&tl);
 	cond_resched();
 
-	tl = mock_timeline(0);
-	if (!tl)
-		return -ENOMEM;
+	mock_timeline_init(&tl, 0);
 
 	/* Benchmark searching for a random context id and maybe changing it */
 	prandom_seed_state(&prng, i915_selftest.random_seed);
@@ -241,8 +211,8 @@ static int bench_sync(void *arg)
 		u32 id = random_engine(&prng);
 		u32 seqno = prandom_u32_state(&prng);
 
-		if (!__intel_timeline_sync_is_later(tl, id, seqno))
-			__intel_timeline_sync_set(tl, id, seqno);
+		if (!__i915_timeline_sync_is_later(&tl, id, seqno))
+			__i915_timeline_sync_set(&tl, id, seqno);
 
 		count++;
 	} while (!time_after(jiffies, end_time));
@@ -250,7 +220,7 @@ static int bench_sync(void *arg)
 	kt = ktime_sub_ns(kt, (count * prng32_1M * 2) >> 20);
 	pr_info("%s: %lu repeated insert/lookups, %lluns/op\n",
 		__func__, count, (long long)div64_ul(ktime_to_ns(kt), count));
-	mock_timeline_destroy(tl);
+	mock_timeline_fini(&tl);
 	cond_resched();
 
 	/* Benchmark searching for a known context id and changing the seqno */
@@ -258,9 +228,7 @@ static int bench_sync(void *arg)
 	     ({ int tmp = last_order; last_order = order; order += tmp; })) {
 		unsigned int mask = BIT(order) - 1;
 
-		tl = mock_timeline(0);
-		if (!tl)
-			return -ENOMEM;
+		mock_timeline_init(&tl, 0);
 
 		count = 0;
 		kt = ktime_get();
@@ -272,8 +240,8 @@ static int bench_sync(void *arg)
 			 */
 			u64 id = (u64)(count & mask) << order;
 
-			__intel_timeline_sync_is_later(tl, id, 0);
-			__intel_timeline_sync_set(tl, id, 0);
+			__i915_timeline_sync_is_later(&tl, id, 0);
+			__i915_timeline_sync_set(&tl, id, 0);
 
 			count++;
 		} while (!time_after(jiffies, end_time));
@@ -281,7 +249,7 @@ static int bench_sync(void *arg)
 		pr_info("%s: %lu cyclic/%d insert/lookups, %lluns/op\n",
 			__func__, count, order,
 			(long long)div64_ul(ktime_to_ns(kt), count));
-		mock_timeline_destroy(tl);
+		mock_timeline_fini(&tl);
 		cond_resched();
 	}
 
diff --git a/drivers/gpu/drm/i915/selftests/mock_engine.c b/drivers/gpu/drm/i915/selftests/mock_engine.c
index 6a10cb734c35..31cc210d51e9 100644
--- a/drivers/gpu/drm/i915/selftests/mock_engine.c
+++ b/drivers/gpu/drm/i915/selftests/mock_engine.c
@@ -25,6 +25,11 @@
 #include "mock_engine.h"
 #include "mock_request.h"
 
+struct mock_ring {
+	struct intel_ring base;
+	struct i915_timeline timeline;
+};
+
 static struct mock_request *first_request(struct mock_engine *engine)
 {
 	return list_first_entry_or_null(&engine->hw_queue,
@@ -125,7 +130,7 @@ static void mock_submit_request(struct i915_request *request)
 static struct intel_ring *mock_ring(struct intel_engine_cs *engine)
 {
 	const unsigned long sz = PAGE_SIZE / 2;
-	struct intel_ring *ring;
+	struct mock_ring *ring;
 
 	BUILD_BUG_ON(MIN_SPACE_FOR_ADD_REQUEST > sz);
 
@@ -133,18 +138,24 @@ static struct intel_ring *mock_ring(struct intel_engine_cs *engine)
 	if (!ring)
 		return NULL;
 
-	ring->size = sz;
-	ring->effective_size = sz;
-	ring->vaddr = (void *)(ring + 1);
+	i915_timeline_init(engine->i915, &ring->timeline, engine->name);
+
+	ring->base.size = sz;
+	ring->base.effective_size = sz;
+	ring->base.vaddr = (void *)(ring + 1);
+	ring->base.timeline = &ring->timeline;
 
-	INIT_LIST_HEAD(&ring->request_list);
-	intel_ring_update_space(ring);
+	INIT_LIST_HEAD(&ring->base.request_list);
+	intel_ring_update_space(&ring->base);
 
-	return ring;
+	return &ring->base;
 }
 
-static void mock_ring_free(struct intel_ring *ring)
+static void mock_ring_free(struct intel_ring *base)
 {
+	struct mock_ring *ring = container_of(base, typeof(*ring), base);
+
+	i915_timeline_fini(&ring->timeline);
 	kfree(ring);
 }
 
@@ -173,8 +184,7 @@ struct intel_engine_cs *mock_engine(struct drm_i915_private *i915,
 	engine->base.emit_breadcrumb = mock_emit_breadcrumb;
 	engine->base.submit_request = mock_submit_request;
 
-	intel_engine_init_timeline(&engine->base);
-
+	i915_timeline_init(i915, &engine->base.timeline, engine->base.name);
 	intel_engine_init_breadcrumbs(&engine->base);
 	engine->base.breadcrumbs.mock = true; /* prevent touching HW for irqs */
 
@@ -191,6 +201,7 @@ struct intel_engine_cs *mock_engine(struct drm_i915_private *i915,
 
 err_breadcrumbs:
 	intel_engine_fini_breadcrumbs(&engine->base);
+	i915_timeline_fini(&engine->base.timeline);
 	kfree(engine);
 	return NULL;
 }
@@ -229,6 +240,7 @@ void mock_engine_free(struct intel_engine_cs *engine)
 	mock_ring_free(engine->buffer);
 
 	intel_engine_fini_breadcrumbs(engine);
+	i915_timeline_fini(&engine->timeline);
 
 	kfree(engine);
 }
diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_device.c b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
index ed1bf3b2e47f..ab6cd0e16d9b 100644
--- a/drivers/gpu/drm/i915/selftests/mock_gem_device.c
+++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
@@ -73,10 +73,8 @@ static void mock_device_release(struct drm_device *dev)
 
 	mutex_lock(&i915->drm.struct_mutex);
 	mock_fini_ggtt(i915);
-	i915_gem_timeline_fini(&i915->gt.legacy_timeline);
-	i915_gem_timeline_fini(&i915->gt.execution_timeline);
-	WARN_ON(!list_empty(&i915->gt.timelines));
 	mutex_unlock(&i915->drm.struct_mutex);
+	WARN_ON(!list_empty(&i915->gt.timelines));
 
 	destroy_workqueue(i915->wq);
 
@@ -226,15 +224,10 @@ struct drm_i915_private *mock_gem_device(void)
 	if (!i915->priorities)
 		goto err_dependencies;
 
-	mutex_lock(&i915->drm.struct_mutex);
 	INIT_LIST_HEAD(&i915->gt.live_rings);
 	INIT_LIST_HEAD(&i915->gt.timelines);
-	err = i915_gem_timeline_init__global(i915);
-	if (err) {
-		mutex_unlock(&i915->drm.struct_mutex);
-		goto err_priorities;
-	}
 
+	mutex_lock(&i915->drm.struct_mutex);
 	mock_init_ggtt(i915);
 	mutex_unlock(&i915->drm.struct_mutex);
 
diff --git a/drivers/gpu/drm/i915/selftests/mock_timeline.c b/drivers/gpu/drm/i915/selftests/mock_timeline.c
index 47b1f47c5812..dcf3b16f5a07 100644
--- a/drivers/gpu/drm/i915/selftests/mock_timeline.c
+++ b/drivers/gpu/drm/i915/selftests/mock_timeline.c
@@ -1,45 +1,28 @@
 /*
- * Copyright © 2017 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
+ * SPDX-License-Identifier: MIT
  *
+ * Copyright © 2017-2018 Intel Corporation
  */
 
+#include "../i915_timeline.h"
+
 #include "mock_timeline.h"
 
-struct intel_timeline *mock_timeline(u64 context)
+void mock_timeline_init(struct i915_timeline *timeline, u64 context)
 {
-	static struct lock_class_key class;
-	struct intel_timeline *tl;
+	timeline->fence_context = context;
+
+	spin_lock_init(&timeline->lock);
 
-	tl = kzalloc(sizeof(*tl), GFP_KERNEL);
-	if (!tl)
-		return NULL;
+	init_request_active(&timeline->last_request, NULL);
+	INIT_LIST_HEAD(&timeline->requests);
 
-	__intel_timeline_init(tl, NULL, context, &class, "mock");
+	i915_syncmap_init(&timeline->sync);
 
-	return tl;
+	INIT_LIST_HEAD(&timeline->link);
 }
 
-void mock_timeline_destroy(struct intel_timeline *tl)
+void mock_timeline_fini(struct i915_timeline *timeline)
 {
-	__intel_timeline_fini(tl);
-	kfree(tl);
+	i915_timeline_fini(timeline);
 }
diff --git a/drivers/gpu/drm/i915/selftests/mock_timeline.h b/drivers/gpu/drm/i915/selftests/mock_timeline.h
index c27ff4639b8b..b6deaa61110d 100644
--- a/drivers/gpu/drm/i915/selftests/mock_timeline.h
+++ b/drivers/gpu/drm/i915/selftests/mock_timeline.h
@@ -1,33 +1,15 @@
 /*
- * Copyright © 2017 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
+ * SPDX-License-Identifier: MIT
  *
+ * Copyright © 2017-2018 Intel Corporation
  */
 
 #ifndef __MOCK_TIMELINE__
 #define __MOCK_TIMELINE__
 
-#include "../i915_gem_timeline.h"
+struct i915_timeline;
 
-struct intel_timeline *mock_timeline(u64 context);
-void mock_timeline_destroy(struct intel_timeline *tl);
+void mock_timeline_init(struct i915_timeline *timeline, u64 context);
+void mock_timeline_fini(struct i915_timeline *timeline);
 
 #endif /* !__MOCK_TIMELINE__ */
-- 
2.17.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 6/6] drm/i915: Lazily unbind vma on close
  2018-04-23 10:13 [PATCH 1/6] drm/i915: Stop tracking timeline->inflight_seqnos Chris Wilson
                   ` (3 preceding siblings ...)
  2018-04-23 10:13 ` [PATCH 5/6] drm/i915: Split i915_gem_timeline into individual timelines Chris Wilson
@ 2018-04-23 10:14 ` Chris Wilson
  2018-04-23 13:08   ` Tvrtko Ursulin
  2018-04-23 13:24 ` ✗ Fi.CI.CHECKPATCH: warning for series starting with [1/6] drm/i915: Stop tracking timeline->inflight_seqnos Patchwork
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 20+ messages in thread
From: Chris Wilson @ 2018-04-23 10:14 UTC (permalink / raw)
  To: intel-gfx

When userspace is passing around swapbuffers using DRI, we frequently
have to open and close the same object in the foreign address space.
This shows itself as the same object being rebound at roughly 30fps
(with a second object also being rebound at 30fps), which involves us
having to rewrite the page tables and maintain the drm_mm range manager
every time.

However, since the object still exists and it is only the local handle
that disappears, if we are lazy and do not unbind the VMA immediately
when the local user closes the object but defer it until the GPU is
idle, then we can reuse the same VMA binding. We still have to be
careful to mark the handle and lookup tables as closed to maintain the
uABI, just allowing the underlying VMA to be resurrected if the user is
able to access the same object from the same context again.

If the object itself is destroyed (neither userspace keeping a handle to
it), the VMA will be reaped immediately as usual.

In the future, this will be even more useful as instantiating a new VMA
for use on the GPU will become heavier. A nuisance indeed, so nip it in
the bud.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h               |  1 +
 drivers/gpu/drm/i915/i915_gem.c               |  4 +-
 drivers/gpu/drm/i915/i915_gem_execbuffer.c    |  5 +++
 drivers/gpu/drm/i915/i915_gem_gtt.c           | 14 ++++---
 drivers/gpu/drm/i915/i915_vma.c               | 39 ++++++++++++-------
 drivers/gpu/drm/i915/i915_vma.h               |  5 +++
 drivers/gpu/drm/i915/selftests/huge_pages.c   |  2 +-
 .../gpu/drm/i915/selftests/mock_gem_device.c  |  1 +
 8 files changed, 51 insertions(+), 20 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 89cb74c30a00..b2f78da9bc3c 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2060,6 +2060,7 @@ struct drm_i915_private {
 
 		struct list_head timelines;
 		struct list_head live_rings;
+		struct list_head closed_vma;
 		u32 active_requests;
 
 		/**
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index f07556693cfe..4fb7d45b5b5d 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -165,6 +165,7 @@ static u32 __i915_gem_park(struct drm_i915_private *i915)
 	i915_timelines_park(i915);
 
 	i915_pmu_gt_parked(i915);
+	i915_vma_parked(i915);
 
 	i915->gt.awake = false;
 
@@ -4792,7 +4793,7 @@ static void __i915_gem_free_objects(struct drm_i915_private *i915,
 					 &obj->vma_list, obj_link) {
 			GEM_BUG_ON(i915_vma_is_active(vma));
 			vma->flags &= ~I915_VMA_PIN_MASK;
-			i915_vma_close(vma);
+			__i915_vma_final_close(vma);
 		}
 		GEM_BUG_ON(!list_empty(&obj->vma_list));
 		GEM_BUG_ON(!RB_EMPTY_ROOT(&obj->vma_tree));
@@ -5595,6 +5596,7 @@ int i915_gem_init_early(struct drm_i915_private *dev_priv)
 
 	INIT_LIST_HEAD(&dev_priv->gt.live_rings);
 	INIT_LIST_HEAD(&dev_priv->gt.timelines);
+	INIT_LIST_HEAD(&dev_priv->gt.closed_vma);
 
 	i915_gem_init__mm(dev_priv);
 
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index c74f5df3fb5a..e5b8371e30de 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -768,6 +768,11 @@ static int eb_lookup_vmas(struct i915_execbuffer *eb)
 		lut->ctx = eb->ctx;
 		lut->handle = handle;
 
+		if (vma->flags & I915_VMA_CLOSED) {
+			vma->flags &= ~I915_VMA_CLOSED;
+			list_del(&vma->closed_link);
+		}
+
 add_vma:
 		err = eb_add_vma(eb, i, vma);
 		if (unlikely(err))
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index e9d828324f67..c1587d83fd19 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -2218,6 +2218,12 @@ i915_ppgtt_create(struct drm_i915_private *dev_priv,
 }
 
 void i915_ppgtt_close(struct i915_address_space *vm)
+{
+	GEM_BUG_ON(vm->closed);
+	vm->closed = true;
+}
+
+static void ppgtt_close_vma(struct i915_address_space *vm)
 {
 	struct list_head *phases[] = {
 		&vm->active_list,
@@ -2226,15 +2232,12 @@ void i915_ppgtt_close(struct i915_address_space *vm)
 		NULL,
 	}, **phase;
 
-	GEM_BUG_ON(vm->closed);
 	vm->closed = true;
-
 	for (phase = phases; *phase; phase++) {
 		struct i915_vma *vma, *vn;
 
 		list_for_each_entry_safe(vma, vn, *phase, vm_link)
-			if (!i915_vma_is_closed(vma))
-				i915_vma_close(vma);
+			__i915_vma_final_close(vma);
 	}
 }
 
@@ -2245,7 +2248,8 @@ void i915_ppgtt_release(struct kref *kref)
 
 	trace_i915_ppgtt_release(&ppgtt->base);
 
-	/* vmas should already be unbound and destroyed */
+	ppgtt_close_vma(&ppgtt->base);
+
 	GEM_BUG_ON(!list_empty(&ppgtt->base.active_list));
 	GEM_BUG_ON(!list_empty(&ppgtt->base.inactive_list));
 	GEM_BUG_ON(!list_empty(&ppgtt->base.unbound_list));
diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c
index 4bda3bd29bf5..5744f4409f09 100644
--- a/drivers/gpu/drm/i915/i915_vma.c
+++ b/drivers/gpu/drm/i915/i915_vma.c
@@ -46,8 +46,6 @@ i915_vma_retire(struct i915_gem_active *active, struct i915_request *rq)
 
 	GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
 	list_move_tail(&vma->vm_link, &vma->vm->inactive_list);
-	if (unlikely(i915_vma_is_closed(vma) && !i915_vma_is_pinned(vma)))
-		WARN_ON(i915_vma_unbind(vma));
 
 	GEM_BUG_ON(!i915_gem_object_is_active(obj));
 	if (--obj->active_count)
@@ -232,7 +230,6 @@ i915_vma_instance(struct drm_i915_gem_object *obj,
 	if (!vma)
 		vma = vma_create(obj, vm, view);
 
-	GEM_BUG_ON(!IS_ERR(vma) && i915_vma_is_closed(vma));
 	GEM_BUG_ON(!IS_ERR(vma) && i915_vma_compare(vma, vm, view));
 	GEM_BUG_ON(!IS_ERR(vma) && vma_lookup(obj, vm, view) != vma);
 	return vma;
@@ -689,8 +686,6 @@ static void i915_vma_destroy(struct i915_vma *vma)
 	int i;
 
 	GEM_BUG_ON(vma->node.allocated);
-	GEM_BUG_ON(i915_vma_is_active(vma));
-	GEM_BUG_ON(!i915_vma_is_closed(vma));
 	GEM_BUG_ON(vma->fence);
 
 	for (i = 0; i < ARRAY_SIZE(vma->last_read); i++)
@@ -699,6 +694,7 @@ static void i915_vma_destroy(struct i915_vma *vma)
 
 	list_del(&vma->obj_link);
 	list_del(&vma->vm_link);
+	rb_erase(&vma->obj_node, &vma->obj->vma_tree);
 
 	if (!i915_vma_is_ggtt(vma))
 		i915_ppgtt_put(i915_vm_to_ppgtt(vma->vm));
@@ -708,13 +704,34 @@ static void i915_vma_destroy(struct i915_vma *vma)
 
 void i915_vma_close(struct i915_vma *vma)
 {
+	lockdep_assert_held(&vma->vm->i915->drm.struct_mutex);
+
 	GEM_BUG_ON(i915_vma_is_closed(vma));
 	vma->flags |= I915_VMA_CLOSED;
 
-	rb_erase(&vma->obj_node, &vma->obj->vma_tree);
+	list_add_tail(&vma->closed_link, &vma->vm->i915->gt.closed_vma);
+}
 
-	if (!i915_vma_is_active(vma) && !i915_vma_is_pinned(vma))
-		WARN_ON(i915_vma_unbind(vma));
+void __i915_vma_final_close(struct i915_vma *vma)
+{
+	lockdep_assert_held(&vma->vm->i915->drm.struct_mutex);
+
+	GEM_BUG_ON(i915_vma_is_active(vma));
+	GEM_BUG_ON(i915_vma_is_pinned(vma));
+
+	if (i915_vma_is_closed(vma))
+		list_del(&vma->closed_link);
+
+	WARN_ON(i915_vma_unbind(vma));
+	i915_vma_destroy(vma);
+}
+
+void i915_vma_parked(struct drm_i915_private *i915)
+{
+	struct i915_vma *vma, *next;
+
+	list_for_each_entry_safe(vma, next, &i915->gt.closed_vma, closed_link)
+		__i915_vma_final_close(vma);
 }
 
 static void __i915_vma_iounmap(struct i915_vma *vma)
@@ -804,7 +821,7 @@ int i915_vma_unbind(struct i915_vma *vma)
 		return -EBUSY;
 
 	if (!drm_mm_node_allocated(&vma->node))
-		goto destroy;
+		return 0;
 
 	GEM_BUG_ON(obj->bind_count == 0);
 	GEM_BUG_ON(!i915_gem_object_has_pinned_pages(obj));
@@ -841,10 +858,6 @@ int i915_vma_unbind(struct i915_vma *vma)
 
 	i915_vma_remove(vma);
 
-destroy:
-	if (unlikely(i915_vma_is_closed(vma)))
-		i915_vma_destroy(vma);
-
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/i915/i915_vma.h b/drivers/gpu/drm/i915/i915_vma.h
index 8c5022095418..0a9790555d84 100644
--- a/drivers/gpu/drm/i915/i915_vma.h
+++ b/drivers/gpu/drm/i915/i915_vma.h
@@ -119,6 +119,8 @@ struct i915_vma {
 	/** This vma's place in the eviction list */
 	struct list_head evict_link;
 
+	struct list_head closed_link;
+
 	/**
 	 * Used for performing relocations during execbuffer insertion.
 	 */
@@ -285,6 +287,7 @@ void i915_vma_revoke_mmap(struct i915_vma *vma);
 int __must_check i915_vma_unbind(struct i915_vma *vma);
 void i915_vma_unlink_ctx(struct i915_vma *vma);
 void i915_vma_close(struct i915_vma *vma);
+void __i915_vma_final_close(struct i915_vma *vma);
 
 int __i915_vma_do_pin(struct i915_vma *vma,
 		      u64 size, u64 alignment, u64 flags);
@@ -408,6 +411,8 @@ i915_vma_unpin_fence(struct i915_vma *vma)
 		__i915_vma_unpin_fence(vma);
 }
 
+void i915_vma_parked(struct drm_i915_private *i915);
+
 #define for_each_until(cond) if (cond) break; else
 
 /**
diff --git a/drivers/gpu/drm/i915/selftests/huge_pages.c b/drivers/gpu/drm/i915/selftests/huge_pages.c
index 05bbef363fff..8fb0b9f434c9 100644
--- a/drivers/gpu/drm/i915/selftests/huge_pages.c
+++ b/drivers/gpu/drm/i915/selftests/huge_pages.c
@@ -1091,7 +1091,7 @@ static int __igt_write_huge(struct i915_gem_context *ctx,
 out_vma_unpin:
 	i915_vma_unpin(vma);
 out_vma_close:
-	i915_vma_close(vma);
+	__i915_vma_final_close(vma);
 
 	return err;
 }
diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_device.c b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
index ab6cd0e16d9b..c50d9fe76465 100644
--- a/drivers/gpu/drm/i915/selftests/mock_gem_device.c
+++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
@@ -226,6 +226,7 @@ struct drm_i915_private *mock_gem_device(void)
 
 	INIT_LIST_HEAD(&i915->gt.live_rings);
 	INIT_LIST_HEAD(&i915->gt.timelines);
+	INIT_LIST_HEAD(&i915->gt.closed_vma);
 
 	mutex_lock(&i915->drm.struct_mutex);
 	mock_init_ggtt(i915);
-- 
2.17.0

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [PATCH 2/6] drm/i915: Retire requests along rings
  2018-04-23 10:13 ` [PATCH 2/6] drm/i915: Retire requests along rings Chris Wilson
@ 2018-04-23 10:18   ` Tvrtko Ursulin
  0 siblings, 0 replies; 20+ messages in thread
From: Tvrtko Ursulin @ 2018-04-23 10:18 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx


On 23/04/2018 11:13, Chris Wilson wrote:
> In the next patch, rings are the central timeline as requests may jump
> between engines. Therefore in the future as we retire in order along the
> engine timeline, we may retire out-of-order within a ring (as the ring now
> occurs along multiple engines), leading to much hilarity in miscomputing
> the position of ring->head.
> 
> As an added bonus, retiring along the ring reduces the penalty of having
> one execlists client do cleanup for another (old legacy submission
> shares a ring between all clients). The downside is that slow and
> irregular (off the critical path) process of cleaning up stale requests
> after userspace becomes a modicum less efficient.
> 
> In the long run, it will become apparent that the ordered
> ring->request_list matches the ring->timeline, a fun challenge for the
> future will be unifying the two lists to avoid duplication!
> 
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> ---
>   drivers/gpu/drm/i915/i915_drv.h               |  3 +-
>   drivers/gpu/drm/i915/i915_gem.c               |  1 +
>   drivers/gpu/drm/i915/i915_request.c           | 43 ++++++++-----------
>   drivers/gpu/drm/i915/intel_ringbuffer.c       |  5 +++
>   drivers/gpu/drm/i915/intel_ringbuffer.h       |  1 +
>   drivers/gpu/drm/i915/selftests/mock_engine.c  | 27 +++++++++---
>   .../gpu/drm/i915/selftests/mock_gem_device.c  |  2 +
>   7 files changed, 50 insertions(+), 32 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 8444ca8d5aa3..73936be90aed 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -2058,8 +2058,9 @@ struct drm_i915_private {
>   		void (*resume)(struct drm_i915_private *);
>   		void (*cleanup_engine)(struct intel_engine_cs *engine);
>   
> -		struct list_head timelines;
>   		struct i915_gem_timeline global_timeline;
> +		struct list_head timelines;
> +		struct list_head rings;
>   		u32 active_requests;
>   
>   		/**
> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> index 795ca83aed7a..906e2395c245 100644
> --- a/drivers/gpu/drm/i915/i915_gem.c
> +++ b/drivers/gpu/drm/i915/i915_gem.c
> @@ -5600,6 +5600,7 @@ int i915_gem_init_early(struct drm_i915_private *dev_priv)
>   		goto err_dependencies;
>   
>   	mutex_lock(&dev_priv->drm.struct_mutex);
> +	INIT_LIST_HEAD(&dev_priv->gt.rings);
>   	INIT_LIST_HEAD(&dev_priv->gt.timelines);
>   	err = i915_gem_timeline_init__global(dev_priv);
>   	mutex_unlock(&dev_priv->drm.struct_mutex);
> diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c
> index 1437538d5bfa..0bf949ec9f1a 100644
> --- a/drivers/gpu/drm/i915/i915_request.c
> +++ b/drivers/gpu/drm/i915/i915_request.c
> @@ -292,6 +292,7 @@ void i915_gem_retire_noop(struct i915_gem_active *active,
>   
>   static void advance_ring(struct i915_request *request)
>   {
> +	struct intel_ring *ring = request->ring;
>   	unsigned int tail;
>   
>   	/*
> @@ -303,7 +304,9 @@ static void advance_ring(struct i915_request *request)
>   	 * Note this requires that we are always called in request
>   	 * completion order.
>   	 */
> -	if (list_is_last(&request->ring_link, &request->ring->request_list)) {
> +	GEM_BUG_ON(request != list_first_entry(&ring->request_list,
> +					       typeof(*request), ring_link));
> +	if (list_is_last(&request->ring_link, &ring->request_list)) {
>   		/*
>   		 * We may race here with execlists resubmitting this request
>   		 * as we retire it. The resubmission will move the ring->tail
> @@ -318,7 +321,7 @@ static void advance_ring(struct i915_request *request)
>   	}
>   	list_del(&request->ring_link);
>   
> -	request->ring->head = tail;
> +	ring->head = tail;
>   }
>   
>   static void free_capture_list(struct i915_request *request)
> @@ -424,18 +427,18 @@ static void i915_request_retire(struct i915_request *request)
>   
>   void i915_request_retire_upto(struct i915_request *rq)
>   {
> -	struct intel_engine_cs *engine = rq->engine;
> +	struct intel_ring *ring = rq->ring;
>   	struct i915_request *tmp;
>   
>   	lockdep_assert_held(&rq->i915->drm.struct_mutex);
>   	GEM_BUG_ON(!i915_request_completed(rq));
>   
> -	if (list_empty(&rq->link))
> +	if (list_empty(&rq->ring_link))
>   		return;
>   
>   	do {
> -		tmp = list_first_entry(&engine->timeline->requests,
> -				       typeof(*tmp), link);
> +		tmp = list_first_entry(&ring->request_list,
> +				       typeof(*tmp), ring_link);
>   
>   		i915_request_retire(tmp);
>   	} while (tmp != rq);
> @@ -644,9 +647,9 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx)
>   	if (ret)
>   		goto err_unreserve;
>   
> -	/* Move the oldest request to the slab-cache (if not in use!) */
> -	rq = list_first_entry_or_null(&engine->timeline->requests,
> -				      typeof(*rq), link);
> +	/* Move our oldest request to the slab-cache (if not in use!) */
> +	rq = list_first_entry_or_null(&ring->request_list,
> +				      typeof(*rq), ring_link);
>   	if (rq && i915_request_completed(rq))
>   		i915_request_retire(rq);
>   
> @@ -1350,38 +1353,30 @@ long i915_request_wait(struct i915_request *rq,
>   	return timeout;
>   }
>   
> -static void engine_retire_requests(struct intel_engine_cs *engine)
> +static void ring_retire_requests(struct intel_ring *ring)
>   {
>   	struct i915_request *request, *next;
> -	u32 seqno = intel_engine_get_seqno(engine);
> -	LIST_HEAD(retire);
>   
> -	spin_lock_irq(&engine->timeline->lock);
>   	list_for_each_entry_safe(request, next,
> -				 &engine->timeline->requests, link) {
> -		if (!i915_seqno_passed(seqno, request->global_seqno))
> +				 &ring->request_list, ring_link) {
> +		if (!i915_request_completed(request))
>   			break;
>   
> -		list_move_tail(&request->link, &retire);
> -	}
> -	spin_unlock_irq(&engine->timeline->lock);
> -
> -	list_for_each_entry_safe(request, next, &retire, link)
>   		i915_request_retire(request);
> +	}
>   }
>   
>   void i915_retire_requests(struct drm_i915_private *i915)
>   {
> -	struct intel_engine_cs *engine;
> -	enum intel_engine_id id;
> +	struct intel_ring *ring, *next;
>   
>   	lockdep_assert_held(&i915->drm.struct_mutex);
>   
>   	if (!i915->gt.active_requests)
>   		return;
>   
> -	for_each_engine(engine, i915, id)
> -		engine_retire_requests(engine);
> +	list_for_each_entry_safe(ring, next, &i915->gt.rings, link)
> +		ring_retire_requests(ring);
>   }
>   
>   #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
> index c68ac605b8a9..792a2ca95872 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.c
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
> @@ -1124,6 +1124,7 @@ intel_engine_create_ring(struct intel_engine_cs *engine, int size)
>   
>   	GEM_BUG_ON(!is_power_of_2(size));
>   	GEM_BUG_ON(RING_CTL_SIZE(size) & ~RING_NR_PAGES);
> +	lockdep_assert_held(&engine->i915->drm.struct_mutex);
>   
>   	ring = kzalloc(sizeof(*ring), GFP_KERNEL);
>   	if (!ring)
> @@ -1149,6 +1150,8 @@ intel_engine_create_ring(struct intel_engine_cs *engine, int size)
>   	}
>   	ring->vma = vma;
>   
> +	list_add(&ring->link, &engine->i915->gt.rings);
> +
>   	return ring;
>   }
>   
> @@ -1160,6 +1163,8 @@ intel_ring_free(struct intel_ring *ring)
>   	i915_vma_close(ring->vma);
>   	__i915_gem_object_release_unless_active(obj);
>   
> +	list_del(&ring->link);
> +
>   	kfree(ring);
>   }
>   
> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
> index c5e27905b0e1..d816f8dea245 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.h
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
> @@ -129,6 +129,7 @@ struct intel_ring {
>   	void *vaddr;
>   
>   	struct list_head request_list;
> +	struct list_head link;
>   
>   	u32 head;
>   	u32 tail;
> diff --git a/drivers/gpu/drm/i915/selftests/mock_engine.c b/drivers/gpu/drm/i915/selftests/mock_engine.c
> index 78a89efa1119..a0bc324edadd 100644
> --- a/drivers/gpu/drm/i915/selftests/mock_engine.c
> +++ b/drivers/gpu/drm/i915/selftests/mock_engine.c
> @@ -140,9 +140,18 @@ static struct intel_ring *mock_ring(struct intel_engine_cs *engine)
>   	INIT_LIST_HEAD(&ring->request_list);
>   	intel_ring_update_space(ring);
>   
> +	list_add(&ring->link, &engine->i915->gt.rings);
> +
>   	return ring;
>   }
>   
> +static void mock_ring_free(struct intel_ring *ring)
> +{
> +	list_del(&ring->link);
> +
> +	kfree(ring);
> +}
> +
>   struct intel_engine_cs *mock_engine(struct drm_i915_private *i915,
>   				    const char *name,
>   				    int id)
> @@ -155,12 +164,6 @@ struct intel_engine_cs *mock_engine(struct drm_i915_private *i915,
>   	if (!engine)
>   		return NULL;
>   
> -	engine->base.buffer = mock_ring(&engine->base);
> -	if (!engine->base.buffer) {
> -		kfree(engine);
> -		return NULL;
> -	}
> -
>   	/* minimal engine setup for requests */
>   	engine->base.i915 = i915;
>   	snprintf(engine->base.name, sizeof(engine->base.name), "%s", name);
> @@ -185,7 +188,16 @@ struct intel_engine_cs *mock_engine(struct drm_i915_private *i915,
>   	timer_setup(&engine->hw_delay, hw_delay_complete, 0);
>   	INIT_LIST_HEAD(&engine->hw_queue);
>   
> +	engine->base.buffer = mock_ring(&engine->base);
> +	if (!engine->base.buffer)
> +		goto err_breadcrumbs;
> +
>   	return &engine->base;
> +
> +err_breadcrumbs:
> +	intel_engine_fini_breadcrumbs(&engine->base);
> +	kfree(engine);
> +	return NULL;
>   }
>   
>   void mock_engine_flush(struct intel_engine_cs *engine)
> @@ -219,8 +231,9 @@ void mock_engine_free(struct intel_engine_cs *engine)
>   	if (engine->last_retired_context)
>   		engine->context_unpin(engine, engine->last_retired_context);
>   
> +	mock_ring_free(engine->buffer);
> +
>   	intel_engine_fini_breadcrumbs(engine);
>   
> -	kfree(engine->buffer);
>   	kfree(engine);
>   }
> diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_device.c b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
> index e6d4b882599a..ac4bacf8b5b9 100644
> --- a/drivers/gpu/drm/i915/selftests/mock_gem_device.c
> +++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
> @@ -44,6 +44,7 @@ void mock_device_flush(struct drm_i915_private *i915)
>   		mock_engine_flush(engine);
>   
>   	i915_retire_requests(i915);
> +	GEM_BUG_ON(i915->gt.active_requests);
>   }
>   
>   static void mock_device_release(struct drm_device *dev)
> @@ -224,6 +225,7 @@ struct drm_i915_private *mock_gem_device(void)
>   		goto err_dependencies;
>   
>   	mutex_lock(&i915->drm.struct_mutex);
> +	INIT_LIST_HEAD(&i915->gt.rings);
>   	INIT_LIST_HEAD(&i915->gt.timelines);
>   	err = i915_gem_timeline_init__global(i915);
>   	if (err) {
> 

Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>

Regards,

Tvrtko
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 3/6] drm/i915: Only track live rings for retiring
  2018-04-23 10:13 ` [PATCH 3/6] drm/i915: Only track live rings for retiring Chris Wilson
@ 2018-04-23 10:25   ` Tvrtko Ursulin
  2018-04-23 10:36     ` Chris Wilson
  0 siblings, 1 reply; 20+ messages in thread
From: Tvrtko Ursulin @ 2018-04-23 10:25 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx


On 23/04/2018 11:13, Chris Wilson wrote:
> We don't need to track every ring for its lifetime as they are managed
> by the contexts/engines. What we do want to track are the live rings so
> that we can sporadically clean up requests if userspace falls behind. We
> can simply restrict the gt->rings list to being only gt->live_rings.
> 
> Suggested-by: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
> ---
>   drivers/gpu/drm/i915/i915_drv.h                  | 2 +-
>   drivers/gpu/drm/i915/i915_gem.c                  | 3 ++-
>   drivers/gpu/drm/i915/i915_request.c              | 6 +++++-
>   drivers/gpu/drm/i915/i915_utils.h                | 6 ++++++
>   drivers/gpu/drm/i915/intel_ringbuffer.c          | 4 ----
>   drivers/gpu/drm/i915/intel_ringbuffer.h          | 2 +-
>   drivers/gpu/drm/i915/selftests/mock_engine.c     | 4 ----
>   drivers/gpu/drm/i915/selftests/mock_gem_device.c | 2 +-
>   8 files changed, 16 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 73936be90aed..a7787c2cb53c 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -2060,7 +2060,7 @@ struct drm_i915_private {
>   
>   		struct i915_gem_timeline global_timeline;
>   		struct list_head timelines;
> -		struct list_head rings;
> +		struct list_head live_rings;
>   		u32 active_requests;
>   
>   		/**
> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> index 906e2395c245..0097a77fae8d 100644
> --- a/drivers/gpu/drm/i915/i915_gem.c
> +++ b/drivers/gpu/drm/i915/i915_gem.c
> @@ -141,6 +141,7 @@ static u32 __i915_gem_park(struct drm_i915_private *i915)
>   {
>   	lockdep_assert_held(&i915->drm.struct_mutex);
>   	GEM_BUG_ON(i915->gt.active_requests);
> +	GEM_BUG_ON(!list_empty(&i915->gt.live_rings));
>   
>   	if (!i915->gt.awake)
>   		return I915_EPOCH_INVALID;
> @@ -5600,7 +5601,7 @@ int i915_gem_init_early(struct drm_i915_private *dev_priv)
>   		goto err_dependencies;
>   
>   	mutex_lock(&dev_priv->drm.struct_mutex);
> -	INIT_LIST_HEAD(&dev_priv->gt.rings);
> +	INIT_LIST_HEAD(&dev_priv->gt.live_rings);
>   	INIT_LIST_HEAD(&dev_priv->gt.timelines);
>   	err = i915_gem_timeline_init__global(dev_priv);
>   	mutex_unlock(&dev_priv->drm.struct_mutex);
> diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c
> index 0bf949ec9f1a..534b8d684cef 100644
> --- a/drivers/gpu/drm/i915/i915_request.c
> +++ b/drivers/gpu/drm/i915/i915_request.c
> @@ -316,6 +316,7 @@ static void advance_ring(struct i915_request *request)
>   		 * noops - they are safe to be replayed on a reset.
>   		 */
>   		tail = READ_ONCE(request->tail);
> +		list_del(&ring->live);
>   	} else {
>   		tail = request->postfix;
>   	}
> @@ -1046,6 +1047,8 @@ void __i915_request_add(struct i915_request *request, bool flush_caches)
>   	i915_gem_active_set(&timeline->last_request, request);
>   
>   	list_add_tail(&request->ring_link, &ring->request_list);
> +	if (list_is_first(&request->ring_link, &ring->request_list))
> +		list_add(&ring->live, &request->i915->gt.live_rings);

If you re-order the two list adds you could use list_empty and wouldn't 
have to add list_is_first.

>   	request->emitted_jiffies = jiffies;
>   
>   	/*
> @@ -1375,7 +1378,8 @@ void i915_retire_requests(struct drm_i915_private *i915)
>   	if (!i915->gt.active_requests)
>   		return;
>   
> -	list_for_each_entry_safe(ring, next, &i915->gt.rings, link)
> +	GEM_BUG_ON(list_empty(&i915->gt.live_rings));

Maybe blank line here since the assert is not logically associated with 
the list but with the !i915.active_requests?

> +	list_for_each_entry_safe(ring, next, &i915->gt.live_rings, live)
>   		ring_retire_requests(ring);
>   }
>   
> diff --git a/drivers/gpu/drm/i915/i915_utils.h b/drivers/gpu/drm/i915/i915_utils.h
> index 0695717522ea..00165ad55fb3 100644
> --- a/drivers/gpu/drm/i915/i915_utils.h
> +++ b/drivers/gpu/drm/i915/i915_utils.h
> @@ -120,6 +120,12 @@ static inline u64 ptr_to_u64(const void *ptr)
>   
>   #include <linux/list.h>
>   
> +static inline int list_is_first(const struct list_head *list,
> +				const struct list_head *head)

Return bool if you decide you prefer to keep list_is_first?

> +{
> +	return head->next == list;
> +}
> +
>   static inline void __list_del_many(struct list_head *head,
>   				   struct list_head *first)
>   {
> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
> index 792a2ca95872..3453e7426f6b 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.c
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
> @@ -1150,8 +1150,6 @@ intel_engine_create_ring(struct intel_engine_cs *engine, int size)
>   	}
>   	ring->vma = vma;
>   
> -	list_add(&ring->link, &engine->i915->gt.rings);
> -
>   	return ring;
>   }
>   
> @@ -1163,8 +1161,6 @@ intel_ring_free(struct intel_ring *ring)
>   	i915_vma_close(ring->vma);
>   	__i915_gem_object_release_unless_active(obj);
>   
> -	list_del(&ring->link);
> -
>   	kfree(ring);
>   }
>   
> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
> index d816f8dea245..fd5a6363ab1d 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.h
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
> @@ -129,7 +129,7 @@ struct intel_ring {
>   	void *vaddr;
>   
>   	struct list_head request_list;
> -	struct list_head link;
> +	struct list_head live;

live_link?

>   
>   	u32 head;
>   	u32 tail;
> diff --git a/drivers/gpu/drm/i915/selftests/mock_engine.c b/drivers/gpu/drm/i915/selftests/mock_engine.c
> index a0bc324edadd..74a88913623f 100644
> --- a/drivers/gpu/drm/i915/selftests/mock_engine.c
> +++ b/drivers/gpu/drm/i915/selftests/mock_engine.c
> @@ -140,15 +140,11 @@ static struct intel_ring *mock_ring(struct intel_engine_cs *engine)
>   	INIT_LIST_HEAD(&ring->request_list);
>   	intel_ring_update_space(ring);
>   
> -	list_add(&ring->link, &engine->i915->gt.rings);
> -
>   	return ring;
>   }
>   
>   static void mock_ring_free(struct intel_ring *ring)
>   {
> -	list_del(&ring->link);
> -
>   	kfree(ring);
>   }
>   
> diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_device.c b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
> index ac4bacf8b5b9..9335b09d8b04 100644
> --- a/drivers/gpu/drm/i915/selftests/mock_gem_device.c
> +++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
> @@ -225,7 +225,7 @@ struct drm_i915_private *mock_gem_device(void)
>   		goto err_dependencies;
>   
>   	mutex_lock(&i915->drm.struct_mutex);
> -	INIT_LIST_HEAD(&i915->gt.rings);
> +	INIT_LIST_HEAD(&i915->gt.live_rings);
>   	INIT_LIST_HEAD(&i915->gt.timelines);
>   	err = i915_gem_timeline_init__global(i915);
>   	if (err) {
> 

Regards,

Tvrtko
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 3/6] drm/i915: Only track live rings for retiring
  2018-04-23 10:25   ` Tvrtko Ursulin
@ 2018-04-23 10:36     ` Chris Wilson
  2018-04-23 10:50       ` Tvrtko Ursulin
  0 siblings, 1 reply; 20+ messages in thread
From: Chris Wilson @ 2018-04-23 10:36 UTC (permalink / raw)
  To: Tvrtko Ursulin, intel-gfx

Quoting Tvrtko Ursulin (2018-04-23 11:25:54)
> 
> On 23/04/2018 11:13, Chris Wilson wrote:
> > We don't need to track every ring for its lifetime as they are managed
> > by the contexts/engines. What we do want to track are the live rings so
> > that we can sporadically clean up requests if userspace falls behind. We
> > can simply restrict the gt->rings list to being only gt->live_rings.
> > 
> > Suggested-by: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
> > Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> > Cc: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
> > ---
> >   drivers/gpu/drm/i915/i915_drv.h                  | 2 +-
> >   drivers/gpu/drm/i915/i915_gem.c                  | 3 ++-
> >   drivers/gpu/drm/i915/i915_request.c              | 6 +++++-
> >   drivers/gpu/drm/i915/i915_utils.h                | 6 ++++++
> >   drivers/gpu/drm/i915/intel_ringbuffer.c          | 4 ----
> >   drivers/gpu/drm/i915/intel_ringbuffer.h          | 2 +-
> >   drivers/gpu/drm/i915/selftests/mock_engine.c     | 4 ----
> >   drivers/gpu/drm/i915/selftests/mock_gem_device.c | 2 +-
> >   8 files changed, 16 insertions(+), 13 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> > index 73936be90aed..a7787c2cb53c 100644
> > --- a/drivers/gpu/drm/i915/i915_drv.h
> > +++ b/drivers/gpu/drm/i915/i915_drv.h
> > @@ -2060,7 +2060,7 @@ struct drm_i915_private {
> >   
> >               struct i915_gem_timeline global_timeline;
> >               struct list_head timelines;
> > -             struct list_head rings;
> > +             struct list_head live_rings;
> >               u32 active_requests;
> >   
> >               /**
> > diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> > index 906e2395c245..0097a77fae8d 100644
> > --- a/drivers/gpu/drm/i915/i915_gem.c
> > +++ b/drivers/gpu/drm/i915/i915_gem.c
> > @@ -141,6 +141,7 @@ static u32 __i915_gem_park(struct drm_i915_private *i915)
> >   {
> >       lockdep_assert_held(&i915->drm.struct_mutex);
> >       GEM_BUG_ON(i915->gt.active_requests);
> > +     GEM_BUG_ON(!list_empty(&i915->gt.live_rings));
> >   
> >       if (!i915->gt.awake)
> >               return I915_EPOCH_INVALID;
> > @@ -5600,7 +5601,7 @@ int i915_gem_init_early(struct drm_i915_private *dev_priv)
> >               goto err_dependencies;
> >   
> >       mutex_lock(&dev_priv->drm.struct_mutex);
> > -     INIT_LIST_HEAD(&dev_priv->gt.rings);
> > +     INIT_LIST_HEAD(&dev_priv->gt.live_rings);
> >       INIT_LIST_HEAD(&dev_priv->gt.timelines);
> >       err = i915_gem_timeline_init__global(dev_priv);
> >       mutex_unlock(&dev_priv->drm.struct_mutex);
> > diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c
> > index 0bf949ec9f1a..534b8d684cef 100644
> > --- a/drivers/gpu/drm/i915/i915_request.c
> > +++ b/drivers/gpu/drm/i915/i915_request.c
> > @@ -316,6 +316,7 @@ static void advance_ring(struct i915_request *request)
> >                * noops - they are safe to be replayed on a reset.
> >                */
> >               tail = READ_ONCE(request->tail);
> > +             list_del(&ring->live);
> >       } else {
> >               tail = request->postfix;
> >       }
> > @@ -1046,6 +1047,8 @@ void __i915_request_add(struct i915_request *request, bool flush_caches)
> >       i915_gem_active_set(&timeline->last_request, request);
> >   
> >       list_add_tail(&request->ring_link, &ring->request_list);
> > +     if (list_is_first(&request->ring_link, &ring->request_list))
> > +             list_add(&ring->live, &request->i915->gt.live_rings);
> 
> If you re-order the two list adds you could use list_empty and wouldn't 
> have to add list_is_first.

list_is_first tallies nicely with the list_is_last used before the
corresponding list_del.

> 
> >       request->emitted_jiffies = jiffies;
> >   
> >       /*
> > @@ -1375,7 +1378,8 @@ void i915_retire_requests(struct drm_i915_private *i915)
> >       if (!i915->gt.active_requests)
> >               return;
> >   
> > -     list_for_each_entry_safe(ring, next, &i915->gt.rings, link)
> > +     GEM_BUG_ON(list_empty(&i915->gt.live_rings));
> 
> Maybe blank line here since the assert is not logically associated with 
> the list but with the !i915.active_requests?

I was thinking list when I wrote it. It's small enough we can argue both
and both be right.

> 
> > +     list_for_each_entry_safe(ring, next, &i915->gt.live_rings, live)
> >               ring_retire_requests(ring);
> >   }
> >   
> > diff --git a/drivers/gpu/drm/i915/i915_utils.h b/drivers/gpu/drm/i915/i915_utils.h
> > index 0695717522ea..00165ad55fb3 100644
> > --- a/drivers/gpu/drm/i915/i915_utils.h
> > +++ b/drivers/gpu/drm/i915/i915_utils.h
> > @@ -120,6 +120,12 @@ static inline u64 ptr_to_u64(const void *ptr)
> >   
> >   #include <linux/list.h>
> >   
> > +static inline int list_is_first(const struct list_head *list,
> > +                             const struct list_head *head)
> 
> Return bool if you decide you prefer to keep list_is_first?

Copy'n'paste from list_is_last().

> 
> > +{
> > +     return head->next == list;
> > +}
> > +
> >   static inline void __list_del_many(struct list_head *head,
> >                                  struct list_head *first)
> >   {
> > diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
> > index 792a2ca95872..3453e7426f6b 100644
> > --- a/drivers/gpu/drm/i915/intel_ringbuffer.c
> > +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
> > @@ -1150,8 +1150,6 @@ intel_engine_create_ring(struct intel_engine_cs *engine, int size)
> >       }
> >       ring->vma = vma;
> >   
> > -     list_add(&ring->link, &engine->i915->gt.rings);
> > -
> >       return ring;
> >   }
> >   
> > @@ -1163,8 +1161,6 @@ intel_ring_free(struct intel_ring *ring)
> >       i915_vma_close(ring->vma);
> >       __i915_gem_object_release_unless_active(obj);
> >   
> > -     list_del(&ring->link);
> > -
> >       kfree(ring);
> >   }
> >   
> > diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
> > index d816f8dea245..fd5a6363ab1d 100644
> > --- a/drivers/gpu/drm/i915/intel_ringbuffer.h
> > +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
> > @@ -129,7 +129,7 @@ struct intel_ring {
> >       void *vaddr;
> >   
> >       struct list_head request_list;
> > -     struct list_head link;
> > +     struct list_head live;
> 
> live_link?

live or active.

active_rings ties in with active_requests, so active_link here.
-Chris
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 4/6] drm/i915: Move timeline from GTT to ring
  2018-04-23 10:13 ` [PATCH 4/6] drm/i915: Move timeline from GTT to ring Chris Wilson
@ 2018-04-23 10:44   ` Tvrtko Ursulin
  2018-04-23 12:51     ` Chris Wilson
  0 siblings, 1 reply; 20+ messages in thread
From: Tvrtko Ursulin @ 2018-04-23 10:44 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx


On 23/04/2018 11:13, Chris Wilson wrote:
> In the future, we want to move a request between engines. To achieve
> this, we first realise that we have two timelines in effect here. The
> first runs through the GTT is required for ordering vma access, which is
> tracked currently by engine. The second is implied by sequential
> execution of commands inside the ringbuffer. This timeline is one that
> maps to userspace's expectations when submitting requests (i.e. given the
> same context, batch A is executed before batch B). As the rings's
> timelines map to userspace and the GTT timeline an implementation
> detail, move the timeline from the GTT into the ring itself (per-context
> in logical-ring-contexts/execlists, or a global per-engine timeline for
> the shared ringbuffers in legacy submission.
> 
> The two timelines are still assumed to be equivalent at the moment (no
> migrating requests between engines yet) and so we can simply move from
> one to the other without adding extra ordering.
> 
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> ---
>   drivers/gpu/drm/i915/i915_drv.h               | 13 +----
>   drivers/gpu/drm/i915/i915_gem.c               |  9 ++--
>   drivers/gpu/drm/i915/i915_gem_context.c       | 15 +++++-
>   drivers/gpu/drm/i915/i915_gem_context.h       |  2 +
>   drivers/gpu/drm/i915/i915_gem_gtt.c           |  3 --
>   drivers/gpu/drm/i915/i915_gem_gtt.h           |  1 -
>   drivers/gpu/drm/i915/i915_gem_timeline.c      | 54 +++++++++++++++++--
>   drivers/gpu/drm/i915/i915_gem_timeline.h      |  4 ++
>   drivers/gpu/drm/i915/i915_request.c           | 15 +++---
>   drivers/gpu/drm/i915/intel_engine_cs.c        |  3 +-
>   drivers/gpu/drm/i915/intel_lrc.c              |  2 +-
>   drivers/gpu/drm/i915/intel_ringbuffer.c       |  9 +++-
>   drivers/gpu/drm/i915/intel_ringbuffer.h       |  5 +-
>   drivers/gpu/drm/i915/selftests/mock_engine.c  |  3 +-
>   .../gpu/drm/i915/selftests/mock_gem_device.c  |  4 +-
>   drivers/gpu/drm/i915/selftests/mock_gtt.c     |  1 -
>   16 files changed, 101 insertions(+), 42 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index a7787c2cb53c..66123cf0eda3 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -2058,7 +2058,8 @@ struct drm_i915_private {
>   		void (*resume)(struct drm_i915_private *);
>   		void (*cleanup_engine)(struct intel_engine_cs *engine);
>   
> -		struct i915_gem_timeline global_timeline;
> +		struct i915_gem_timeline execution_timeline;
> +		struct i915_gem_timeline legacy_timeline;
>   		struct list_head timelines;
>   		struct list_head live_rings;
>   		u32 active_requests;
> @@ -3232,16 +3233,6 @@ i915_gem_context_lookup(struct drm_i915_file_private *file_priv, u32 id)
>   	return ctx;
>   }
>   
> -static inline struct intel_timeline *
> -i915_gem_context_lookup_timeline(struct i915_gem_context *ctx,
> -				 struct intel_engine_cs *engine)
> -{
> -	struct i915_address_space *vm;
> -
> -	vm = ctx->ppgtt ? &ctx->ppgtt->base : &ctx->i915->ggtt.base;
> -	return &vm->timeline.engine[engine->id];
> -}
> -
>   int i915_perf_open_ioctl(struct drm_device *dev, void *data,
>   			 struct drm_file *file);
>   int i915_perf_add_config_ioctl(struct drm_device *dev, void *data,
> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> index 0097a77fae8d..1635975dbc16 100644
> --- a/drivers/gpu/drm/i915/i915_gem.c
> +++ b/drivers/gpu/drm/i915/i915_gem.c
> @@ -3110,10 +3110,10 @@ static void engine_skip_context(struct i915_request *request)
>   {
>   	struct intel_engine_cs *engine = request->engine;
>   	struct i915_gem_context *hung_ctx = request->ctx;
> -	struct intel_timeline *timeline;
> +	struct intel_timeline *timeline = request->timeline;
>   	unsigned long flags;
>   
> -	timeline = i915_gem_context_lookup_timeline(hung_ctx, engine);
> +	GEM_BUG_ON(timeline == engine->timeline);

Isn't this the guilty request, so would be on the engine timeline?

>   
>   	spin_lock_irqsave(&engine->timeline->lock, flags);
>   	spin_lock(&timeline->lock);
> @@ -3782,7 +3782,7 @@ int i915_gem_wait_for_idle(struct drm_i915_private *i915, unsigned int flags)
>   
>   		ret = wait_for_engines(i915);
>   	} else {
> -		ret = wait_for_timeline(&i915->gt.global_timeline, flags);
> +		ret = wait_for_timeline(&i915->gt.execution_timeline, flags);
>   	}
>   
>   	return ret;
> @@ -5651,7 +5651,8 @@ void i915_gem_cleanup_early(struct drm_i915_private *dev_priv)
>   	WARN_ON(dev_priv->mm.object_count);
>   
>   	mutex_lock(&dev_priv->drm.struct_mutex);
> -	i915_gem_timeline_fini(&dev_priv->gt.global_timeline);
> +	i915_gem_timeline_fini(&dev_priv->gt.legacy_timeline);
> +	i915_gem_timeline_fini(&dev_priv->gt.execution_timeline);
>   	WARN_ON(!list_empty(&dev_priv->gt.timelines));
>   	mutex_unlock(&dev_priv->drm.struct_mutex);
>   
> diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
> index 74435affe23f..58b185abe652 100644
> --- a/drivers/gpu/drm/i915/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/i915_gem_context.c
> @@ -122,6 +122,7 @@ static void i915_gem_context_free(struct i915_gem_context *ctx)
>   	lockdep_assert_held(&ctx->i915->drm.struct_mutex);
>   	GEM_BUG_ON(!i915_gem_context_is_closed(ctx));
>   
> +	i915_gem_timeline_free(ctx->timeline);
>   	i915_ppgtt_put(ctx->ppgtt);
>   
>   	for (i = 0; i < I915_NUM_ENGINES; i++) {
> @@ -376,6 +377,18 @@ i915_gem_create_context(struct drm_i915_private *dev_priv,
>   		ctx->desc_template = default_desc_template(dev_priv, ppgtt);
>   	}
>   
> +	if (HAS_EXECLISTS(dev_priv)) {
> +		struct i915_gem_timeline *timeline;
> +
> +		timeline = i915_gem_timeline_create(dev_priv, ctx->name);
> +		if (IS_ERR(timeline)) {
> +			__destroy_hw_context(ctx, file_priv);
> +			return ERR_CAST(timeline);

Leaks ppgtt by the look of it.

> +		}
> +
> +		ctx->timeline = timeline;
> +	}
> +
>   	trace_i915_context_create(ctx);
>   
>   	return ctx;
> @@ -584,7 +597,7 @@ static bool engine_has_idle_kernel_context(struct intel_engine_cs *engine)
>   	list_for_each_entry(timeline, &engine->i915->gt.timelines, link) {
>   		struct intel_timeline *tl;
>   
> -		if (timeline == &engine->i915->gt.global_timeline)
> +		if (timeline == &engine->i915->gt.execution_timeline)
>   			continue;
>   
>   		tl = &timeline->engine[engine->id];
> diff --git a/drivers/gpu/drm/i915/i915_gem_context.h b/drivers/gpu/drm/i915/i915_gem_context.h
> index b12a8a8c5af9..140edcb424df 100644
> --- a/drivers/gpu/drm/i915/i915_gem_context.h
> +++ b/drivers/gpu/drm/i915/i915_gem_context.h
> @@ -58,6 +58,8 @@ struct i915_gem_context {
>   	/** file_priv: owning file descriptor */
>   	struct drm_i915_file_private *file_priv;
>   
> +	struct i915_gem_timeline *timeline;
> +
>   	/**
>   	 * @ppgtt: unique address space (GTT)
>   	 *
> diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
> index 21d72f695adb..e9d828324f67 100644
> --- a/drivers/gpu/drm/i915/i915_gem_gtt.c
> +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
> @@ -2111,8 +2111,6 @@ static void i915_address_space_init(struct i915_address_space *vm,
>   				    struct drm_i915_private *dev_priv,
>   				    const char *name)
>   {
> -	i915_gem_timeline_init(dev_priv, &vm->timeline, name);
> -
>   	drm_mm_init(&vm->mm, 0, vm->total);
>   	vm->mm.head_node.color = I915_COLOR_UNEVICTABLE;
>   
> @@ -2129,7 +2127,6 @@ static void i915_address_space_fini(struct i915_address_space *vm)
>   	if (pagevec_count(&vm->free_pages))
>   		vm_free_pages_release(vm, true);
>   
> -	i915_gem_timeline_fini(&vm->timeline);
>   	drm_mm_takedown(&vm->mm);
>   	list_del(&vm->global_link);
>   }
> diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h
> index 6efc017e8bb3..98107925de48 100644
> --- a/drivers/gpu/drm/i915/i915_gem_gtt.h
> +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h
> @@ -257,7 +257,6 @@ struct i915_pml4 {
>   
>   struct i915_address_space {
>   	struct drm_mm mm;
> -	struct i915_gem_timeline timeline;
>   	struct drm_i915_private *i915;
>   	struct device *dma;
>   	/* Every address space belongs to a struct file - except for the global
> diff --git a/drivers/gpu/drm/i915/i915_gem_timeline.c b/drivers/gpu/drm/i915/i915_gem_timeline.c
> index e9fd87604067..24f4068cc137 100644
> --- a/drivers/gpu/drm/i915/i915_gem_timeline.c
> +++ b/drivers/gpu/drm/i915/i915_gem_timeline.c
> @@ -95,12 +95,28 @@ int i915_gem_timeline_init(struct drm_i915_private *i915,
>   
>   int i915_gem_timeline_init__global(struct drm_i915_private *i915)
>   {
> -	static struct lock_class_key class;
> +	static struct lock_class_key class1, class2;
> +	int err;
> +
> +	err = __i915_gem_timeline_init(i915,
> +				       &i915->gt.execution_timeline,
> +				       "[execution]", &class1,
> +				       "i915_execution_timeline");
> +	if (err)
> +		return err;
> +
> +	err = __i915_gem_timeline_init(i915,
> +				       &i915->gt.legacy_timeline,
> +				       "[global]", &class2,
> +				       "i915_global_timeline");
> +	if (err)
> +		goto err_exec_timeline;
> +
> +	return 0;
>   
> -	return __i915_gem_timeline_init(i915,
> -					&i915->gt.global_timeline,
> -					"[execution]",
> -					&class, "&global_timeline->lock");
> +err_exec_timeline:
> +	i915_gem_timeline_fini(&i915->gt.execution_timeline);
> +	return err;
>   }
>   
>   /**
> @@ -148,6 +164,34 @@ void i915_gem_timeline_fini(struct i915_gem_timeline *timeline)
>   	kfree(timeline->name);
>   }
>   
> +struct i915_gem_timeline *
> +i915_gem_timeline_create(struct drm_i915_private *i915, const char *name)
> +{
> +	struct i915_gem_timeline *timeline;
> +	int err;
> +
> +	timeline = kzalloc(sizeof(*timeline), GFP_KERNEL);
> +	if (!timeline)
> +		return ERR_PTR(-ENOMEM);
> +
> +	err = i915_gem_timeline_init(i915, timeline, name);
> +	if (err) {
> +		kfree(timeline);
> +		return ERR_PTR(err);
> +	}
> +
> +	return timeline;
> +}
> +
> +void i915_gem_timeline_free(struct i915_gem_timeline *timeline)
> +{
> +	if (!timeline)
> +		return;
> +
> +	i915_gem_timeline_fini(timeline);
> +	kfree(timeline);
> +}
> +
>   #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
>   #include "selftests/mock_timeline.c"
>   #include "selftests/i915_gem_timeline.c"
> diff --git a/drivers/gpu/drm/i915/i915_gem_timeline.h b/drivers/gpu/drm/i915/i915_gem_timeline.h
> index 6e82119e2cd8..780ed465c4fc 100644
> --- a/drivers/gpu/drm/i915/i915_gem_timeline.h
> +++ b/drivers/gpu/drm/i915/i915_gem_timeline.h
> @@ -90,6 +90,10 @@ int i915_gem_timeline_init__global(struct drm_i915_private *i915);
>   void i915_gem_timelines_park(struct drm_i915_private *i915);
>   void i915_gem_timeline_fini(struct i915_gem_timeline *tl);
>   
> +struct i915_gem_timeline *
> +i915_gem_timeline_create(struct drm_i915_private *i915, const char *name);
> +void i915_gem_timeline_free(struct i915_gem_timeline *timeline);
> +
>   static inline int __intel_timeline_sync_set(struct intel_timeline *tl,
>   					    u64 context, u32 seqno)
>   {
> diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c
> index 534b8d684cef..35869afdb199 100644
> --- a/drivers/gpu/drm/i915/i915_request.c
> +++ b/drivers/gpu/drm/i915/i915_request.c
> @@ -639,6 +639,7 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx)
>   	if (IS_ERR(ring))
>   		return ERR_CAST(ring);
>   	GEM_BUG_ON(!ring);
> +	GEM_BUG_ON(ring->timeline == engine->timeline);

It's debugging only but feels out of place. Put it in 
intel_engine_create_ring?

>   
>   	ret = reserve_engine(engine);
>   	if (ret)
> @@ -711,8 +712,12 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx)
>   		}
>   	}
>   
> -	rq->timeline = i915_gem_context_lookup_timeline(ctx, engine);
> -	GEM_BUG_ON(rq->timeline == engine->timeline);
> +	INIT_LIST_HEAD(&rq->active_list);
> +	rq->i915 = i915;
> +	rq->engine = engine;
> +	rq->ctx = ctx;
> +	rq->ring = ring;
> +	rq->timeline = ring->timeline;
>   
>   	spin_lock_init(&rq->lock);
>   	dma_fence_init(&rq->fence,
> @@ -727,12 +732,6 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx)
>   
>   	i915_sched_node_init(&rq->sched);
>   
> -	INIT_LIST_HEAD(&rq->active_list);
> -	rq->i915 = i915;
> -	rq->engine = engine;
> -	rq->ctx = ctx;
> -	rq->ring = ring;
> -
>   	/* No zalloc, must clear what we need by hand */
>   	rq->global_seqno = 0;
>   	rq->signaling.wait.seqno = 0;
> diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c
> index a55a849b81b6..d44a8eb83379 100644
> --- a/drivers/gpu/drm/i915/intel_engine_cs.c
> +++ b/drivers/gpu/drm/i915/intel_engine_cs.c
> @@ -453,7 +453,8 @@ void intel_engine_init_global_seqno(struct intel_engine_cs *engine, u32 seqno)
>   
>   static void intel_engine_init_timeline(struct intel_engine_cs *engine)
>   {
> -	engine->timeline = &engine->i915->gt.global_timeline.engine[engine->id];
> +	engine->timeline =
> +		&engine->i915->gt.execution_timeline.engine[engine->id];
>   }
>   
>   static void intel_engine_init_batch_pool(struct intel_engine_cs *engine)
> diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
> index 029901a8fa38..fd3539034665 100644
> --- a/drivers/gpu/drm/i915/intel_lrc.c
> +++ b/drivers/gpu/drm/i915/intel_lrc.c
> @@ -2584,7 +2584,7 @@ static int execlists_context_deferred_alloc(struct i915_gem_context *ctx,
>   		goto error_deref_obj;
>   	}
>   
> -	ring = intel_engine_create_ring(engine, ctx->ring_size);
> +	ring = intel_engine_create_ring(engine, ctx->timeline, ctx->ring_size);
>   	if (IS_ERR(ring)) {
>   		ret = PTR_ERR(ring);
>   		goto error_deref_obj;
> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
> index 3453e7426f6b..4559fe1c574e 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.c
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
> @@ -1117,7 +1117,9 @@ intel_ring_create_vma(struct drm_i915_private *dev_priv, int size)
>   }
>   
>   struct intel_ring *
> -intel_engine_create_ring(struct intel_engine_cs *engine, int size)
> +intel_engine_create_ring(struct intel_engine_cs *engine,
> +			 struct i915_gem_timeline *timeline,
> +			 int size)
>   {
>   	struct intel_ring *ring;
>   	struct i915_vma *vma;
> @@ -1131,6 +1133,7 @@ intel_engine_create_ring(struct intel_engine_cs *engine, int size)
>   		return ERR_PTR(-ENOMEM);
>   
>   	INIT_LIST_HEAD(&ring->request_list);
> +	ring->timeline = &timeline->engine[engine->id];
>   
>   	ring->size = size;
>   	/* Workaround an erratum on the i830 which causes a hang if
> @@ -1327,7 +1330,9 @@ static int intel_init_ring_buffer(struct intel_engine_cs *engine)
>   	if (err)
>   		goto err;
>   
> -	ring = intel_engine_create_ring(engine, 32 * PAGE_SIZE);
> +	ring = intel_engine_create_ring(engine,
> +					&engine->i915->gt.legacy_timeline,
> +					32 * PAGE_SIZE);
>   	if (IS_ERR(ring)) {
>   		err = PTR_ERR(ring);
>   		goto err;
> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
> index fd5a6363ab1d..3f63499734f7 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.h
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
> @@ -128,6 +128,7 @@ struct intel_ring {
>   	struct i915_vma *vma;
>   	void *vaddr;
>   
> +	struct intel_timeline *timeline;
>   	struct list_head request_list;
>   	struct list_head live;
>   
> @@ -767,7 +768,9 @@ intel_write_status_page(struct intel_engine_cs *engine, int reg, u32 value)
>   #define CNL_HWS_CSB_WRITE_INDEX		0x2f
>   
>   struct intel_ring *
> -intel_engine_create_ring(struct intel_engine_cs *engine, int size);
> +intel_engine_create_ring(struct intel_engine_cs *engine,
> +			 struct i915_gem_timeline *timeline,
> +			 int size);
>   int intel_ring_pin(struct intel_ring *ring,
>   		   struct drm_i915_private *i915,
>   		   unsigned int offset_bias);
> diff --git a/drivers/gpu/drm/i915/selftests/mock_engine.c b/drivers/gpu/drm/i915/selftests/mock_engine.c
> index 74a88913623f..6a10cb734c35 100644
> --- a/drivers/gpu/drm/i915/selftests/mock_engine.c
> +++ b/drivers/gpu/drm/i915/selftests/mock_engine.c
> @@ -173,8 +173,7 @@ struct intel_engine_cs *mock_engine(struct drm_i915_private *i915,
>   	engine->base.emit_breadcrumb = mock_emit_breadcrumb;
>   	engine->base.submit_request = mock_submit_request;
>   
> -	engine->base.timeline =
> -		&i915->gt.global_timeline.engine[engine->base.id];
> +	intel_engine_init_timeline(&engine->base);
>   
>   	intel_engine_init_breadcrumbs(&engine->base);
>   	engine->base.breadcrumbs.mock = true; /* prevent touching HW for irqs */
> diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_device.c b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
> index 9335b09d8b04..ed1bf3b2e47f 100644
> --- a/drivers/gpu/drm/i915/selftests/mock_gem_device.c
> +++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
> @@ -73,7 +73,9 @@ static void mock_device_release(struct drm_device *dev)
>   
>   	mutex_lock(&i915->drm.struct_mutex);
>   	mock_fini_ggtt(i915);
> -	i915_gem_timeline_fini(&i915->gt.global_timeline);
> +	i915_gem_timeline_fini(&i915->gt.legacy_timeline);
> +	i915_gem_timeline_fini(&i915->gt.execution_timeline);
> +	WARN_ON(!list_empty(&i915->gt.timelines));
>   	mutex_unlock(&i915->drm.struct_mutex);
>   
>   	destroy_workqueue(i915->wq);
> diff --git a/drivers/gpu/drm/i915/selftests/mock_gtt.c b/drivers/gpu/drm/i915/selftests/mock_gtt.c
> index e96873f96116..36c112088940 100644
> --- a/drivers/gpu/drm/i915/selftests/mock_gtt.c
> +++ b/drivers/gpu/drm/i915/selftests/mock_gtt.c
> @@ -76,7 +76,6 @@ mock_ppgtt(struct drm_i915_private *i915,
>   
>   	INIT_LIST_HEAD(&ppgtt->base.global_link);
>   	drm_mm_init(&ppgtt->base.mm, 0, ppgtt->base.total);
> -	i915_gem_timeline_init(i915, &ppgtt->base.timeline, name);
>   
>   	ppgtt->base.clear_range = nop_clear_range;
>   	ppgtt->base.insert_page = mock_insert_page;
> 

Looks good in principle, only some details to talk about.

Regards,

Tvrtko
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 3/6] drm/i915: Only track live rings for retiring
  2018-04-23 10:36     ` Chris Wilson
@ 2018-04-23 10:50       ` Tvrtko Ursulin
  0 siblings, 0 replies; 20+ messages in thread
From: Tvrtko Ursulin @ 2018-04-23 10:50 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx


On 23/04/2018 11:36, Chris Wilson wrote:
> Quoting Tvrtko Ursulin (2018-04-23 11:25:54)
>>
>> On 23/04/2018 11:13, Chris Wilson wrote:
>>> We don't need to track every ring for its lifetime as they are managed
>>> by the contexts/engines. What we do want to track are the live rings so
>>> that we can sporadically clean up requests if userspace falls behind. We
>>> can simply restrict the gt->rings list to being only gt->live_rings.
>>>
>>> Suggested-by: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
>>> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
>>> Cc: Tvrtko Ursulin <tvrtko.ursulin@linux.intel.com>
>>> ---
>>>    drivers/gpu/drm/i915/i915_drv.h                  | 2 +-
>>>    drivers/gpu/drm/i915/i915_gem.c                  | 3 ++-
>>>    drivers/gpu/drm/i915/i915_request.c              | 6 +++++-
>>>    drivers/gpu/drm/i915/i915_utils.h                | 6 ++++++
>>>    drivers/gpu/drm/i915/intel_ringbuffer.c          | 4 ----
>>>    drivers/gpu/drm/i915/intel_ringbuffer.h          | 2 +-
>>>    drivers/gpu/drm/i915/selftests/mock_engine.c     | 4 ----
>>>    drivers/gpu/drm/i915/selftests/mock_gem_device.c | 2 +-
>>>    8 files changed, 16 insertions(+), 13 deletions(-)
>>>
>>> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
>>> index 73936be90aed..a7787c2cb53c 100644
>>> --- a/drivers/gpu/drm/i915/i915_drv.h
>>> +++ b/drivers/gpu/drm/i915/i915_drv.h
>>> @@ -2060,7 +2060,7 @@ struct drm_i915_private {
>>>    
>>>                struct i915_gem_timeline global_timeline;
>>>                struct list_head timelines;
>>> -             struct list_head rings;
>>> +             struct list_head live_rings;
>>>                u32 active_requests;
>>>    
>>>                /**
>>> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
>>> index 906e2395c245..0097a77fae8d 100644
>>> --- a/drivers/gpu/drm/i915/i915_gem.c
>>> +++ b/drivers/gpu/drm/i915/i915_gem.c
>>> @@ -141,6 +141,7 @@ static u32 __i915_gem_park(struct drm_i915_private *i915)
>>>    {
>>>        lockdep_assert_held(&i915->drm.struct_mutex);
>>>        GEM_BUG_ON(i915->gt.active_requests);
>>> +     GEM_BUG_ON(!list_empty(&i915->gt.live_rings));
>>>    
>>>        if (!i915->gt.awake)
>>>                return I915_EPOCH_INVALID;
>>> @@ -5600,7 +5601,7 @@ int i915_gem_init_early(struct drm_i915_private *dev_priv)
>>>                goto err_dependencies;
>>>    
>>>        mutex_lock(&dev_priv->drm.struct_mutex);
>>> -     INIT_LIST_HEAD(&dev_priv->gt.rings);
>>> +     INIT_LIST_HEAD(&dev_priv->gt.live_rings);
>>>        INIT_LIST_HEAD(&dev_priv->gt.timelines);
>>>        err = i915_gem_timeline_init__global(dev_priv);
>>>        mutex_unlock(&dev_priv->drm.struct_mutex);
>>> diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c
>>> index 0bf949ec9f1a..534b8d684cef 100644
>>> --- a/drivers/gpu/drm/i915/i915_request.c
>>> +++ b/drivers/gpu/drm/i915/i915_request.c
>>> @@ -316,6 +316,7 @@ static void advance_ring(struct i915_request *request)
>>>                 * noops - they are safe to be replayed on a reset.
>>>                 */
>>>                tail = READ_ONCE(request->tail);
>>> +             list_del(&ring->live);
>>>        } else {
>>>                tail = request->postfix;
>>>        }
>>> @@ -1046,6 +1047,8 @@ void __i915_request_add(struct i915_request *request, bool flush_caches)
>>>        i915_gem_active_set(&timeline->last_request, request);
>>>    
>>>        list_add_tail(&request->ring_link, &ring->request_list);
>>> +     if (list_is_first(&request->ring_link, &ring->request_list))
>>> +             list_add(&ring->live, &request->i915->gt.live_rings);
>>
>> If you re-order the two list adds you could use list_empty and wouldn't
>> have to add list_is_first.
> 
> list_is_first tallies nicely with the list_is_last used before the
> corresponding list_del.

Yes but to me that's minor, basically immaterial as argument whether or 
not to add our own list helper.

>>
>>>        request->emitted_jiffies = jiffies;
>>>    
>>>        /*
>>> @@ -1375,7 +1378,8 @@ void i915_retire_requests(struct drm_i915_private *i915)
>>>        if (!i915->gt.active_requests)
>>>                return;
>>>    
>>> -     list_for_each_entry_safe(ring, next, &i915->gt.rings, link)
>>> +     GEM_BUG_ON(list_empty(&i915->gt.live_rings));
>>
>> Maybe blank line here since the assert is not logically associated with
>> the list but with the !i915.active_requests?
> 
> I was thinking list when I wrote it. It's small enough we can argue both
> and both be right.

Hm obviosuly it is not an error to call i915_retire_requests with 
nothing active (early return). So I even briefly wanted to suggest to 
make it 100% explicit and have the assert at the top of the function as:

GEM_BUG_ON(!!i915->gt.active_requests ^ !!list_empty(..));

Unless I messed it up, the idea is to check those two are always in the 
same state.

> 
>>
>>> +     list_for_each_entry_safe(ring, next, &i915->gt.live_rings, live)
>>>                ring_retire_requests(ring);
>>>    }
>>>    
>>> diff --git a/drivers/gpu/drm/i915/i915_utils.h b/drivers/gpu/drm/i915/i915_utils.h
>>> index 0695717522ea..00165ad55fb3 100644
>>> --- a/drivers/gpu/drm/i915/i915_utils.h
>>> +++ b/drivers/gpu/drm/i915/i915_utils.h
>>> @@ -120,6 +120,12 @@ static inline u64 ptr_to_u64(const void *ptr)
>>>    
>>>    #include <linux/list.h>
>>>    
>>> +static inline int list_is_first(const struct list_head *list,
>>> +                             const struct list_head *head)
>>
>> Return bool if you decide you prefer to keep list_is_first?
> 
> Copy'n'paste from list_is_last().
> 
>>
>>> +{
>>> +     return head->next == list;
>>> +}
>>> +
>>>    static inline void __list_del_many(struct list_head *head,
>>>                                   struct list_head *first)
>>>    {
>>> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
>>> index 792a2ca95872..3453e7426f6b 100644
>>> --- a/drivers/gpu/drm/i915/intel_ringbuffer.c
>>> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
>>> @@ -1150,8 +1150,6 @@ intel_engine_create_ring(struct intel_engine_cs *engine, int size)
>>>        }
>>>        ring->vma = vma;
>>>    
>>> -     list_add(&ring->link, &engine->i915->gt.rings);
>>> -
>>>        return ring;
>>>    }
>>>    
>>> @@ -1163,8 +1161,6 @@ intel_ring_free(struct intel_ring *ring)
>>>        i915_vma_close(ring->vma);
>>>        __i915_gem_object_release_unless_active(obj);
>>>    
>>> -     list_del(&ring->link);
>>> -
>>>        kfree(ring);
>>>    }
>>>    
>>> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
>>> index d816f8dea245..fd5a6363ab1d 100644
>>> --- a/drivers/gpu/drm/i915/intel_ringbuffer.h
>>> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
>>> @@ -129,7 +129,7 @@ struct intel_ring {
>>>        void *vaddr;
>>>    
>>>        struct list_head request_list;
>>> -     struct list_head link;
>>> +     struct list_head live;
>>
>> live_link?
> 
> live or active.
> 
> active_rings ties in with active_requests, so active_link here.

Fine by me.

Regards,

Tvrtko
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 5/6] drm/i915: Split i915_gem_timeline into individual timelines
  2018-04-23 10:13 ` [PATCH 5/6] drm/i915: Split i915_gem_timeline into individual timelines Chris Wilson
@ 2018-04-23 12:33   ` Tvrtko Ursulin
  2018-04-23 12:55     ` Chris Wilson
  0 siblings, 1 reply; 20+ messages in thread
From: Tvrtko Ursulin @ 2018-04-23 12:33 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx


On 23/04/2018 11:13, Chris Wilson wrote:
> We need to move to a more flexible timeline that doesn't assume one
> fence context per engine, and so allow for a single timeline to be used
> across a combination of engines. This means that preallocating a fence
> context per engine is now a hindrance, and so we want to introduce the
> singular timeline. From the code perspective, this has the notable
> advantage of clearing up a lot of mirky semantics and some clumsy
> pointer chasing.
> 
> By splitting the timeline up into a single entity rather than an array
> of per-engine timelines, we can realise the goal of the previous patch
> of tracking the timeline alongside the ring.

Isn't single fence context and a single seqno space breaking the ABI? 
Submissions from a context are now serialized across all engines. I am 
thinking about await and dependency created in __i915_add_request to 
timeline->last_request.

> 
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> ---
>   drivers/gpu/drm/i915/Makefile                 |   2 +-
>   drivers/gpu/drm/i915/i915_drv.h               |   4 +-
>   drivers/gpu/drm/i915/i915_gem.c               | 117 +++++------
>   drivers/gpu/drm/i915/i915_gem_context.c       |  49 ++---
>   drivers/gpu/drm/i915/i915_gem_context.h       |   2 -
>   drivers/gpu/drm/i915/i915_gem_gtt.h           |   3 +-
>   drivers/gpu/drm/i915/i915_gem_timeline.c      | 198 ------------------
>   drivers/gpu/drm/i915/i915_gpu_error.c         |   4 +-
>   drivers/gpu/drm/i915/i915_perf.c              |  10 +-
>   drivers/gpu/drm/i915/i915_request.c           |  65 +++---
>   drivers/gpu/drm/i915/i915_request.h           |   3 +-
>   drivers/gpu/drm/i915/i915_timeline.c          | 105 ++++++++++
>   .../{i915_gem_timeline.h => i915_timeline.h}  |  67 +++---
>   drivers/gpu/drm/i915/intel_engine_cs.c        |  27 ++-
>   drivers/gpu/drm/i915/intel_guc_submission.c   |   4 +-
>   drivers/gpu/drm/i915/intel_lrc.c              |  48 +++--
>   drivers/gpu/drm/i915/intel_ringbuffer.c       |  23 +-
>   drivers/gpu/drm/i915/intel_ringbuffer.h       |  11 +-
>   .../{i915_gem_timeline.c => i915_timeline.c}  |  94 +++------
>   drivers/gpu/drm/i915/selftests/mock_engine.c  |  32 ++-
>   .../gpu/drm/i915/selftests/mock_gem_device.c  |  11 +-
>   .../gpu/drm/i915/selftests/mock_timeline.c    |  45 ++--
>   .../gpu/drm/i915/selftests/mock_timeline.h    |  28 +--
>   23 files changed, 389 insertions(+), 563 deletions(-)
>   delete mode 100644 drivers/gpu/drm/i915/i915_gem_timeline.c
>   create mode 100644 drivers/gpu/drm/i915/i915_timeline.c
>   rename drivers/gpu/drm/i915/{i915_gem_timeline.h => i915_timeline.h} (68%)
>   rename drivers/gpu/drm/i915/selftests/{i915_gem_timeline.c => i915_timeline.c} (70%)
> 
> diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
> index 9bee52a949a9..120db21fcd50 100644
> --- a/drivers/gpu/drm/i915/Makefile
> +++ b/drivers/gpu/drm/i915/Makefile
> @@ -67,11 +67,11 @@ i915-y += i915_cmd_parser.o \
>   	  i915_gem_shrinker.o \
>   	  i915_gem_stolen.o \
>   	  i915_gem_tiling.o \
> -	  i915_gem_timeline.o \
>   	  i915_gem_userptr.o \
>   	  i915_gemfs.o \
>   	  i915_query.o \
>   	  i915_request.o \
> +	  i915_timeline.o \
>   	  i915_trace_points.o \
>   	  i915_vma.o \
>   	  intel_breadcrumbs.o \
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 66123cf0eda3..89cb74c30a00 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -72,10 +72,10 @@
>   #include "i915_gem_fence_reg.h"
>   #include "i915_gem_object.h"
>   #include "i915_gem_gtt.h"
> -#include "i915_gem_timeline.h"
>   #include "i915_gpu_error.h"
>   #include "i915_request.h"
>   #include "i915_scheduler.h"
> +#include "i915_timeline.h"
>   #include "i915_vma.h"
>   
>   #include "intel_gvt.h"
> @@ -2058,8 +2058,6 @@ struct drm_i915_private {
>   		void (*resume)(struct drm_i915_private *);
>   		void (*cleanup_engine)(struct intel_engine_cs *engine);
>   
> -		struct i915_gem_timeline execution_timeline;
> -		struct i915_gem_timeline legacy_timeline;
>   		struct list_head timelines;
>   		struct list_head live_rings;
>   		u32 active_requests;
> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> index 1635975dbc16..f07556693cfe 100644
> --- a/drivers/gpu/drm/i915/i915_gem.c
> +++ b/drivers/gpu/drm/i915/i915_gem.c
> @@ -162,7 +162,7 @@ static u32 __i915_gem_park(struct drm_i915_private *i915)
>   	synchronize_irq(i915->drm.irq);
>   
>   	intel_engines_park(i915);
> -	i915_gem_timelines_park(i915);
> +	i915_timelines_park(i915);
>   
>   	i915_pmu_gt_parked(i915);
>   
> @@ -2977,8 +2977,8 @@ i915_gem_find_active_request(struct intel_engine_cs *engine)
>   	 * extra delay for a recent interrupt is pointless. Hence, we do
>   	 * not need an engine->irq_seqno_barrier() before the seqno reads.
>   	 */
> -	spin_lock_irqsave(&engine->timeline->lock, flags);
> -	list_for_each_entry(request, &engine->timeline->requests, link) {
> +	spin_lock_irqsave(&engine->timeline.lock, flags);
> +	list_for_each_entry(request, &engine->timeline.requests, link) {
>   		if (__i915_request_completed(request, request->global_seqno))
>   			continue;
>   
> @@ -2989,7 +2989,7 @@ i915_gem_find_active_request(struct intel_engine_cs *engine)
>   		active = request;
>   		break;
>   	}
> -	spin_unlock_irqrestore(&engine->timeline->lock, flags);
> +	spin_unlock_irqrestore(&engine->timeline.lock, flags);
>   
>   	return active;
>   }
> @@ -3110,15 +3110,15 @@ static void engine_skip_context(struct i915_request *request)
>   {
>   	struct intel_engine_cs *engine = request->engine;
>   	struct i915_gem_context *hung_ctx = request->ctx;
> -	struct intel_timeline *timeline = request->timeline;
> +	struct i915_timeline *timeline = request->timeline;
>   	unsigned long flags;
>   
> -	GEM_BUG_ON(timeline == engine->timeline);
> +	GEM_BUG_ON(timeline == &engine->timeline);
>   
> -	spin_lock_irqsave(&engine->timeline->lock, flags);
> +	spin_lock_irqsave(&engine->timeline.lock, flags);
>   	spin_lock(&timeline->lock);
>   
> -	list_for_each_entry_continue(request, &engine->timeline->requests, link)
> +	list_for_each_entry_continue(request, &engine->timeline.requests, link)
>   		if (request->ctx == hung_ctx)
>   			skip_request(request);
>   
> @@ -3126,7 +3126,7 @@ static void engine_skip_context(struct i915_request *request)
>   		skip_request(request);
>   
>   	spin_unlock(&timeline->lock);
> -	spin_unlock_irqrestore(&engine->timeline->lock, flags);
> +	spin_unlock_irqrestore(&engine->timeline.lock, flags);
>   }
>   
>   /* Returns the request if it was guilty of the hang */
> @@ -3183,11 +3183,11 @@ i915_gem_reset_request(struct intel_engine_cs *engine,
>   			dma_fence_set_error(&request->fence, -EAGAIN);
>   
>   			/* Rewind the engine to replay the incomplete rq */
> -			spin_lock_irq(&engine->timeline->lock);
> +			spin_lock_irq(&engine->timeline.lock);
>   			request = list_prev_entry(request, link);
> -			if (&request->link == &engine->timeline->requests)
> +			if (&request->link == &engine->timeline.requests)
>   				request = NULL;
> -			spin_unlock_irq(&engine->timeline->lock);
> +			spin_unlock_irq(&engine->timeline.lock);
>   		}
>   	}
>   
> @@ -3300,10 +3300,10 @@ static void nop_complete_submit_request(struct i915_request *request)
>   		  request->fence.context, request->fence.seqno);
>   	dma_fence_set_error(&request->fence, -EIO);
>   
> -	spin_lock_irqsave(&request->engine->timeline->lock, flags);
> +	spin_lock_irqsave(&request->engine->timeline.lock, flags);
>   	__i915_request_submit(request);
>   	intel_engine_init_global_seqno(request->engine, request->global_seqno);
> -	spin_unlock_irqrestore(&request->engine->timeline->lock, flags);
> +	spin_unlock_irqrestore(&request->engine->timeline.lock, flags);
>   }
>   
>   void i915_gem_set_wedged(struct drm_i915_private *i915)
> @@ -3372,10 +3372,10 @@ void i915_gem_set_wedged(struct drm_i915_private *i915)
>   		 * (lockless) lookup doesn't try and wait upon the request as we
>   		 * reset it.
>   		 */
> -		spin_lock_irqsave(&engine->timeline->lock, flags);
> +		spin_lock_irqsave(&engine->timeline.lock, flags);
>   		intel_engine_init_global_seqno(engine,
>   					       intel_engine_last_submit(engine));
> -		spin_unlock_irqrestore(&engine->timeline->lock, flags);
> +		spin_unlock_irqrestore(&engine->timeline.lock, flags);
>   
>   		i915_gem_reset_finish_engine(engine);
>   	}
> @@ -3387,8 +3387,7 @@ void i915_gem_set_wedged(struct drm_i915_private *i915)
>   
>   bool i915_gem_unset_wedged(struct drm_i915_private *i915)
>   {
> -	struct i915_gem_timeline *tl;
> -	int i;
> +	struct i915_timeline *tl;
>   
>   	lockdep_assert_held(&i915->drm.struct_mutex);
>   	if (!test_bit(I915_WEDGED, &i915->gpu_error.flags))
> @@ -3407,29 +3406,27 @@ bool i915_gem_unset_wedged(struct drm_i915_private *i915)
>   	 * No more can be submitted until we reset the wedged bit.
>   	 */
>   	list_for_each_entry(tl, &i915->gt.timelines, link) {
> -		for (i = 0; i < ARRAY_SIZE(tl->engine); i++) {
> -			struct i915_request *rq;
> +		struct i915_request *rq;
>   
> -			rq = i915_gem_active_peek(&tl->engine[i].last_request,
> -						  &i915->drm.struct_mutex);
> -			if (!rq)
> -				continue;
> +		rq = i915_gem_active_peek(&tl->last_request,
> +					  &i915->drm.struct_mutex);
> +		if (!rq)
> +			continue;
>   
> -			/*
> -			 * We can't use our normal waiter as we want to
> -			 * avoid recursively trying to handle the current
> -			 * reset. The basic dma_fence_default_wait() installs
> -			 * a callback for dma_fence_signal(), which is
> -			 * triggered by our nop handler (indirectly, the
> -			 * callback enables the signaler thread which is
> -			 * woken by the nop_submit_request() advancing the seqno
> -			 * and when the seqno passes the fence, the signaler
> -			 * then signals the fence waking us up).
> -			 */
> -			if (dma_fence_default_wait(&rq->fence, true,
> -						   MAX_SCHEDULE_TIMEOUT) < 0)
> -				return false;
> -		}
> +		/*
> +		 * We can't use our normal waiter as we want to
> +		 * avoid recursively trying to handle the current
> +		 * reset. The basic dma_fence_default_wait() installs
> +		 * a callback for dma_fence_signal(), which is
> +		 * triggered by our nop handler (indirectly, the
> +		 * callback enables the signaler thread which is
> +		 * woken by the nop_submit_request() advancing the seqno
> +		 * and when the seqno passes the fence, the signaler
> +		 * then signals the fence waking us up).
> +		 */
> +		if (dma_fence_default_wait(&rq->fence, true,
> +					   MAX_SCHEDULE_TIMEOUT) < 0)
> +			return false;
>   	}
>   	i915_retire_requests(i915);
>   	GEM_BUG_ON(i915->gt.active_requests);
> @@ -3734,19 +3731,6 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
>   	return ret;
>   }
>   
> -static int wait_for_timeline(struct i915_gem_timeline *tl, unsigned int flags)
> -{
> -	int ret, i;
> -
> -	for (i = 0; i < ARRAY_SIZE(tl->engine); i++) {
> -		ret = i915_gem_active_wait(&tl->engine[i].last_request, flags);
> -		if (ret)
> -			return ret;
> -	}
> -
> -	return 0;
> -}
> -
>   static int wait_for_engines(struct drm_i915_private *i915)
>   {
>   	if (wait_for(intel_engines_are_idle(i915), I915_IDLE_ENGINES_TIMEOUT)) {
> @@ -3769,12 +3753,12 @@ int i915_gem_wait_for_idle(struct drm_i915_private *i915, unsigned int flags)
>   		return 0;
>   
>   	if (flags & I915_WAIT_LOCKED) {
> -		struct i915_gem_timeline *tl;
> +		struct i915_timeline *tl;
>   
>   		lockdep_assert_held(&i915->drm.struct_mutex);
>   
>   		list_for_each_entry(tl, &i915->gt.timelines, link) {
> -			ret = wait_for_timeline(tl, flags);
> +			ret = i915_gem_active_wait(&tl->last_request, flags);
>   			if (ret)
>   				return ret;
>   		}
> @@ -3782,7 +3766,16 @@ int i915_gem_wait_for_idle(struct drm_i915_private *i915, unsigned int flags)
>   
>   		ret = wait_for_engines(i915);
>   	} else {
> -		ret = wait_for_timeline(&i915->gt.execution_timeline, flags);
> +		struct intel_engine_cs *engine;
> +		enum intel_engine_id id;
> +
> +		for_each_engine(engine, i915, id) {
> +			struct i915_timeline *tl = &engine->timeline;
> +
> +			ret = i915_gem_active_wait(&tl->last_request, flags);
> +			if (ret)
> +				return ret;
> +		}
>   	}
>   
>   	return ret;
> @@ -4954,7 +4947,7 @@ static void assert_kernel_context_is_current(struct drm_i915_private *i915)
>   	enum intel_engine_id id;
>   
>   	for_each_engine(engine, i915, id) {
> -		GEM_BUG_ON(__i915_gem_active_peek(&engine->timeline->last_request));
> +		GEM_BUG_ON(__i915_gem_active_peek(&engine->timeline.last_request));
>   		GEM_BUG_ON(engine->last_retired_context != kernel_context);
>   	}
>   }
> @@ -5600,13 +5593,8 @@ int i915_gem_init_early(struct drm_i915_private *dev_priv)
>   	if (!dev_priv->priorities)
>   		goto err_dependencies;
>   
> -	mutex_lock(&dev_priv->drm.struct_mutex);
>   	INIT_LIST_HEAD(&dev_priv->gt.live_rings);
>   	INIT_LIST_HEAD(&dev_priv->gt.timelines);
> -	err = i915_gem_timeline_init__global(dev_priv);
> -	mutex_unlock(&dev_priv->drm.struct_mutex);
> -	if (err)
> -		goto err_priorities;
>   
>   	i915_gem_init__mm(dev_priv);
>   
> @@ -5627,8 +5615,6 @@ int i915_gem_init_early(struct drm_i915_private *dev_priv)
>   
>   	return 0;
>   
> -err_priorities:
> -	kmem_cache_destroy(dev_priv->priorities);
>   err_dependencies:
>   	kmem_cache_destroy(dev_priv->dependencies);
>   err_requests:
> @@ -5649,12 +5635,7 @@ void i915_gem_cleanup_early(struct drm_i915_private *dev_priv)
>   	GEM_BUG_ON(!llist_empty(&dev_priv->mm.free_list));
>   	GEM_BUG_ON(atomic_read(&dev_priv->mm.free_count));
>   	WARN_ON(dev_priv->mm.object_count);
> -
> -	mutex_lock(&dev_priv->drm.struct_mutex);
> -	i915_gem_timeline_fini(&dev_priv->gt.legacy_timeline);
> -	i915_gem_timeline_fini(&dev_priv->gt.execution_timeline);
>   	WARN_ON(!list_empty(&dev_priv->gt.timelines));
> -	mutex_unlock(&dev_priv->drm.struct_mutex);
>   
>   	kmem_cache_destroy(dev_priv->priorities);
>   	kmem_cache_destroy(dev_priv->dependencies);
> diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
> index 58b185abe652..027b7ddae1d3 100644
> --- a/drivers/gpu/drm/i915/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/i915_gem_context.c
> @@ -122,7 +122,6 @@ static void i915_gem_context_free(struct i915_gem_context *ctx)
>   	lockdep_assert_held(&ctx->i915->drm.struct_mutex);
>   	GEM_BUG_ON(!i915_gem_context_is_closed(ctx));
>   
> -	i915_gem_timeline_free(ctx->timeline);
>   	i915_ppgtt_put(ctx->ppgtt);
>   
>   	for (i = 0; i < I915_NUM_ENGINES; i++) {
> @@ -377,18 +376,6 @@ i915_gem_create_context(struct drm_i915_private *dev_priv,
>   		ctx->desc_template = default_desc_template(dev_priv, ppgtt);
>   	}
>   
> -	if (HAS_EXECLISTS(dev_priv)) {
> -		struct i915_gem_timeline *timeline;
> -
> -		timeline = i915_gem_timeline_create(dev_priv, ctx->name);
> -		if (IS_ERR(timeline)) {
> -			__destroy_hw_context(ctx, file_priv);
> -			return ERR_CAST(timeline);
> -		}
> -
> -		ctx->timeline = timeline;
> -	}
> -
>   	trace_i915_context_create(ctx);
>   
>   	return ctx;
> @@ -590,21 +577,30 @@ void i915_gem_context_close(struct drm_file *file)
>   	idr_destroy(&file_priv->context_idr);
>   }
>   
> -static bool engine_has_idle_kernel_context(struct intel_engine_cs *engine)
> +static struct i915_request *
> +last_timeline_request(struct i915_timeline *timeline,
> +		      struct intel_engine_cs *engine)
>   {
> -	struct i915_gem_timeline *timeline;
> +	struct i915_request *rq;
>   
> -	list_for_each_entry(timeline, &engine->i915->gt.timelines, link) {
> -		struct intel_timeline *tl;
> +	if (timeline == &engine->timeline)
> +		return NULL;

Is there still use to keep engine timelines on the i915->gt.timelines list?

>   
> -		if (timeline == &engine->i915->gt.execution_timeline)
> -			continue;
> +	rq = i915_gem_active_raw(&timeline->last_request,
> +				 &engine->i915->drm.struct_mutex);
> +	if (rq && rq->engine == engine)
> +		return rq;
> +
> +	return NULL;
> +}
>   
> -		tl = &timeline->engine[engine->id];
> -		if (i915_gem_active_peek(&tl->last_request,
> -					 &engine->i915->drm.struct_mutex))
> +static bool engine_has_idle_kernel_context(struct intel_engine_cs *engine)
> +{
> +	struct i915_timeline *timeline;
> +
> +	list_for_each_entry(timeline, &engine->i915->gt.timelines, link)
> +		if (last_timeline_request(timeline, engine))
>   			return false;
> -	}
>   
>   	return intel_engine_has_kernel_context(engine);
>   }
> @@ -612,7 +608,7 @@ static bool engine_has_idle_kernel_context(struct intel_engine_cs *engine)
>   int i915_gem_switch_to_kernel_context(struct drm_i915_private *dev_priv)
>   {
>   	struct intel_engine_cs *engine;
> -	struct i915_gem_timeline *timeline;
> +	struct i915_timeline *timeline;
>   	enum intel_engine_id id;
>   
>   	lockdep_assert_held(&dev_priv->drm.struct_mutex);
> @@ -632,11 +628,8 @@ int i915_gem_switch_to_kernel_context(struct drm_i915_private *dev_priv)
>   		/* Queue this switch after all other activity */
>   		list_for_each_entry(timeline, &dev_priv->gt.timelines, link) {
>   			struct i915_request *prev;
> -			struct intel_timeline *tl;
>   
> -			tl = &timeline->engine[engine->id];
> -			prev = i915_gem_active_raw(&tl->last_request,
> -						   &dev_priv->drm.struct_mutex);
> +			prev = last_timeline_request(timeline, engine);
>   			if (prev)
>   				i915_sw_fence_await_sw_fence_gfp(&rq->submit,
>   								 &prev->submit,
> diff --git a/drivers/gpu/drm/i915/i915_gem_context.h b/drivers/gpu/drm/i915/i915_gem_context.h
> index 140edcb424df..b12a8a8c5af9 100644
> --- a/drivers/gpu/drm/i915/i915_gem_context.h
> +++ b/drivers/gpu/drm/i915/i915_gem_context.h
> @@ -58,8 +58,6 @@ struct i915_gem_context {
>   	/** file_priv: owning file descriptor */
>   	struct drm_i915_file_private *file_priv;
>   
> -	struct i915_gem_timeline *timeline;
> -
>   	/**
>   	 * @ppgtt: unique address space (GTT)
>   	 *
> diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h
> index 98107925de48..1db0dedb4059 100644
> --- a/drivers/gpu/drm/i915/i915_gem_gtt.h
> +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h
> @@ -38,10 +38,9 @@
>   #include <linux/mm.h>
>   #include <linux/pagevec.h>
>   
> -#include "i915_gem_timeline.h"
> -
>   #include "i915_request.h"
>   #include "i915_selftest.h"
> +#include "i915_timeline.h"
>   
>   #define I915_GTT_PAGE_SIZE_4K BIT(12)
>   #define I915_GTT_PAGE_SIZE_64K BIT(16)
> diff --git a/drivers/gpu/drm/i915/i915_gem_timeline.c b/drivers/gpu/drm/i915/i915_gem_timeline.c
> deleted file mode 100644
> index 24f4068cc137..000000000000
> --- a/drivers/gpu/drm/i915/i915_gem_timeline.c
> +++ /dev/null
> @@ -1,198 +0,0 @@
> -/*
> - * Copyright © 2016 Intel Corporation
> - *
> - * Permission is hereby granted, free of charge, to any person obtaining a
> - * copy of this software and associated documentation files (the "Software"),
> - * to deal in the Software without restriction, including without limitation
> - * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> - * and/or sell copies of the Software, and to permit persons to whom the
> - * Software is furnished to do so, subject to the following conditions:
> - *
> - * The above copyright notice and this permission notice (including the next
> - * paragraph) shall be included in all copies or substantial portions of the
> - * Software.
> - *
> - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> - * IN THE SOFTWARE.
> - *
> - */
> -
> -#include "i915_drv.h"
> -#include "i915_syncmap.h"
> -
> -static void __intel_timeline_init(struct intel_timeline *tl,
> -				  struct i915_gem_timeline *parent,
> -				  u64 context,
> -				  struct lock_class_key *lockclass,
> -				  const char *lockname)
> -{
> -	tl->fence_context = context;
> -	tl->common = parent;
> -	spin_lock_init(&tl->lock);
> -	lockdep_set_class_and_name(&tl->lock, lockclass, lockname);
> -	init_request_active(&tl->last_request, NULL);
> -	INIT_LIST_HEAD(&tl->requests);
> -	i915_syncmap_init(&tl->sync);
> -}
> -
> -static void __intel_timeline_fini(struct intel_timeline *tl)
> -{
> -	GEM_BUG_ON(!list_empty(&tl->requests));
> -
> -	i915_syncmap_free(&tl->sync);
> -}
> -
> -static int __i915_gem_timeline_init(struct drm_i915_private *i915,
> -				    struct i915_gem_timeline *timeline,
> -				    const char *name,
> -				    struct lock_class_key *lockclass,
> -				    const char *lockname)
> -{
> -	unsigned int i;
> -	u64 fences;
> -
> -	lockdep_assert_held(&i915->drm.struct_mutex);
> -
> -	/*
> -	 * Ideally we want a set of engines on a single leaf as we expect
> -	 * to mostly be tracking synchronisation between engines. It is not
> -	 * a huge issue if this is not the case, but we may want to mitigate
> -	 * any page crossing penalties if they become an issue.
> -	 */
> -	BUILD_BUG_ON(KSYNCMAP < I915_NUM_ENGINES);
> -
> -	timeline->i915 = i915;
> -	timeline->name = kstrdup(name ?: "[kernel]", GFP_KERNEL);
> -	if (!timeline->name)
> -		return -ENOMEM;
> -
> -	list_add(&timeline->link, &i915->gt.timelines);
> -
> -	/* Called during early_init before we know how many engines there are */
> -	fences = dma_fence_context_alloc(ARRAY_SIZE(timeline->engine));
> -	for (i = 0; i < ARRAY_SIZE(timeline->engine); i++)
> -		__intel_timeline_init(&timeline->engine[i],
> -				      timeline, fences++,
> -				      lockclass, lockname);
> -
> -	return 0;
> -}
> -
> -int i915_gem_timeline_init(struct drm_i915_private *i915,
> -			   struct i915_gem_timeline *timeline,
> -			   const char *name)
> -{
> -	static struct lock_class_key class;
> -
> -	return __i915_gem_timeline_init(i915, timeline, name,
> -					&class, "&timeline->lock");
> -}
> -
> -int i915_gem_timeline_init__global(struct drm_i915_private *i915)
> -{
> -	static struct lock_class_key class1, class2;
> -	int err;
> -
> -	err = __i915_gem_timeline_init(i915,
> -				       &i915->gt.execution_timeline,
> -				       "[execution]", &class1,
> -				       "i915_execution_timeline");
> -	if (err)
> -		return err;
> -
> -	err = __i915_gem_timeline_init(i915,
> -				       &i915->gt.legacy_timeline,
> -				       "[global]", &class2,
> -				       "i915_global_timeline");
> -	if (err)
> -		goto err_exec_timeline;
> -
> -	return 0;
> -
> -err_exec_timeline:
> -	i915_gem_timeline_fini(&i915->gt.execution_timeline);
> -	return err;
> -}
> -
> -/**
> - * i915_gem_timelines_park - called when the driver idles
> - * @i915: the drm_i915_private device
> - *
> - * When the driver is completely idle, we know that all of our sync points
> - * have been signaled and our tracking is then entirely redundant. Any request
> - * to wait upon an older sync point will be completed instantly as we know
> - * the fence is signaled and therefore we will not even look them up in the
> - * sync point map.
> - */
> -void i915_gem_timelines_park(struct drm_i915_private *i915)
> -{
> -	struct i915_gem_timeline *timeline;
> -	int i;
> -
> -	lockdep_assert_held(&i915->drm.struct_mutex);
> -
> -	list_for_each_entry(timeline, &i915->gt.timelines, link) {
> -		for (i = 0; i < ARRAY_SIZE(timeline->engine); i++) {
> -			struct intel_timeline *tl = &timeline->engine[i];
> -
> -			/*
> -			 * All known fences are completed so we can scrap
> -			 * the current sync point tracking and start afresh,
> -			 * any attempt to wait upon a previous sync point
> -			 * will be skipped as the fence was signaled.
> -			 */
> -			i915_syncmap_free(&tl->sync);
> -		}
> -	}
> -}
> -
> -void i915_gem_timeline_fini(struct i915_gem_timeline *timeline)
> -{
> -	int i;
> -
> -	lockdep_assert_held(&timeline->i915->drm.struct_mutex);
> -
> -	for (i = 0; i < ARRAY_SIZE(timeline->engine); i++)
> -		__intel_timeline_fini(&timeline->engine[i]);
> -
> -	list_del(&timeline->link);
> -	kfree(timeline->name);
> -}
> -
> -struct i915_gem_timeline *
> -i915_gem_timeline_create(struct drm_i915_private *i915, const char *name)
> -{
> -	struct i915_gem_timeline *timeline;
> -	int err;
> -
> -	timeline = kzalloc(sizeof(*timeline), GFP_KERNEL);
> -	if (!timeline)
> -		return ERR_PTR(-ENOMEM);
> -
> -	err = i915_gem_timeline_init(i915, timeline, name);
> -	if (err) {
> -		kfree(timeline);
> -		return ERR_PTR(err);
> -	}
> -
> -	return timeline;
> -}
> -
> -void i915_gem_timeline_free(struct i915_gem_timeline *timeline)
> -{
> -	if (!timeline)
> -		return;
> -
> -	i915_gem_timeline_fini(timeline);
> -	kfree(timeline);
> -}
> -
> -#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
> -#include "selftests/mock_timeline.c"
> -#include "selftests/i915_gem_timeline.c"
> -#endif
> diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c
> index 671ffa37614e..71bb8230cb97 100644
> --- a/drivers/gpu/drm/i915/i915_gpu_error.c
> +++ b/drivers/gpu/drm/i915/i915_gpu_error.c
> @@ -1299,7 +1299,7 @@ static void engine_record_requests(struct intel_engine_cs *engine,
>   
>   	count = 0;
>   	request = first;
> -	list_for_each_entry_from(request, &engine->timeline->requests, link)
> +	list_for_each_entry_from(request, &engine->timeline.requests, link)
>   		count++;
>   	if (!count)
>   		return;
> @@ -1312,7 +1312,7 @@ static void engine_record_requests(struct intel_engine_cs *engine,
>   
>   	count = 0;
>   	request = first;
> -	list_for_each_entry_from(request, &engine->timeline->requests, link) {
> +	list_for_each_entry_from(request, &engine->timeline.requests, link) {
>   		if (count >= ee->num_requests) {
>   			/*
>   			 * If the ring request list was changed in
> diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c
> index bfc906cd4e5e..5dcd76e27c68 100644
> --- a/drivers/gpu/drm/i915/i915_perf.c
> +++ b/drivers/gpu/drm/i915/i915_perf.c
> @@ -1695,7 +1695,7 @@ static int gen8_switch_to_updated_kernel_context(struct drm_i915_private *dev_pr
>   						 const struct i915_oa_config *oa_config)
>   {
>   	struct intel_engine_cs *engine = dev_priv->engine[RCS];
> -	struct i915_gem_timeline *timeline;
> +	struct i915_timeline *timeline;
>   	struct i915_request *rq;
>   	int ret;
>   
> @@ -1716,15 +1716,11 @@ static int gen8_switch_to_updated_kernel_context(struct drm_i915_private *dev_pr
>   	/* Queue this switch after all other activity */
>   	list_for_each_entry(timeline, &dev_priv->gt.timelines, link) {
>   		struct i915_request *prev;
> -		struct intel_timeline *tl;
>   
> -		tl = &timeline->engine[engine->id];
> -		prev = i915_gem_active_raw(&tl->last_request,
> +		prev = i915_gem_active_raw(&timeline->last_request,
>   					   &dev_priv->drm.struct_mutex);
>   		if (prev)
> -			i915_sw_fence_await_sw_fence_gfp(&rq->submit,
> -							 &prev->submit,
> -							 GFP_KERNEL);
> +			i915_request_await_dma_fence(rq, &prev->fence);
>   	}
>   
>   	i915_request_add(rq);
> diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c
> index 35869afdb199..4e6c1022519c 100644
> --- a/drivers/gpu/drm/i915/i915_request.c
> +++ b/drivers/gpu/drm/i915/i915_request.c
> @@ -49,7 +49,7 @@ static const char *i915_fence_get_timeline_name(struct dma_fence *fence)
>   	if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags))
>   		return "signaled";
>   
> -	return to_request(fence)->timeline->common->name;
> +	return to_request(fence)->timeline->name;
>   }
>   
>   static bool i915_fence_signaled(struct dma_fence *fence)
> @@ -199,6 +199,7 @@ i915_sched_node_init(struct i915_sched_node *node)
>   static int reset_all_global_seqno(struct drm_i915_private *i915, u32 seqno)
>   {
>   	struct intel_engine_cs *engine;
> +	struct i915_timeline *timeline;
>   	enum intel_engine_id id;
>   	int ret;
>   
> @@ -213,16 +214,13 @@ static int reset_all_global_seqno(struct drm_i915_private *i915, u32 seqno)
>   
>   	/* If the seqno wraps around, we need to clear the breadcrumb rbtree */
>   	for_each_engine(engine, i915, id) {
> -		struct i915_gem_timeline *timeline;
> -		struct intel_timeline *tl = engine->timeline;
> -
>   		GEM_TRACE("%s seqno %d (current %d) -> %d\n",
>   			  engine->name,
> -			  tl->seqno,
> +			  engine->timeline.seqno,
>   			  intel_engine_get_seqno(engine),
>   			  seqno);
>   
> -		if (!i915_seqno_passed(seqno, tl->seqno)) {
> +		if (!i915_seqno_passed(seqno, engine->timeline.seqno)) {
>   			/* Flush any waiters before we reuse the seqno */
>   			intel_engine_disarm_breadcrumbs(engine);
>   			GEM_BUG_ON(!list_empty(&engine->breadcrumbs.signals));
> @@ -230,17 +228,16 @@ static int reset_all_global_seqno(struct drm_i915_private *i915, u32 seqno)
>   
>   		/* Check we are idle before we fiddle with hw state! */
>   		GEM_BUG_ON(!intel_engine_is_idle(engine));
> -		GEM_BUG_ON(i915_gem_active_isset(&engine->timeline->last_request));
> +		GEM_BUG_ON(i915_gem_active_isset(&engine->timeline.last_request));
>   
>   		/* Finally reset hw state */
>   		intel_engine_init_global_seqno(engine, seqno);
> -		tl->seqno = seqno;
> -
> -		list_for_each_entry(timeline, &i915->gt.timelines, link)
> -			memset(timeline->engine[id].global_sync, 0,
> -			       sizeof(timeline->engine[id].global_sync));
> +		engine->timeline.seqno = seqno;
>   	}
>   
> +	list_for_each_entry(timeline, &i915->gt.timelines, link)
> +		memset(timeline->global_sync, 0, sizeof(timeline->global_sync));
> +
>   	return 0;
>   }
>   
> @@ -263,7 +260,7 @@ static int reserve_engine(struct intel_engine_cs *engine)
>   	int ret;
>   
>   	/* Reservation is fine until we need to wrap around */
> -	if (unlikely(add_overflows(engine->timeline->seqno,
> +	if (unlikely(add_overflows(engine->timeline.seqno,
>   				   i915->gt.active_requests + 1))) {
>   		ret = reset_all_global_seqno(i915, 0);
>   		if (ret)
> @@ -356,9 +353,9 @@ static void i915_request_retire(struct i915_request *request)
>   
>   	trace_i915_request_retire(request);
>   
> -	spin_lock_irq(&engine->timeline->lock);
> +	spin_lock_irq(&engine->timeline.lock);
>   	list_del_init(&request->link);
> -	spin_unlock_irq(&engine->timeline->lock);
> +	spin_unlock_irq(&engine->timeline.lock);
>   
>   	unreserve_engine(request->engine);
>   	advance_ring(request);
> @@ -445,16 +442,16 @@ void i915_request_retire_upto(struct i915_request *rq)
>   	} while (tmp != rq);
>   }
>   
> -static u32 timeline_get_seqno(struct intel_timeline *tl)
> +static u32 timeline_get_seqno(struct i915_timeline *tl)
>   {
>   	return ++tl->seqno;
>   }
>   
>   static void move_to_timeline(struct i915_request *request,
> -			     struct intel_timeline *timeline)
> +			     struct i915_timeline *timeline)
>   {
> -	GEM_BUG_ON(request->timeline == request->engine->timeline);
> -	lockdep_assert_held(&request->engine->timeline->lock);
> +	GEM_BUG_ON(request->timeline == &request->engine->timeline);
> +	lockdep_assert_held(&request->engine->timeline.lock);
>   
>   	spin_lock(&request->timeline->lock);
>   	list_move_tail(&request->link, &timeline->requests);
> @@ -469,15 +466,15 @@ void __i915_request_submit(struct i915_request *request)
>   	GEM_TRACE("%s fence %llx:%d -> global=%d, current %d\n",
>   		  engine->name,
>   		  request->fence.context, request->fence.seqno,
> -		  engine->timeline->seqno + 1,
> +		  engine->timeline.seqno + 1,
>   		  intel_engine_get_seqno(engine));
>   
>   	GEM_BUG_ON(!irqs_disabled());
> -	lockdep_assert_held(&engine->timeline->lock);
> +	lockdep_assert_held(&engine->timeline.lock);
>   
>   	GEM_BUG_ON(request->global_seqno);
>   
> -	seqno = timeline_get_seqno(engine->timeline);
> +	seqno = timeline_get_seqno(&engine->timeline);
>   	GEM_BUG_ON(!seqno);
>   	GEM_BUG_ON(i915_seqno_passed(intel_engine_get_seqno(engine), seqno));
>   
> @@ -492,7 +489,7 @@ void __i915_request_submit(struct i915_request *request)
>   				request->ring->vaddr + request->postfix);
>   
>   	/* Transfer from per-context onto the global per-engine timeline */
> -	move_to_timeline(request, engine->timeline);
> +	move_to_timeline(request, &engine->timeline);
>   
>   	trace_i915_request_execute(request);
>   
> @@ -505,11 +502,11 @@ void i915_request_submit(struct i915_request *request)
>   	unsigned long flags;
>   
>   	/* Will be called from irq-context when using foreign fences. */
> -	spin_lock_irqsave(&engine->timeline->lock, flags);
> +	spin_lock_irqsave(&engine->timeline.lock, flags);
>   
>   	__i915_request_submit(request);
>   
> -	spin_unlock_irqrestore(&engine->timeline->lock, flags);
> +	spin_unlock_irqrestore(&engine->timeline.lock, flags);
>   }
>   
>   void __i915_request_unsubmit(struct i915_request *request)
> @@ -523,17 +520,17 @@ void __i915_request_unsubmit(struct i915_request *request)
>   		  intel_engine_get_seqno(engine));
>   
>   	GEM_BUG_ON(!irqs_disabled());
> -	lockdep_assert_held(&engine->timeline->lock);
> +	lockdep_assert_held(&engine->timeline.lock);
>   
>   	/*
>   	 * Only unwind in reverse order, required so that the per-context list
>   	 * is kept in seqno/ring order.
>   	 */
>   	GEM_BUG_ON(!request->global_seqno);
> -	GEM_BUG_ON(request->global_seqno != engine->timeline->seqno);
> +	GEM_BUG_ON(request->global_seqno != engine->timeline.seqno);
>   	GEM_BUG_ON(i915_seqno_passed(intel_engine_get_seqno(engine),
>   				     request->global_seqno));
> -	engine->timeline->seqno--;
> +	engine->timeline.seqno--;
>   
>   	/* We may be recursing from the signal callback of another i915 fence */
>   	spin_lock_nested(&request->lock, SINGLE_DEPTH_NESTING);
> @@ -560,11 +557,11 @@ void i915_request_unsubmit(struct i915_request *request)
>   	unsigned long flags;
>   
>   	/* Will be called from irq-context when using foreign fences. */
> -	spin_lock_irqsave(&engine->timeline->lock, flags);
> +	spin_lock_irqsave(&engine->timeline.lock, flags);
>   
>   	__i915_request_unsubmit(request);
>   
> -	spin_unlock_irqrestore(&engine->timeline->lock, flags);
> +	spin_unlock_irqrestore(&engine->timeline.lock, flags);
>   }
>   
>   static int __i915_sw_fence_call
> @@ -639,7 +636,7 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx)
>   	if (IS_ERR(ring))
>   		return ERR_CAST(ring);
>   	GEM_BUG_ON(!ring);
> -	GEM_BUG_ON(ring->timeline == engine->timeline);
> +	GEM_BUG_ON(ring->timeline == &engine->timeline);
>   
>   	ret = reserve_engine(engine);
>   	if (ret)
> @@ -879,7 +876,7 @@ i915_request_await_dma_fence(struct i915_request *rq, struct dma_fence *fence)
>   
>   		/* Squash repeated waits to the same timelines */
>   		if (fence->context != rq->i915->mm.unordered_timeline &&
> -		    intel_timeline_sync_is_later(rq->timeline, fence))
> +		    i915_timeline_sync_is_later(rq->timeline, fence))
>   			continue;
>   
>   		if (dma_fence_is_i915(fence))
> @@ -893,7 +890,7 @@ i915_request_await_dma_fence(struct i915_request *rq, struct dma_fence *fence)
>   
>   		/* Record the latest fence used against each timeline */
>   		if (fence->context != rq->i915->mm.unordered_timeline)
> -			intel_timeline_sync_set(rq->timeline, fence);
> +			i915_timeline_sync_set(rq->timeline, fence);
>   	} while (--nchild);
>   
>   	return 0;
> @@ -970,7 +967,7 @@ void __i915_request_add(struct i915_request *request, bool flush_caches)
>   {
>   	struct intel_engine_cs *engine = request->engine;
>   	struct intel_ring *ring = request->ring;
> -	struct intel_timeline *timeline = request->timeline;
> +	struct i915_timeline *timeline = request->timeline;
>   	struct i915_request *prev;
>   	u32 *cs;
>   	int err;
> diff --git a/drivers/gpu/drm/i915/i915_request.h b/drivers/gpu/drm/i915/i915_request.h
> index 8f31ca8272f8..eddbd4245cb3 100644
> --- a/drivers/gpu/drm/i915/i915_request.h
> +++ b/drivers/gpu/drm/i915/i915_request.h
> @@ -37,6 +37,7 @@
>   struct drm_file;
>   struct drm_i915_gem_object;
>   struct i915_request;
> +struct i915_timeline;
>   
>   struct intel_wait {
>   	struct rb_node node;
> @@ -95,7 +96,7 @@ struct i915_request {
>   	struct i915_gem_context *ctx;
>   	struct intel_engine_cs *engine;
>   	struct intel_ring *ring;
> -	struct intel_timeline *timeline;
> +	struct i915_timeline *timeline;
>   	struct intel_signal_node signaling;
>   
>   	/*
> diff --git a/drivers/gpu/drm/i915/i915_timeline.c b/drivers/gpu/drm/i915/i915_timeline.c
> new file mode 100644
> index 000000000000..4667cc08c416
> --- /dev/null
> +++ b/drivers/gpu/drm/i915/i915_timeline.c
> @@ -0,0 +1,105 @@
> +/*
> + * SPDX-License-Identifier: MIT
> + *
> + * Copyright © 2016-2018 Intel Corporation
> + */
> +
> +#include "i915_drv.h"
> +
> +#include "i915_timeline.h"
> +#include "i915_syncmap.h"
> +
> +void i915_timeline_init(struct drm_i915_private *i915,
> +			struct i915_timeline *timeline,
> +			const char *name)
> +{
> +	lockdep_assert_held(&i915->drm.struct_mutex);
> +
> +	/*
> +	 * Ideally we want a set of engines on a single leaf as we expect
> +	 * to mostly be tracking synchronisation between engines. It is not
> +	 * a huge issue if this is not the case, but we may want to mitigate
> +	 * any page crossing penalties if they become an issue.
> +	 */
> +	BUILD_BUG_ON(KSYNCMAP < I915_NUM_ENGINES);
> +
> +	timeline->name = name;
> +
> +	list_add(&timeline->link, &i915->gt.timelines);
> +
> +	/* Called during early_init before we know how many engines there are */
> +
> +	timeline->fence_context = dma_fence_context_alloc(1);
> +
> +	spin_lock_init(&timeline->lock);
> +
> +	init_request_active(&timeline->last_request, NULL);
> +	INIT_LIST_HEAD(&timeline->requests);
> +
> +	i915_syncmap_init(&timeline->sync);
> +}
> +
> +/**
> + * i915_timelines_park - called when the driver idles
> + * @i915: the drm_i915_private device
> + *
> + * When the driver is completely idle, we know that all of our sync points
> + * have been signaled and our tracking is then entirely redundant. Any request
> + * to wait upon an older sync point will be completed instantly as we know
> + * the fence is signaled and therefore we will not even look them up in the
> + * sync point map.
> + */
> +void i915_timelines_park(struct drm_i915_private *i915)
> +{
> +	struct i915_timeline *timeline;
> +
> +	lockdep_assert_held(&i915->drm.struct_mutex);
> +
> +	list_for_each_entry(timeline, &i915->gt.timelines, link) {
> +		/*
> +		 * All known fences are completed so we can scrap
> +		 * the current sync point tracking and start afresh,
> +		 * any attempt to wait upon a previous sync point
> +		 * will be skipped as the fence was signaled.
> +		 */
> +		i915_syncmap_free(&timeline->sync);
> +	}
> +}
> +
> +void i915_timeline_fini(struct i915_timeline *timeline)
> +{
> +	GEM_BUG_ON(!list_empty(&timeline->requests));
> +
> +	i915_syncmap_free(&timeline->sync);
> +
> +	list_del(&timeline->link);
> +}
> +
> +struct i915_timeline *
> +i915_timeline_create(struct drm_i915_private *i915, const char *name)
> +{
> +	struct i915_timeline *timeline;
> +
> +	timeline = kzalloc(sizeof(*timeline), GFP_KERNEL);
> +	if (!timeline)
> +		return ERR_PTR(-ENOMEM);
> +
> +	i915_timeline_init(i915, timeline, name);
> +	kref_init(&timeline->kref);
> +
> +	return timeline;
> +}
> +
> +void __i915_timeline_free(struct kref *kref)
> +{
> +	struct i915_timeline *timeline =
> +		container_of(kref, typeof(*timeline), kref);
> +
> +	i915_timeline_fini(timeline);
> +	kfree(timeline);
> +}
> +
> +#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
> +#include "selftests/mock_timeline.c"
> +#include "selftests/i915_timeline.c"
> +#endif
> diff --git a/drivers/gpu/drm/i915/i915_gem_timeline.h b/drivers/gpu/drm/i915/i915_timeline.h
> similarity index 68%
> rename from drivers/gpu/drm/i915/i915_gem_timeline.h
> rename to drivers/gpu/drm/i915/i915_timeline.h
> index 780ed465c4fc..dc2a4632faa7 100644
> --- a/drivers/gpu/drm/i915/i915_gem_timeline.h
> +++ b/drivers/gpu/drm/i915/i915_timeline.h
> @@ -22,18 +22,17 @@
>    *
>    */
>   
> -#ifndef I915_GEM_TIMELINE_H
> -#define I915_GEM_TIMELINE_H
> +#ifndef I915_TIMELINE_H
> +#define I915_TIMELINE_H
>   
>   #include <linux/list.h>
> +#include <linux/kref.h>
>   
>   #include "i915_request.h"
>   #include "i915_syncmap.h"
>   #include "i915_utils.h"
>   
> -struct i915_gem_timeline;
> -
> -struct intel_timeline {
> +struct i915_timeline {
>   	u64 fence_context;
>   	u32 seqno;
>   
> @@ -71,51 +70,57 @@ struct intel_timeline {
>   	 */
>   	u32 global_sync[I915_NUM_ENGINES];
>   
> -	struct i915_gem_timeline *common;
> -};
> -
> -struct i915_gem_timeline {
>   	struct list_head link;
> -
> -	struct drm_i915_private *i915;
>   	const char *name;
>   
> -	struct intel_timeline engine[I915_NUM_ENGINES];
> +	struct kref kref;
>   };
>   
> -int i915_gem_timeline_init(struct drm_i915_private *i915,
> -			   struct i915_gem_timeline *tl,
> -			   const char *name);
> -int i915_gem_timeline_init__global(struct drm_i915_private *i915);
> -void i915_gem_timelines_park(struct drm_i915_private *i915);
> -void i915_gem_timeline_fini(struct i915_gem_timeline *tl);
> +void i915_timeline_init(struct drm_i915_private *i915,
> +			struct i915_timeline *tl,
> +			const char *name);
> +void i915_timeline_fini(struct i915_timeline *tl);
>   
> -struct i915_gem_timeline *
> -i915_gem_timeline_create(struct drm_i915_private *i915, const char *name);
> -void i915_gem_timeline_free(struct i915_gem_timeline *timeline);
> +struct i915_timeline *
> +i915_timeline_create(struct drm_i915_private *i915, const char *name);
>   
> -static inline int __intel_timeline_sync_set(struct intel_timeline *tl,
> -					    u64 context, u32 seqno)
> +static inline struct i915_timeline *
> +i915_timeline_get(struct i915_timeline *timeline)
> +{
> +	kref_get(&timeline->kref);
> +	return timeline;
> +}
> +
> +void __i915_timeline_free(struct kref *kref);
> +static inline void i915_timeline_put(struct i915_timeline *timeline)
> +{
> +	kref_put(&timeline->kref, __i915_timeline_free);
> +}
> +
> +static inline int __i915_timeline_sync_set(struct i915_timeline *tl,
> +					   u64 context, u32 seqno)
>   {
>   	return i915_syncmap_set(&tl->sync, context, seqno);
>   }
>   
> -static inline int intel_timeline_sync_set(struct intel_timeline *tl,
> -					  const struct dma_fence *fence)
> +static inline int i915_timeline_sync_set(struct i915_timeline *tl,
> +					 const struct dma_fence *fence)
>   {
> -	return __intel_timeline_sync_set(tl, fence->context, fence->seqno);
> +	return __i915_timeline_sync_set(tl, fence->context, fence->seqno);
>   }
>   
> -static inline bool __intel_timeline_sync_is_later(struct intel_timeline *tl,
> -						  u64 context, u32 seqno)
> +static inline bool __i915_timeline_sync_is_later(struct i915_timeline *tl,
> +						 u64 context, u32 seqno)
>   {
>   	return i915_syncmap_is_later(&tl->sync, context, seqno);
>   }
>   
> -static inline bool intel_timeline_sync_is_later(struct intel_timeline *tl,
> -						const struct dma_fence *fence)
> +static inline bool i915_timeline_sync_is_later(struct i915_timeline *tl,
> +					       const struct dma_fence *fence)
>   {
> -	return __intel_timeline_sync_is_later(tl, fence->context, fence->seqno);
> +	return __i915_timeline_sync_is_later(tl, fence->context, fence->seqno);
>   }
>   
> +void i915_timelines_park(struct drm_i915_private *i915);
> +
>   #endif
> diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c
> index d44a8eb83379..dcfdd4439935 100644
> --- a/drivers/gpu/drm/i915/intel_engine_cs.c
> +++ b/drivers/gpu/drm/i915/intel_engine_cs.c
> @@ -451,12 +451,6 @@ void intel_engine_init_global_seqno(struct intel_engine_cs *engine, u32 seqno)
>   	GEM_BUG_ON(intel_engine_get_seqno(engine) != seqno);
>   }
>   
> -static void intel_engine_init_timeline(struct intel_engine_cs *engine)
> -{
> -	engine->timeline =
> -		&engine->i915->gt.execution_timeline.engine[engine->id];
> -}
> -
>   static void intel_engine_init_batch_pool(struct intel_engine_cs *engine)
>   {
>   	i915_gem_batch_pool_init(&engine->batch_pool, engine);
> @@ -508,8 +502,9 @@ static void intel_engine_init_execlist(struct intel_engine_cs *engine)
>    */
>   void intel_engine_setup_common(struct intel_engine_cs *engine)
>   {
> +	i915_timeline_init(engine->i915, &engine->timeline, engine->name);
> +
>   	intel_engine_init_execlist(engine);
> -	intel_engine_init_timeline(engine);
>   	intel_engine_init_hangcheck(engine);
>   	intel_engine_init_batch_pool(engine);
>   	intel_engine_init_cmd_parser(engine);
> @@ -757,6 +752,8 @@ void intel_engine_cleanup_common(struct intel_engine_cs *engine)
>   	if (engine->i915->preempt_context)
>   		engine->context_unpin(engine, engine->i915->preempt_context);
>   	engine->context_unpin(engine, engine->i915->kernel_context);
> +
> +	i915_timeline_fini(&engine->timeline);
>   }
>   
>   u64 intel_engine_get_active_head(const struct intel_engine_cs *engine)
> @@ -1009,7 +1006,7 @@ bool intel_engine_has_kernel_context(const struct intel_engine_cs *engine)
>   	 * the last request that remains in the timeline. When idle, it is
>   	 * the last executed context as tracked by retirement.
>   	 */
> -	rq = __i915_gem_active_peek(&engine->timeline->last_request);
> +	rq = __i915_gem_active_peek(&engine->timeline.last_request);
>   	if (rq)
>   		return rq->ctx == kernel_context;
>   	else
> @@ -1332,14 +1329,14 @@ void intel_engine_dump(struct intel_engine_cs *engine,
>   
>   	drm_printf(m, "\tRequests:\n");
>   
> -	rq = list_first_entry(&engine->timeline->requests,
> +	rq = list_first_entry(&engine->timeline.requests,
>   			      struct i915_request, link);
> -	if (&rq->link != &engine->timeline->requests)
> +	if (&rq->link != &engine->timeline.requests)
>   		print_request(m, rq, "\t\tfirst  ");
>   
> -	rq = list_last_entry(&engine->timeline->requests,
> +	rq = list_last_entry(&engine->timeline.requests,
>   			     struct i915_request, link);
> -	if (&rq->link != &engine->timeline->requests)
> +	if (&rq->link != &engine->timeline.requests)
>   		print_request(m, rq, "\t\tlast   ");
>   
>   	rq = i915_gem_find_active_request(engine);
> @@ -1371,8 +1368,8 @@ void intel_engine_dump(struct intel_engine_cs *engine,
>   		drm_printf(m, "\tDevice is asleep; skipping register dump\n");
>   	}
>   
> -	spin_lock_irq(&engine->timeline->lock);
> -	list_for_each_entry(rq, &engine->timeline->requests, link)
> +	spin_lock_irq(&engine->timeline.lock);
> +	list_for_each_entry(rq, &engine->timeline.requests, link)
>   		print_request(m, rq, "\t\tE ");
>   	drm_printf(m, "\t\tQueue priority: %d\n", execlists->queue_priority);
>   	for (rb = execlists->first; rb; rb = rb_next(rb)) {
> @@ -1382,7 +1379,7 @@ void intel_engine_dump(struct intel_engine_cs *engine,
>   		list_for_each_entry(rq, &p->requests, sched.link)
>   			print_request(m, rq, "\t\tQ ");
>   	}
> -	spin_unlock_irq(&engine->timeline->lock);
> +	spin_unlock_irq(&engine->timeline.lock);
>   
>   	spin_lock_irq(&b->rb_lock);
>   	for (rb = rb_first(&b->waiters); rb; rb = rb_next(rb)) {
> diff --git a/drivers/gpu/drm/i915/intel_guc_submission.c b/drivers/gpu/drm/i915/intel_guc_submission.c
> index 02da05875aa7..cb4fcde1ffdc 100644
> --- a/drivers/gpu/drm/i915/intel_guc_submission.c
> +++ b/drivers/gpu/drm/i915/intel_guc_submission.c
> @@ -677,7 +677,7 @@ static void guc_dequeue(struct intel_engine_cs *engine)
>   	bool submit = false;
>   	struct rb_node *rb;
>   
> -	spin_lock_irq(&engine->timeline->lock);
> +	spin_lock_irq(&engine->timeline.lock);
>   	rb = execlists->first;
>   	GEM_BUG_ON(rb_first(&execlists->queue) != rb);
>   
> @@ -748,7 +748,7 @@ static void guc_dequeue(struct intel_engine_cs *engine)
>   	GEM_BUG_ON(execlists->first && !port_isset(execlists->port));
>   
>   unlock:
> -	spin_unlock_irq(&engine->timeline->lock);
> +	spin_unlock_irq(&engine->timeline.lock);
>   }
>   
>   static void guc_submission_tasklet(unsigned long data)
> diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
> index fd3539034665..fa802d791804 100644
> --- a/drivers/gpu/drm/i915/intel_lrc.c
> +++ b/drivers/gpu/drm/i915/intel_lrc.c
> @@ -330,10 +330,10 @@ static void __unwind_incomplete_requests(struct intel_engine_cs *engine)
>   	struct i915_priolist *uninitialized_var(p);
>   	int last_prio = I915_PRIORITY_INVALID;
>   
> -	lockdep_assert_held(&engine->timeline->lock);
> +	lockdep_assert_held(&engine->timeline.lock);
>   
>   	list_for_each_entry_safe_reverse(rq, rn,
> -					 &engine->timeline->requests,
> +					 &engine->timeline.requests,
>   					 link) {
>   		if (i915_request_completed(rq))
>   			return;
> @@ -357,9 +357,9 @@ execlists_unwind_incomplete_requests(struct intel_engine_execlists *execlists)
>   	struct intel_engine_cs *engine =
>   		container_of(execlists, typeof(*engine), execlists);
>   
> -	spin_lock_irq(&engine->timeline->lock);
> +	spin_lock_irq(&engine->timeline.lock);
>   	__unwind_incomplete_requests(engine);
> -	spin_unlock_irq(&engine->timeline->lock);
> +	spin_unlock_irq(&engine->timeline.lock);
>   }
>   
>   static inline void
> @@ -583,7 +583,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
>   	 * and context switches) submission.
>   	 */
>   
> -	spin_lock_irq(&engine->timeline->lock);
> +	spin_lock_irq(&engine->timeline.lock);
>   	rb = execlists->first;
>   	GEM_BUG_ON(rb_first(&execlists->queue) != rb);
>   
> @@ -743,7 +743,7 @@ static void execlists_dequeue(struct intel_engine_cs *engine)
>   	GEM_BUG_ON(execlists->first && !port_isset(execlists->port));
>   
>   unlock:
> -	spin_unlock_irq(&engine->timeline->lock);
> +	spin_unlock_irq(&engine->timeline.lock);
>   
>   	if (submit) {
>   		execlists_user_begin(execlists, execlists->port);
> @@ -868,10 +868,10 @@ static void execlists_cancel_requests(struct intel_engine_cs *engine)
>   	execlists_cancel_port_requests(execlists);
>   	reset_irq(engine);
>   
> -	spin_lock(&engine->timeline->lock);
> +	spin_lock(&engine->timeline.lock);
>   
>   	/* Mark all executing requests as skipped. */
> -	list_for_each_entry(rq, &engine->timeline->requests, link) {
> +	list_for_each_entry(rq, &engine->timeline.requests, link) {
>   		GEM_BUG_ON(!rq->global_seqno);
>   		if (!i915_request_completed(rq))
>   			dma_fence_set_error(&rq->fence, -EIO);
> @@ -903,7 +903,7 @@ static void execlists_cancel_requests(struct intel_engine_cs *engine)
>   	execlists->first = NULL;
>   	GEM_BUG_ON(port_isset(execlists->port));
>   
> -	spin_unlock(&engine->timeline->lock);
> +	spin_unlock(&engine->timeline.lock);
>   
>   	local_irq_restore(flags);
>   }
> @@ -1141,7 +1141,7 @@ static void execlists_submit_request(struct i915_request *request)
>   	unsigned long flags;
>   
>   	/* Will be called from irq-context when using foreign fences. */
> -	spin_lock_irqsave(&engine->timeline->lock, flags);
> +	spin_lock_irqsave(&engine->timeline.lock, flags);
>   
>   	queue_request(engine, &request->sched, rq_prio(request));
>   	submit_queue(engine, rq_prio(request));
> @@ -1149,7 +1149,7 @@ static void execlists_submit_request(struct i915_request *request)
>   	GEM_BUG_ON(!engine->execlists.first);
>   	GEM_BUG_ON(list_empty(&request->sched.link));
>   
> -	spin_unlock_irqrestore(&engine->timeline->lock, flags);
> +	spin_unlock_irqrestore(&engine->timeline.lock, flags);
>   }
>   
>   static struct i915_request *sched_to_request(struct i915_sched_node *node)
> @@ -1165,8 +1165,8 @@ sched_lock_engine(struct i915_sched_node *node, struct intel_engine_cs *locked)
>   	GEM_BUG_ON(!locked);
>   
>   	if (engine != locked) {
> -		spin_unlock(&locked->timeline->lock);
> -		spin_lock(&engine->timeline->lock);
> +		spin_unlock(&locked->timeline.lock);
> +		spin_lock(&engine->timeline.lock);
>   	}
>   
>   	return engine;
> @@ -1249,7 +1249,7 @@ static void execlists_schedule(struct i915_request *request,
>   	}
>   
>   	engine = request->engine;
> -	spin_lock_irq(&engine->timeline->lock);
> +	spin_lock_irq(&engine->timeline.lock);
>   
>   	/* Fifo and depth-first replacement ensure our deps execute before us */
>   	list_for_each_entry_safe_reverse(dep, p, &dfs, dfs_link) {
> @@ -1273,7 +1273,7 @@ static void execlists_schedule(struct i915_request *request,
>   			__submit_queue(engine, prio);
>   	}
>   
> -	spin_unlock_irq(&engine->timeline->lock);
> +	spin_unlock_irq(&engine->timeline.lock);
>   }
>   
>   static int __context_pin(struct i915_gem_context *ctx, struct i915_vma *vma)
> @@ -1802,9 +1802,9 @@ static void reset_common_ring(struct intel_engine_cs *engine,
>   	reset_irq(engine);
>   
>   	/* Push back any incomplete requests for replay after the reset. */
> -	spin_lock(&engine->timeline->lock);
> +	spin_lock(&engine->timeline.lock);
>   	__unwind_incomplete_requests(engine);
> -	spin_unlock(&engine->timeline->lock);
> +	spin_unlock(&engine->timeline.lock);
>   
>   	local_irq_restore(flags);
>   
> @@ -2559,6 +2559,7 @@ static int execlists_context_deferred_alloc(struct i915_gem_context *ctx,
>   	struct i915_vma *vma;
>   	uint32_t context_size;
>   	struct intel_ring *ring;
> +	struct i915_timeline *timeline;
>   	int ret;
>   
>   	if (ce->state)
> @@ -2574,8 +2575,8 @@ static int execlists_context_deferred_alloc(struct i915_gem_context *ctx,
>   
>   	ctx_obj = i915_gem_object_create(ctx->i915, context_size);
>   	if (IS_ERR(ctx_obj)) {
> -		DRM_DEBUG_DRIVER("Alloc LRC backing obj failed.\n");
> -		return PTR_ERR(ctx_obj);
> +		ret = PTR_ERR(ctx_obj);
> +		goto error_deref_obj;
>   	}
>   
>   	vma = i915_vma_instance(ctx_obj, &ctx->i915->ggtt.base, NULL);
> @@ -2584,7 +2585,14 @@ static int execlists_context_deferred_alloc(struct i915_gem_context *ctx,
>   		goto error_deref_obj;
>   	}
>   
> -	ring = intel_engine_create_ring(engine, ctx->timeline, ctx->ring_size);
> +	timeline = i915_timeline_create(ctx->i915, ctx->name);
> +	if (IS_ERR(timeline)) {
> +		ret = PTR_ERR(timeline);
> +		goto error_deref_obj;
> +	}
> +
> +	ring = intel_engine_create_ring(engine, timeline, ctx->ring_size);
> +	i915_timeline_put(timeline);
>   	if (IS_ERR(ring)) {
>   		ret = PTR_ERR(ring);
>   		goto error_deref_obj;
> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
> index 4559fe1c574e..e85abfafeaf0 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.c
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
> @@ -696,17 +696,17 @@ static void cancel_requests(struct intel_engine_cs *engine)
>   	struct i915_request *request;
>   	unsigned long flags;
>   
> -	spin_lock_irqsave(&engine->timeline->lock, flags);
> +	spin_lock_irqsave(&engine->timeline.lock, flags);
>   
>   	/* Mark all submitted requests as skipped. */
> -	list_for_each_entry(request, &engine->timeline->requests, link) {
> +	list_for_each_entry(request, &engine->timeline.requests, link) {
>   		GEM_BUG_ON(!request->global_seqno);
>   		if (!i915_request_completed(request))
>   			dma_fence_set_error(&request->fence, -EIO);
>   	}
>   	/* Remaining _unready_ requests will be nop'ed when submitted */
>   
> -	spin_unlock_irqrestore(&engine->timeline->lock, flags);
> +	spin_unlock_irqrestore(&engine->timeline.lock, flags);
>   }
>   
>   static void i9xx_submit_request(struct i915_request *request)
> @@ -1118,7 +1118,7 @@ intel_ring_create_vma(struct drm_i915_private *dev_priv, int size)
>   
>   struct intel_ring *
>   intel_engine_create_ring(struct intel_engine_cs *engine,
> -			 struct i915_gem_timeline *timeline,
> +			 struct i915_timeline *timeline,
>   			 int size)
>   {
>   	struct intel_ring *ring;
> @@ -1133,7 +1133,7 @@ intel_engine_create_ring(struct intel_engine_cs *engine,
>   		return ERR_PTR(-ENOMEM);
>   
>   	INIT_LIST_HEAD(&ring->request_list);
> -	ring->timeline = &timeline->engine[engine->id];
> +	ring->timeline = i915_timeline_get(timeline);
>   
>   	ring->size = size;
>   	/* Workaround an erratum on the i830 which causes a hang if
> @@ -1164,6 +1164,7 @@ intel_ring_free(struct intel_ring *ring)
>   	i915_vma_close(ring->vma);
>   	__i915_gem_object_release_unless_active(obj);
>   
> +	i915_timeline_put(ring->timeline);
>   	kfree(ring);
>   }
>   
> @@ -1322,6 +1323,7 @@ static void intel_ring_context_unpin(struct intel_engine_cs *engine,
>   static int intel_init_ring_buffer(struct intel_engine_cs *engine)
>   {
>   	struct intel_ring *ring;
> +	struct i915_timeline *timeline;
>   	int err;
>   
>   	intel_engine_setup_common(engine);
> @@ -1330,9 +1332,14 @@ static int intel_init_ring_buffer(struct intel_engine_cs *engine)
>   	if (err)
>   		goto err;
>   
> -	ring = intel_engine_create_ring(engine,
> -					&engine->i915->gt.legacy_timeline,
> -					32 * PAGE_SIZE);
> +	timeline = i915_timeline_create(engine->i915, engine->name);
> +	if (IS_ERR(timeline)) {
> +		err = PTR_ERR(timeline);
> +		goto err;
> +	}
> +
> +	ring = intel_engine_create_ring(engine, timeline, 32 * PAGE_SIZE);
> +	i915_timeline_put(timeline);
>   	if (IS_ERR(ring)) {
>   		err = PTR_ERR(ring);
>   		goto err;
> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
> index 3f63499734f7..539eefb31cb6 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.h
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
> @@ -5,12 +5,12 @@
>   #include <linux/hashtable.h>
>   
>   #include "i915_gem_batch_pool.h"
> -#include "i915_gem_timeline.h"
>   
>   #include "i915_reg.h"
>   #include "i915_pmu.h"
>   #include "i915_request.h"
>   #include "i915_selftest.h"
> +#include "i915_timeline.h"
>   #include "intel_gpu_commands.h"
>   
>   struct drm_printer;
> @@ -128,7 +128,7 @@ struct intel_ring {
>   	struct i915_vma *vma;
>   	void *vaddr;
>   
> -	struct intel_timeline *timeline;
> +	struct i915_timeline *timeline;
>   	struct list_head request_list;
>   	struct list_head live;
>   
> @@ -337,7 +337,8 @@ struct intel_engine_cs {
>   	u32 mmio_base;
>   
>   	struct intel_ring *buffer;
> -	struct intel_timeline *timeline;
> +
> +	struct i915_timeline timeline;
>   
>   	struct drm_i915_gem_object *default_state;
>   
> @@ -769,7 +770,7 @@ intel_write_status_page(struct intel_engine_cs *engine, int reg, u32 value)
>   
>   struct intel_ring *
>   intel_engine_create_ring(struct intel_engine_cs *engine,
> -			 struct i915_gem_timeline *timeline,
> +			 struct i915_timeline *timeline,
>   			 int size);
>   int intel_ring_pin(struct intel_ring *ring,
>   		   struct drm_i915_private *i915,
> @@ -888,7 +889,7 @@ static inline u32 intel_engine_last_submit(struct intel_engine_cs *engine)
>   	 * wtih serialising this hint with anything, so document it as
>   	 * a hint and nothing more.
>   	 */
> -	return READ_ONCE(engine->timeline->seqno);
> +	return READ_ONCE(engine->timeline.seqno);
>   }
>   
>   void intel_engine_get_instdone(struct intel_engine_cs *engine,
> diff --git a/drivers/gpu/drm/i915/selftests/i915_gem_timeline.c b/drivers/gpu/drm/i915/selftests/i915_timeline.c
> similarity index 70%
> rename from drivers/gpu/drm/i915/selftests/i915_gem_timeline.c
> rename to drivers/gpu/drm/i915/selftests/i915_timeline.c
> index 3000e6a7d82d..19f1c6a5c8fb 100644
> --- a/drivers/gpu/drm/i915/selftests/i915_gem_timeline.c
> +++ b/drivers/gpu/drm/i915/selftests/i915_timeline.c
> @@ -1,25 +1,7 @@
>   /*
> - * Copyright © 2017 Intel Corporation
> - *
> - * Permission is hereby granted, free of charge, to any person obtaining a
> - * copy of this software and associated documentation files (the "Software"),
> - * to deal in the Software without restriction, including without limitation
> - * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> - * and/or sell copies of the Software, and to permit persons to whom the
> - * Software is furnished to do so, subject to the following conditions:
> - *
> - * The above copyright notice and this permission notice (including the next
> - * paragraph) shall be included in all copies or substantial portions of the
> - * Software.
> - *
> - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> - * IN THE SOFTWARE.
> + * SPDX-License-Identifier: MIT
>    *
> + * Copyright © 2017-2018 Intel Corporation
>    */
>   
>   #include "../i915_selftest.h"
> @@ -35,21 +17,21 @@ struct __igt_sync {
>   	bool set;
>   };
>   
> -static int __igt_sync(struct intel_timeline *tl,
> +static int __igt_sync(struct i915_timeline *tl,
>   		      u64 ctx,
>   		      const struct __igt_sync *p,
>   		      const char *name)
>   {
>   	int ret;
>   
> -	if (__intel_timeline_sync_is_later(tl, ctx, p->seqno) != p->expected) {
> +	if (__i915_timeline_sync_is_later(tl, ctx, p->seqno) != p->expected) {
>   		pr_err("%s: %s(ctx=%llu, seqno=%u) expected passed %s but failed\n",
>   		       name, p->name, ctx, p->seqno, yesno(p->expected));
>   		return -EINVAL;
>   	}
>   
>   	if (p->set) {
> -		ret = __intel_timeline_sync_set(tl, ctx, p->seqno);
> +		ret = __i915_timeline_sync_set(tl, ctx, p->seqno);
>   		if (ret)
>   			return ret;
>   	}
> @@ -77,37 +59,31 @@ static int igt_sync(void *arg)
>   		{ "unwrap", UINT_MAX, true, false },
>   		{},
>   	}, *p;
> -	struct intel_timeline *tl;
> +	struct i915_timeline tl;
>   	int order, offset;
>   	int ret = -ENODEV;
>   
> -	tl = mock_timeline(0);
> -	if (!tl)
> -		return -ENOMEM;
> -
> +	mock_timeline_init(&tl, 0);
>   	for (p = pass; p->name; p++) {
>   		for (order = 1; order < 64; order++) {
>   			for (offset = -1; offset <= (order > 1); offset++) {
>   				u64 ctx = BIT_ULL(order) + offset;
>   
> -				ret = __igt_sync(tl, ctx, p, "1");
> +				ret = __igt_sync(&tl, ctx, p, "1");
>   				if (ret)
>   					goto out;
>   			}
>   		}
>   	}
> -	mock_timeline_destroy(tl);
> -
> -	tl = mock_timeline(0);
> -	if (!tl)
> -		return -ENOMEM;
> +	mock_timeline_fini(&tl);
>   
> +	mock_timeline_init(&tl, 0);
>   	for (order = 1; order < 64; order++) {
>   		for (offset = -1; offset <= (order > 1); offset++) {
>   			u64 ctx = BIT_ULL(order) + offset;
>   
>   			for (p = pass; p->name; p++) {
> -				ret = __igt_sync(tl, ctx, p, "2");
> +				ret = __igt_sync(&tl, ctx, p, "2");
>   				if (ret)
>   					goto out;
>   			}
> @@ -115,7 +91,7 @@ static int igt_sync(void *arg)
>   	}
>   
>   out:
> -	mock_timeline_destroy(tl);
> +	mock_timeline_fini(&tl);
>   	return ret;
>   }
>   
> @@ -127,15 +103,13 @@ static unsigned int random_engine(struct rnd_state *rnd)
>   static int bench_sync(void *arg)
>   {
>   	struct rnd_state prng;
> -	struct intel_timeline *tl;
> +	struct i915_timeline tl;
>   	unsigned long end_time, count;
>   	u64 prng32_1M;
>   	ktime_t kt;
>   	int order, last_order;
>   
> -	tl = mock_timeline(0);
> -	if (!tl)
> -		return -ENOMEM;
> +	mock_timeline_init(&tl, 0);
>   
>   	/* Lookups from cache are very fast and so the random number generation
>   	 * and the loop itself becomes a significant factor in the per-iteration
> @@ -167,7 +141,7 @@ static int bench_sync(void *arg)
>   	do {
>   		u64 id = i915_prandom_u64_state(&prng);
>   
> -		__intel_timeline_sync_set(tl, id, 0);
> +		__i915_timeline_sync_set(&tl, id, 0);
>   		count++;
>   	} while (!time_after(jiffies, end_time));
>   	kt = ktime_sub(ktime_get(), kt);
> @@ -182,8 +156,8 @@ static int bench_sync(void *arg)
>   	while (end_time--) {
>   		u64 id = i915_prandom_u64_state(&prng);
>   
> -		if (!__intel_timeline_sync_is_later(tl, id, 0)) {
> -			mock_timeline_destroy(tl);
> +		if (!__i915_timeline_sync_is_later(&tl, id, 0)) {
> +			mock_timeline_fini(&tl);
>   			pr_err("Lookup of %llu failed\n", id);
>   			return -EINVAL;
>   		}
> @@ -193,19 +167,17 @@ static int bench_sync(void *arg)
>   	pr_info("%s: %lu random lookups, %lluns/lookup\n",
>   		__func__, count, (long long)div64_ul(ktime_to_ns(kt), count));
>   
> -	mock_timeline_destroy(tl);
> +	mock_timeline_fini(&tl);
>   	cond_resched();
>   
> -	tl = mock_timeline(0);
> -	if (!tl)
> -		return -ENOMEM;
> +	mock_timeline_init(&tl, 0);
>   
>   	/* Benchmark setting the first N (in order) contexts */
>   	count = 0;
>   	kt = ktime_get();
>   	end_time = jiffies + HZ/10;
>   	do {
> -		__intel_timeline_sync_set(tl, count++, 0);
> +		__i915_timeline_sync_set(&tl, count++, 0);
>   	} while (!time_after(jiffies, end_time));
>   	kt = ktime_sub(ktime_get(), kt);
>   	pr_info("%s: %lu in-order insertions, %lluns/insert\n",
> @@ -215,9 +187,9 @@ static int bench_sync(void *arg)
>   	end_time = count;
>   	kt = ktime_get();
>   	while (end_time--) {
> -		if (!__intel_timeline_sync_is_later(tl, end_time, 0)) {
> +		if (!__i915_timeline_sync_is_later(&tl, end_time, 0)) {
>   			pr_err("Lookup of %lu failed\n", end_time);
> -			mock_timeline_destroy(tl);
> +			mock_timeline_fini(&tl);
>   			return -EINVAL;
>   		}
>   	}
> @@ -225,12 +197,10 @@ static int bench_sync(void *arg)
>   	pr_info("%s: %lu in-order lookups, %lluns/lookup\n",
>   		__func__, count, (long long)div64_ul(ktime_to_ns(kt), count));
>   
> -	mock_timeline_destroy(tl);
> +	mock_timeline_fini(&tl);
>   	cond_resched();
>   
> -	tl = mock_timeline(0);
> -	if (!tl)
> -		return -ENOMEM;
> +	mock_timeline_init(&tl, 0);
>   
>   	/* Benchmark searching for a random context id and maybe changing it */
>   	prandom_seed_state(&prng, i915_selftest.random_seed);
> @@ -241,8 +211,8 @@ static int bench_sync(void *arg)
>   		u32 id = random_engine(&prng);
>   		u32 seqno = prandom_u32_state(&prng);
>   
> -		if (!__intel_timeline_sync_is_later(tl, id, seqno))
> -			__intel_timeline_sync_set(tl, id, seqno);
> +		if (!__i915_timeline_sync_is_later(&tl, id, seqno))
> +			__i915_timeline_sync_set(&tl, id, seqno);
>   
>   		count++;
>   	} while (!time_after(jiffies, end_time));
> @@ -250,7 +220,7 @@ static int bench_sync(void *arg)
>   	kt = ktime_sub_ns(kt, (count * prng32_1M * 2) >> 20);
>   	pr_info("%s: %lu repeated insert/lookups, %lluns/op\n",
>   		__func__, count, (long long)div64_ul(ktime_to_ns(kt), count));
> -	mock_timeline_destroy(tl);
> +	mock_timeline_fini(&tl);
>   	cond_resched();
>   
>   	/* Benchmark searching for a known context id and changing the seqno */
> @@ -258,9 +228,7 @@ static int bench_sync(void *arg)
>   	     ({ int tmp = last_order; last_order = order; order += tmp; })) {
>   		unsigned int mask = BIT(order) - 1;
>   
> -		tl = mock_timeline(0);
> -		if (!tl)
> -			return -ENOMEM;
> +		mock_timeline_init(&tl, 0);
>   
>   		count = 0;
>   		kt = ktime_get();
> @@ -272,8 +240,8 @@ static int bench_sync(void *arg)
>   			 */
>   			u64 id = (u64)(count & mask) << order;
>   
> -			__intel_timeline_sync_is_later(tl, id, 0);
> -			__intel_timeline_sync_set(tl, id, 0);
> +			__i915_timeline_sync_is_later(&tl, id, 0);
> +			__i915_timeline_sync_set(&tl, id, 0);
>   
>   			count++;
>   		} while (!time_after(jiffies, end_time));
> @@ -281,7 +249,7 @@ static int bench_sync(void *arg)
>   		pr_info("%s: %lu cyclic/%d insert/lookups, %lluns/op\n",
>   			__func__, count, order,
>   			(long long)div64_ul(ktime_to_ns(kt), count));
> -		mock_timeline_destroy(tl);
> +		mock_timeline_fini(&tl);
>   		cond_resched();
>   	}
>   
> diff --git a/drivers/gpu/drm/i915/selftests/mock_engine.c b/drivers/gpu/drm/i915/selftests/mock_engine.c
> index 6a10cb734c35..31cc210d51e9 100644
> --- a/drivers/gpu/drm/i915/selftests/mock_engine.c
> +++ b/drivers/gpu/drm/i915/selftests/mock_engine.c
> @@ -25,6 +25,11 @@
>   #include "mock_engine.h"
>   #include "mock_request.h"
>   
> +struct mock_ring {
> +	struct intel_ring base;
> +	struct i915_timeline timeline;
> +};
> +
>   static struct mock_request *first_request(struct mock_engine *engine)
>   {
>   	return list_first_entry_or_null(&engine->hw_queue,
> @@ -125,7 +130,7 @@ static void mock_submit_request(struct i915_request *request)
>   static struct intel_ring *mock_ring(struct intel_engine_cs *engine)
>   {
>   	const unsigned long sz = PAGE_SIZE / 2;
> -	struct intel_ring *ring;
> +	struct mock_ring *ring;
>   
>   	BUILD_BUG_ON(MIN_SPACE_FOR_ADD_REQUEST > sz);
>   
> @@ -133,18 +138,24 @@ static struct intel_ring *mock_ring(struct intel_engine_cs *engine)
>   	if (!ring)
>   		return NULL;
>   
> -	ring->size = sz;
> -	ring->effective_size = sz;
> -	ring->vaddr = (void *)(ring + 1);
> +	i915_timeline_init(engine->i915, &ring->timeline, engine->name);
> +
> +	ring->base.size = sz;
> +	ring->base.effective_size = sz;
> +	ring->base.vaddr = (void *)(ring + 1);
> +	ring->base.timeline = &ring->timeline;
>   
> -	INIT_LIST_HEAD(&ring->request_list);
> -	intel_ring_update_space(ring);
> +	INIT_LIST_HEAD(&ring->base.request_list);
> +	intel_ring_update_space(&ring->base);
>   
> -	return ring;
> +	return &ring->base;
>   }
>   
> -static void mock_ring_free(struct intel_ring *ring)
> +static void mock_ring_free(struct intel_ring *base)
>   {
> +	struct mock_ring *ring = container_of(base, typeof(*ring), base);
> +
> +	i915_timeline_fini(&ring->timeline);
>   	kfree(ring);
>   }
>   
> @@ -173,8 +184,7 @@ struct intel_engine_cs *mock_engine(struct drm_i915_private *i915,
>   	engine->base.emit_breadcrumb = mock_emit_breadcrumb;
>   	engine->base.submit_request = mock_submit_request;
>   
> -	intel_engine_init_timeline(&engine->base);
> -
> +	i915_timeline_init(i915, &engine->base.timeline, engine->base.name);
>   	intel_engine_init_breadcrumbs(&engine->base);
>   	engine->base.breadcrumbs.mock = true; /* prevent touching HW for irqs */
>   
> @@ -191,6 +201,7 @@ struct intel_engine_cs *mock_engine(struct drm_i915_private *i915,
>   
>   err_breadcrumbs:
>   	intel_engine_fini_breadcrumbs(&engine->base);
> +	i915_timeline_fini(&engine->base.timeline);
>   	kfree(engine);
>   	return NULL;
>   }
> @@ -229,6 +240,7 @@ void mock_engine_free(struct intel_engine_cs *engine)
>   	mock_ring_free(engine->buffer);
>   
>   	intel_engine_fini_breadcrumbs(engine);
> +	i915_timeline_fini(&engine->timeline);
>   
>   	kfree(engine);
>   }
> diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_device.c b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
> index ed1bf3b2e47f..ab6cd0e16d9b 100644
> --- a/drivers/gpu/drm/i915/selftests/mock_gem_device.c
> +++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
> @@ -73,10 +73,8 @@ static void mock_device_release(struct drm_device *dev)
>   
>   	mutex_lock(&i915->drm.struct_mutex);
>   	mock_fini_ggtt(i915);
> -	i915_gem_timeline_fini(&i915->gt.legacy_timeline);
> -	i915_gem_timeline_fini(&i915->gt.execution_timeline);
> -	WARN_ON(!list_empty(&i915->gt.timelines));
>   	mutex_unlock(&i915->drm.struct_mutex);
> +	WARN_ON(!list_empty(&i915->gt.timelines));
>   
>   	destroy_workqueue(i915->wq);
>   
> @@ -226,15 +224,10 @@ struct drm_i915_private *mock_gem_device(void)
>   	if (!i915->priorities)
>   		goto err_dependencies;
>   
> -	mutex_lock(&i915->drm.struct_mutex);
>   	INIT_LIST_HEAD(&i915->gt.live_rings);
>   	INIT_LIST_HEAD(&i915->gt.timelines);
> -	err = i915_gem_timeline_init__global(i915);
> -	if (err) {
> -		mutex_unlock(&i915->drm.struct_mutex);
> -		goto err_priorities;
> -	}
>   
> +	mutex_lock(&i915->drm.struct_mutex);
>   	mock_init_ggtt(i915);
>   	mutex_unlock(&i915->drm.struct_mutex);
>   
> diff --git a/drivers/gpu/drm/i915/selftests/mock_timeline.c b/drivers/gpu/drm/i915/selftests/mock_timeline.c
> index 47b1f47c5812..dcf3b16f5a07 100644
> --- a/drivers/gpu/drm/i915/selftests/mock_timeline.c
> +++ b/drivers/gpu/drm/i915/selftests/mock_timeline.c
> @@ -1,45 +1,28 @@
>   /*
> - * Copyright © 2017 Intel Corporation
> - *
> - * Permission is hereby granted, free of charge, to any person obtaining a
> - * copy of this software and associated documentation files (the "Software"),
> - * to deal in the Software without restriction, including without limitation
> - * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> - * and/or sell copies of the Software, and to permit persons to whom the
> - * Software is furnished to do so, subject to the following conditions:
> - *
> - * The above copyright notice and this permission notice (including the next
> - * paragraph) shall be included in all copies or substantial portions of the
> - * Software.
> - *
> - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> - * IN THE SOFTWARE.
> + * SPDX-License-Identifier: MIT
>    *
> + * Copyright © 2017-2018 Intel Corporation
>    */
>   
> +#include "../i915_timeline.h"
> +
>   #include "mock_timeline.h"
>   
> -struct intel_timeline *mock_timeline(u64 context)
> +void mock_timeline_init(struct i915_timeline *timeline, u64 context)
>   {
> -	static struct lock_class_key class;
> -	struct intel_timeline *tl;
> +	timeline->fence_context = context;
> +
> +	spin_lock_init(&timeline->lock);
>   
> -	tl = kzalloc(sizeof(*tl), GFP_KERNEL);
> -	if (!tl)
> -		return NULL;
> +	init_request_active(&timeline->last_request, NULL);
> +	INIT_LIST_HEAD(&timeline->requests);
>   
> -	__intel_timeline_init(tl, NULL, context, &class, "mock");
> +	i915_syncmap_init(&timeline->sync);
>   
> -	return tl;
> +	INIT_LIST_HEAD(&timeline->link);
>   }
>   
> -void mock_timeline_destroy(struct intel_timeline *tl)
> +void mock_timeline_fini(struct i915_timeline *timeline)
>   {
> -	__intel_timeline_fini(tl);
> -	kfree(tl);
> +	i915_timeline_fini(timeline);
>   }
> diff --git a/drivers/gpu/drm/i915/selftests/mock_timeline.h b/drivers/gpu/drm/i915/selftests/mock_timeline.h
> index c27ff4639b8b..b6deaa61110d 100644
> --- a/drivers/gpu/drm/i915/selftests/mock_timeline.h
> +++ b/drivers/gpu/drm/i915/selftests/mock_timeline.h
> @@ -1,33 +1,15 @@
>   /*
> - * Copyright © 2017 Intel Corporation
> - *
> - * Permission is hereby granted, free of charge, to any person obtaining a
> - * copy of this software and associated documentation files (the "Software"),
> - * to deal in the Software without restriction, including without limitation
> - * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> - * and/or sell copies of the Software, and to permit persons to whom the
> - * Software is furnished to do so, subject to the following conditions:
> - *
> - * The above copyright notice and this permission notice (including the next
> - * paragraph) shall be included in all copies or substantial portions of the
> - * Software.
> - *
> - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> - * IN THE SOFTWARE.
> + * SPDX-License-Identifier: MIT
>    *
> + * Copyright © 2017-2018 Intel Corporation
>    */
>   
>   #ifndef __MOCK_TIMELINE__
>   #define __MOCK_TIMELINE__
>   
> -#include "../i915_gem_timeline.h"
> +struct i915_timeline;
>   
> -struct intel_timeline *mock_timeline(u64 context);
> -void mock_timeline_destroy(struct intel_timeline *tl);
> +void mock_timeline_init(struct i915_timeline *timeline, u64 context);
> +void mock_timeline_fini(struct i915_timeline *timeline);
>   
>   #endif /* !__MOCK_TIMELINE__ */
> 

Regards,

Tvrtko
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 4/6] drm/i915: Move timeline from GTT to ring
  2018-04-23 10:44   ` Tvrtko Ursulin
@ 2018-04-23 12:51     ` Chris Wilson
  0 siblings, 0 replies; 20+ messages in thread
From: Chris Wilson @ 2018-04-23 12:51 UTC (permalink / raw)
  To: Tvrtko Ursulin, intel-gfx

Quoting Tvrtko Ursulin (2018-04-23 11:44:19)
> 
> On 23/04/2018 11:13, Chris Wilson wrote:
> > diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> > index 0097a77fae8d..1635975dbc16 100644
> > --- a/drivers/gpu/drm/i915/i915_gem.c
> > +++ b/drivers/gpu/drm/i915/i915_gem.c
> > @@ -3110,10 +3110,10 @@ static void engine_skip_context(struct i915_request *request)
> >   {
> >       struct intel_engine_cs *engine = request->engine;
> >       struct i915_gem_context *hung_ctx = request->ctx;
> > -     struct intel_timeline *timeline;
> > +     struct intel_timeline *timeline = request->timeline;
> >       unsigned long flags;
> >   
> > -     timeline = i915_gem_context_lookup_timeline(hung_ctx, engine);
> > +     GEM_BUG_ON(timeline == engine->timeline);
> 
> Isn't this the guilty request, so would be on the engine timeline?

request->timeline is always the client timeline, so we can move it back
to the client on being preempted.

> > diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c
> > index 534b8d684cef..35869afdb199 100644
> > --- a/drivers/gpu/drm/i915/i915_request.c
> > +++ b/drivers/gpu/drm/i915/i915_request.c
> > @@ -639,6 +639,7 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx)
> >       if (IS_ERR(ring))
> >               return ERR_CAST(ring);
> >       GEM_BUG_ON(!ring);
> > +     GEM_BUG_ON(ring->timeline == engine->timeline);
> 
> It's debugging only but feels out of place. Put it in 
> intel_engine_create_ring?

Not quite, I can move it down, the point is that rq->timeline !=
engine->timeline. Maybe a bit of s/rq->timeline/rq->user_timeline/?
-Chris
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 5/6] drm/i915: Split i915_gem_timeline into individual timelines
  2018-04-23 12:33   ` Tvrtko Ursulin
@ 2018-04-23 12:55     ` Chris Wilson
  0 siblings, 0 replies; 20+ messages in thread
From: Chris Wilson @ 2018-04-23 12:55 UTC (permalink / raw)
  To: Tvrtko Ursulin, intel-gfx

Quoting Tvrtko Ursulin (2018-04-23 13:33:04)
> 
> On 23/04/2018 11:13, Chris Wilson wrote:
> > We need to move to a more flexible timeline that doesn't assume one
> > fence context per engine, and so allow for a single timeline to be used
> > across a combination of engines. This means that preallocating a fence
> > context per engine is now a hindrance, and so we want to introduce the
> > singular timeline. From the code perspective, this has the notable
> > advantage of clearing up a lot of mirky semantics and some clumsy
> > pointer chasing.
> > 
> > By splitting the timeline up into a single entity rather than an array
> > of per-engine timelines, we can realise the goal of the previous patch
> > of tracking the timeline alongside the ring.
> 
> Isn't single fence context and a single seqno space breaking the ABI? 
> Submissions from a context are now serialized across all engines. I am 
> thinking about await and dependency created in __i915_add_request to 
> timeline->last_request.

It's still one per engine, the ABI shouldn't have changed unless I've
screwed up. I now I wrote some tests to assert the independence... But
probably only have those for the new ABI we were discussing.

I guess I should make sure gem_exec_schedule is covering it.
-Chris
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 6/6] drm/i915: Lazily unbind vma on close
  2018-04-23 10:14 ` [PATCH 6/6] drm/i915: Lazily unbind vma on close Chris Wilson
@ 2018-04-23 13:08   ` Tvrtko Ursulin
  0 siblings, 0 replies; 20+ messages in thread
From: Tvrtko Ursulin @ 2018-04-23 13:08 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx


On 23/04/2018 11:14, Chris Wilson wrote:
> When userspace is passing around swapbuffers using DRI, we frequently
> have to open and close the same object in the foreign address space.
> This shows itself as the same object being rebound at roughly 30fps
> (with a second object also being rebound at 30fps), which involves us
> having to rewrite the page tables and maintain the drm_mm range manager
> every time.
> 
> However, since the object still exists and it is only the local handle
> that disappears, if we are lazy and do not unbind the VMA immediately
> when the local user closes the object but defer it until the GPU is
> idle, then we can reuse the same VMA binding. We still have to be
> careful to mark the handle and lookup tables as closed to maintain the
> uABI, just allowing the underlying VMA to be resurrected if the user is
> able to access the same object from the same context again.
> 
> If the object itself is destroyed (neither userspace keeping a handle to
> it), the VMA will be reaped immediately as usual.
> 
> In the future, this will be even more useful as instantiating a new VMA
> for use on the GPU will become heavier. A nuisance indeed, so nip it in
> the bud.
> 
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
> ---
>   drivers/gpu/drm/i915/i915_drv.h               |  1 +
>   drivers/gpu/drm/i915/i915_gem.c               |  4 +-
>   drivers/gpu/drm/i915/i915_gem_execbuffer.c    |  5 +++
>   drivers/gpu/drm/i915/i915_gem_gtt.c           | 14 ++++---
>   drivers/gpu/drm/i915/i915_vma.c               | 39 ++++++++++++-------
>   drivers/gpu/drm/i915/i915_vma.h               |  5 +++
>   drivers/gpu/drm/i915/selftests/huge_pages.c   |  2 +-
>   .../gpu/drm/i915/selftests/mock_gem_device.c  |  1 +
>   8 files changed, 51 insertions(+), 20 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 89cb74c30a00..b2f78da9bc3c 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -2060,6 +2060,7 @@ struct drm_i915_private {
>   
>   		struct list_head timelines;
>   		struct list_head live_rings;
> +		struct list_head closed_vma;
>   		u32 active_requests;
>   
>   		/**
> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> index f07556693cfe..4fb7d45b5b5d 100644
> --- a/drivers/gpu/drm/i915/i915_gem.c
> +++ b/drivers/gpu/drm/i915/i915_gem.c
> @@ -165,6 +165,7 @@ static u32 __i915_gem_park(struct drm_i915_private *i915)
>   	i915_timelines_park(i915);
>   
>   	i915_pmu_gt_parked(i915);
> +	i915_vma_parked(i915);
>   
>   	i915->gt.awake = false;
>   
> @@ -4792,7 +4793,7 @@ static void __i915_gem_free_objects(struct drm_i915_private *i915,
>   					 &obj->vma_list, obj_link) {
>   			GEM_BUG_ON(i915_vma_is_active(vma));
>   			vma->flags &= ~I915_VMA_PIN_MASK;
> -			i915_vma_close(vma);
> +			__i915_vma_final_close(vma);
>   		}
>   		GEM_BUG_ON(!list_empty(&obj->vma_list));
>   		GEM_BUG_ON(!RB_EMPTY_ROOT(&obj->vma_tree));
> @@ -5595,6 +5596,7 @@ int i915_gem_init_early(struct drm_i915_private *dev_priv)
>   
>   	INIT_LIST_HEAD(&dev_priv->gt.live_rings);
>   	INIT_LIST_HEAD(&dev_priv->gt.timelines);
> +	INIT_LIST_HEAD(&dev_priv->gt.closed_vma);
>   
>   	i915_gem_init__mm(dev_priv);
>   
> diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
> index c74f5df3fb5a..e5b8371e30de 100644
> --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
> +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
> @@ -768,6 +768,11 @@ static int eb_lookup_vmas(struct i915_execbuffer *eb)
>   		lut->ctx = eb->ctx;
>   		lut->handle = handle;
>   
> +		if (vma->flags & I915_VMA_CLOSED) {
> +			vma->flags &= ~I915_VMA_CLOSED;
> +			list_del(&vma->closed_link);
> +		}

Feels like i915_vma.c should contain code do deal with this level of 
operation. Not sure - i915_vma_pin perhaps, or somewhere else, or 
somewhere new yet. i915_vma_reopen maybe?

> +
>   add_vma:
>   		err = eb_add_vma(eb, i, vma);
>   		if (unlikely(err))
> diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
> index e9d828324f67..c1587d83fd19 100644
> --- a/drivers/gpu/drm/i915/i915_gem_gtt.c
> +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
> @@ -2218,6 +2218,12 @@ i915_ppgtt_create(struct drm_i915_private *dev_priv,
>   }
>   
>   void i915_ppgtt_close(struct i915_address_space *vm)
> +{
> +	GEM_BUG_ON(vm->closed);
> +	vm->closed = true;
> +}
> +
> +static void ppgtt_close_vma(struct i915_address_space *vm)
>   {
>   	struct list_head *phases[] = {
>   		&vm->active_list,
> @@ -2226,15 +2232,12 @@ void i915_ppgtt_close(struct i915_address_space *vm)
>   		NULL,
>   	}, **phase;
>   
> -	GEM_BUG_ON(vm->closed);
>   	vm->closed = true;
> -
>   	for (phase = phases; *phase; phase++) {
>   		struct i915_vma *vma, *vn;
>   
>   		list_for_each_entry_safe(vma, vn, *phase, vm_link)
> -			if (!i915_vma_is_closed(vma))
> -				i915_vma_close(vma);
> +			__i915_vma_final_close(vma);
>   	}
>   }
>   
> @@ -2245,7 +2248,8 @@ void i915_ppgtt_release(struct kref *kref)
>   
>   	trace_i915_ppgtt_release(&ppgtt->base);
>   
> -	/* vmas should already be unbound and destroyed */
> +	ppgtt_close_vma(&ppgtt->base);

ppgtt_destroy_vmas?

> +
>   	GEM_BUG_ON(!list_empty(&ppgtt->base.active_list));
>   	GEM_BUG_ON(!list_empty(&ppgtt->base.inactive_list));
>   	GEM_BUG_ON(!list_empty(&ppgtt->base.unbound_list));
> diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c
> index 4bda3bd29bf5..5744f4409f09 100644
> --- a/drivers/gpu/drm/i915/i915_vma.c
> +++ b/drivers/gpu/drm/i915/i915_vma.c
> @@ -46,8 +46,6 @@ i915_vma_retire(struct i915_gem_active *active, struct i915_request *rq)
>   
>   	GEM_BUG_ON(!drm_mm_node_allocated(&vma->node));
>   	list_move_tail(&vma->vm_link, &vma->vm->inactive_list);
> -	if (unlikely(i915_vma_is_closed(vma) && !i915_vma_is_pinned(vma)))
> -		WARN_ON(i915_vma_unbind(vma));
>   
>   	GEM_BUG_ON(!i915_gem_object_is_active(obj));
>   	if (--obj->active_count)
> @@ -232,7 +230,6 @@ i915_vma_instance(struct drm_i915_gem_object *obj,
>   	if (!vma)
>   		vma = vma_create(obj, vm, view);
>   
> -	GEM_BUG_ON(!IS_ERR(vma) && i915_vma_is_closed(vma));
>   	GEM_BUG_ON(!IS_ERR(vma) && i915_vma_compare(vma, vm, view));
>   	GEM_BUG_ON(!IS_ERR(vma) && vma_lookup(obj, vm, view) != vma);
>   	return vma;
> @@ -689,8 +686,6 @@ static void i915_vma_destroy(struct i915_vma *vma)
>   	int i;
>   
>   	GEM_BUG_ON(vma->node.allocated);
> -	GEM_BUG_ON(i915_vma_is_active(vma));
> -	GEM_BUG_ON(!i915_vma_is_closed(vma));
>   	GEM_BUG_ON(vma->fence);
>   
>   	for (i = 0; i < ARRAY_SIZE(vma->last_read); i++)
> @@ -699,6 +694,7 @@ static void i915_vma_destroy(struct i915_vma *vma)
>   
>   	list_del(&vma->obj_link);
>   	list_del(&vma->vm_link);
> +	rb_erase(&vma->obj_node, &vma->obj->vma_tree);
>   
>   	if (!i915_vma_is_ggtt(vma))
>   		i915_ppgtt_put(i915_vm_to_ppgtt(vma->vm));
> @@ -708,13 +704,34 @@ static void i915_vma_destroy(struct i915_vma *vma)
>   
>   void i915_vma_close(struct i915_vma *vma)
>   {
> +	lockdep_assert_held(&vma->vm->i915->drm.struct_mutex);
> +
>   	GEM_BUG_ON(i915_vma_is_closed(vma));
>   	vma->flags |= I915_VMA_CLOSED;
>   
> -	rb_erase(&vma->obj_node, &vma->obj->vma_tree);
> +	list_add_tail(&vma->closed_link, &vma->vm->i915->gt.closed_vma);
> +}
>   
> -	if (!i915_vma_is_active(vma) && !i915_vma_is_pinned(vma))
> -		WARN_ON(i915_vma_unbind(vma));
> +void __i915_vma_final_close(struct i915_vma *vma)

__i915_vma_final_destroy? Since it is not dealing only with closed vmas.

Or even this one could be i915_vma_destroy, and current i915_vma_destroy 
renamed __i915_vma_destroy to follow the practice of "almost" vs "real" 
destroy? It would be the only caller, so in this case it would be more 
like higher level destroy calls lower level destroy so still fits.

> +{
> +	lockdep_assert_held(&vma->vm->i915->drm.struct_mutex);
> +
> +	GEM_BUG_ON(i915_vma_is_active(vma));
> +	GEM_BUG_ON(i915_vma_is_pinned(vma));
> +
> +	if (i915_vma_is_closed(vma))
> +		list_del(&vma->closed_link);
> +
> +	WARN_ON(i915_vma_unbind(vma));
> +	i915_vma_destroy(vma);
> +}
> +
> +void i915_vma_parked(struct drm_i915_private *i915)
> +{
> +	struct i915_vma *vma, *next;
> +
> +	list_for_each_entry_safe(vma, next, &i915->gt.closed_vma, closed_link)
> +		__i915_vma_final_close(vma);

Then in my scheme this would call i915_vma_destroy.

Btw assert that there are no "unclosed" vmas on this list at this point?

>   }
>   
>   static void __i915_vma_iounmap(struct i915_vma *vma)
> @@ -804,7 +821,7 @@ int i915_vma_unbind(struct i915_vma *vma)
>   		return -EBUSY;
>   
>   	if (!drm_mm_node_allocated(&vma->node))
> -		goto destroy;
> +		return 0;
>   
>   	GEM_BUG_ON(obj->bind_count == 0);
>   	GEM_BUG_ON(!i915_gem_object_has_pinned_pages(obj));
> @@ -841,10 +858,6 @@ int i915_vma_unbind(struct i915_vma *vma)
>   
>   	i915_vma_remove(vma);
>   
> -destroy:
> -	if (unlikely(i915_vma_is_closed(vma)))
> -		i915_vma_destroy(vma);
> -
>   	return 0;
>   }
>   
> diff --git a/drivers/gpu/drm/i915/i915_vma.h b/drivers/gpu/drm/i915/i915_vma.h
> index 8c5022095418..0a9790555d84 100644
> --- a/drivers/gpu/drm/i915/i915_vma.h
> +++ b/drivers/gpu/drm/i915/i915_vma.h
> @@ -119,6 +119,8 @@ struct i915_vma {
>   	/** This vma's place in the eviction list */
>   	struct list_head evict_link;
>   
> +	struct list_head closed_link;
> +
>   	/**
>   	 * Used for performing relocations during execbuffer insertion.
>   	 */
> @@ -285,6 +287,7 @@ void i915_vma_revoke_mmap(struct i915_vma *vma);
>   int __must_check i915_vma_unbind(struct i915_vma *vma);
>   void i915_vma_unlink_ctx(struct i915_vma *vma);
>   void i915_vma_close(struct i915_vma *vma);
> +void __i915_vma_final_close(struct i915_vma *vma);
>   
>   int __i915_vma_do_pin(struct i915_vma *vma,
>   		      u64 size, u64 alignment, u64 flags);
> @@ -408,6 +411,8 @@ i915_vma_unpin_fence(struct i915_vma *vma)
>   		__i915_vma_unpin_fence(vma);
>   }
>   
> +void i915_vma_parked(struct drm_i915_private *i915);
> +
>   #define for_each_until(cond) if (cond) break; else
>   
>   /**
> diff --git a/drivers/gpu/drm/i915/selftests/huge_pages.c b/drivers/gpu/drm/i915/selftests/huge_pages.c
> index 05bbef363fff..8fb0b9f434c9 100644
> --- a/drivers/gpu/drm/i915/selftests/huge_pages.c
> +++ b/drivers/gpu/drm/i915/selftests/huge_pages.c
> @@ -1091,7 +1091,7 @@ static int __igt_write_huge(struct i915_gem_context *ctx,
>   out_vma_unpin:
>   	i915_vma_unpin(vma);
>   out_vma_close:
> -	i915_vma_close(vma);
> +	__i915_vma_final_close(vma);
>   
>   	return err;
>   }
> diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_device.c b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
> index ab6cd0e16d9b..c50d9fe76465 100644
> --- a/drivers/gpu/drm/i915/selftests/mock_gem_device.c
> +++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
> @@ -226,6 +226,7 @@ struct drm_i915_private *mock_gem_device(void)
>   
>   	INIT_LIST_HEAD(&i915->gt.live_rings);
>   	INIT_LIST_HEAD(&i915->gt.timelines);
> +	INIT_LIST_HEAD(&i915->gt.closed_vma);
>   
>   	mutex_lock(&i915->drm.struct_mutex);
>   	mock_init_ggtt(i915);
> 

Looks believable. I'll have another pass after a break and also will see 
what CI says. :)

Regards,

Tvrtko
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

* ✗ Fi.CI.CHECKPATCH: warning for series starting with [1/6] drm/i915: Stop tracking timeline->inflight_seqnos
  2018-04-23 10:13 [PATCH 1/6] drm/i915: Stop tracking timeline->inflight_seqnos Chris Wilson
                   ` (4 preceding siblings ...)
  2018-04-23 10:14 ` [PATCH 6/6] drm/i915: Lazily unbind vma on close Chris Wilson
@ 2018-04-23 13:24 ` Patchwork
  2018-04-23 13:27 ` ✗ Fi.CI.SPARSE: " Patchwork
  2018-04-23 13:40 ` ✗ Fi.CI.BAT: failure " Patchwork
  7 siblings, 0 replies; 20+ messages in thread
From: Patchwork @ 2018-04-23 13:24 UTC (permalink / raw)
  To: Chris Wilson; +Cc: intel-gfx

== Series Details ==

Series: series starting with [1/6] drm/i915: Stop tracking timeline->inflight_seqnos
URL   : https://patchwork.freedesktop.org/series/42111/
State : warning

== Summary ==

$ dim checkpatch origin/drm-tip
cdd8eb08a9de drm/i915: Stop tracking timeline->inflight_seqnos
-:14: ERROR:GIT_COMMIT_ID: Please use git commit description style 'commit <12+ chars of sha1> ("<title line>")' - ie: 'commit 9b6586ae9f6b ("drm/i915: Keep a global seqno per-engine")'
#14: 
References: 9b6586ae9f6b ("drm/i915: Keep a global seqno per-engine")

total: 1 errors, 0 warnings, 0 checks, 67 lines checked
8456001c1d6e drm/i915: Retire requests along rings
7a4324010faa drm/i915: Only track live rings for retiring
c0197b0d3111 drm/i915: Move timeline from GTT to ring
13fe29e79460 drm/i915: Split i915_gem_timeline into individual timelines
-:447: WARNING:FILE_PATH_CHANGES: added, moved or deleted file(s), does MAINTAINERS need updating?
#447: 
deleted file mode 100644

-:948: WARNING:SPDX_LICENSE_TAG: Missing or malformed SPDX-License-Identifier tag in line 1
#948: FILE: drivers/gpu/drm/i915/i915_timeline.c:1:
+/*

total: 0 errors, 2 warnings, 0 checks, 1612 lines checked
2b96d52d778b drm/i915: Lazily unbind vma on close

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

* ✗ Fi.CI.SPARSE: warning for series starting with [1/6] drm/i915: Stop tracking timeline->inflight_seqnos
  2018-04-23 10:13 [PATCH 1/6] drm/i915: Stop tracking timeline->inflight_seqnos Chris Wilson
                   ` (5 preceding siblings ...)
  2018-04-23 13:24 ` ✗ Fi.CI.CHECKPATCH: warning for series starting with [1/6] drm/i915: Stop tracking timeline->inflight_seqnos Patchwork
@ 2018-04-23 13:27 ` Patchwork
  2018-04-23 13:40 ` ✗ Fi.CI.BAT: failure " Patchwork
  7 siblings, 0 replies; 20+ messages in thread
From: Patchwork @ 2018-04-23 13:27 UTC (permalink / raw)
  To: Chris Wilson; +Cc: intel-gfx

== Series Details ==

Series: series starting with [1/6] drm/i915: Stop tracking timeline->inflight_seqnos
URL   : https://patchwork.freedesktop.org/series/42111/
State : warning

== Summary ==

$ dim sparse origin/drm-tip
Commit: drm/i915: Stop tracking timeline->inflight_seqnos
-O:drivers/gpu/drm/i915/i915_request.c:268:13: error: undefined identifier '__builtin_add_overflow_p'
-O:drivers/gpu/drm/i915/i915_request.c:268:13: warning: call with no type!
+drivers/gpu/drm/i915/i915_request.c:266:13: error: undefined identifier '__builtin_add_overflow_p'
+drivers/gpu/drm/i915/i915_request.c:266:13: warning: call with no type!

Commit: drm/i915: Retire requests along rings
-drivers/gpu/drm/i915/selftests/../i915_drv.h:2211:33: warning: constant 0xffffea0000000000 is so big it is unsigned long
-drivers/gpu/drm/i915/selftests/../i915_drv.h:3659:16: warning: expression using sizeof(void)
+drivers/gpu/drm/i915/selftests/../i915_drv.h:2212:33: warning: constant 0xffffea0000000000 is so big it is unsigned long
+drivers/gpu/drm/i915/selftests/../i915_drv.h:3660:16: warning: expression using sizeof(void)

Commit: drm/i915: Only track live rings for retiring
Okay!

Commit: drm/i915: Move timeline from GTT to ring
-drivers/gpu/drm/i915/selftests/../i915_drv.h:2212:33: warning: constant 0xffffea0000000000 is so big it is unsigned long
-drivers/gpu/drm/i915/selftests/../i915_drv.h:3660:16: warning: expression using sizeof(void)
+drivers/gpu/drm/i915/selftests/../i915_drv.h:2213:33: warning: constant 0xffffea0000000000 is so big it is unsigned long
+drivers/gpu/drm/i915/selftests/../i915_drv.h:3651:16: warning: expression using sizeof(void)

Commit: drm/i915: Split i915_gem_timeline into individual timelines
-O:drivers/gpu/drm/i915/i915_request.c:266:13: error: undefined identifier '__builtin_add_overflow_p'
-O:drivers/gpu/drm/i915/i915_request.c:266:13: warning: call with no type!
+drivers/gpu/drm/i915/i915_request.c:263:13: error: undefined identifier '__builtin_add_overflow_p'
+drivers/gpu/drm/i915/i915_request.c:263:13: warning: call with no type!
-drivers/gpu/drm/i915/selftests/../i915_drv.h:2213:33: warning: constant 0xffffea0000000000 is so big it is unsigned long
-drivers/gpu/drm/i915/selftests/../i915_drv.h:3651:16: warning: expression using sizeof(void)
+drivers/gpu/drm/i915/selftests/../i915_drv.h:2211:33: warning: constant 0xffffea0000000000 is so big it is unsigned long
+drivers/gpu/drm/i915/selftests/../i915_drv.h:3649:16: warning: expression using sizeof(void)

Commit: drm/i915: Lazily unbind vma on close
-drivers/gpu/drm/i915/selftests/../i915_drv.h:2211:33: warning: constant 0xffffea0000000000 is so big it is unsigned long
-drivers/gpu/drm/i915/selftests/../i915_drv.h:3649:16: warning: expression using sizeof(void)
+drivers/gpu/drm/i915/selftests/../i915_drv.h:2212:33: warning: constant 0xffffea0000000000 is so big it is unsigned long
+drivers/gpu/drm/i915/selftests/../i915_drv.h:3650:16: warning: expression using sizeof(void)

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

* ✗ Fi.CI.BAT: failure for series starting with [1/6] drm/i915: Stop tracking timeline->inflight_seqnos
  2018-04-23 10:13 [PATCH 1/6] drm/i915: Stop tracking timeline->inflight_seqnos Chris Wilson
                   ` (6 preceding siblings ...)
  2018-04-23 13:27 ` ✗ Fi.CI.SPARSE: " Patchwork
@ 2018-04-23 13:40 ` Patchwork
  2018-04-23 13:49   ` Chris Wilson
  7 siblings, 1 reply; 20+ messages in thread
From: Patchwork @ 2018-04-23 13:40 UTC (permalink / raw)
  To: Chris Wilson; +Cc: intel-gfx

== Series Details ==

Series: series starting with [1/6] drm/i915: Stop tracking timeline->inflight_seqnos
URL   : https://patchwork.freedesktop.org/series/42111/
State : failure

== Summary ==

= CI Bug Log - changes from CI_DRM_4078 -> Patchwork_8772 =

== Summary - FAILURE ==

  Serious unknown changes coming with Patchwork_8772 absolutely need to be
  verified manually.
  
  If you think the reported changes have nothing to do with the changes
  introduced in Patchwork_8772, please notify your bug team to allow them
  to document this new failure mode, which will reduce false positives in CI.

  External URL: https://patchwork.freedesktop.org/api/1.0/series/42111/revisions/1/mbox/

== Possible new issues ==

  Here are the unknown changes that may have been introduced in Patchwork_8772:

  === IGT changes ===

    ==== Possible regressions ====

    igt@core_auth@basic-auth:
      fi-kbl-r:           PASS -> INCOMPLETE
      fi-bdw-5557u:       PASS -> INCOMPLETE
      fi-skl-guc:         PASS -> INCOMPLETE
      fi-kbl-7567u:       PASS -> INCOMPLETE
      fi-kbl-7500u:       PASS -> INCOMPLETE
      fi-skl-6600u:       PASS -> INCOMPLETE
      {fi-kbl-7560u}:     PASS -> INCOMPLETE
      fi-cfl-8700k:       PASS -> INCOMPLETE
      fi-skl-6700k2:      PASS -> INCOMPLETE
      fi-cfl-s3:          PASS -> INCOMPLETE
      fi-skl-6770hq:      PASS -> INCOMPLETE
      fi-bsw-n3050:       PASS -> INCOMPLETE
      fi-skl-6260u:       PASS -> INCOMPLETE

    
== Known issues ==

  Here are the changes found in Patchwork_8772 that come from known issues:

  === IGT changes ===

    ==== Issues hit ====

    igt@core_auth@basic-auth:
      fi-glk-j4005:       PASS -> INCOMPLETE (k.org#198133, fdo#103359)
      fi-bdw-gvtdvm:      PASS -> INCOMPLETE (fdo#105600)
      fi-bxt-dsi:         PASS -> INCOMPLETE (fdo#103927)
      fi-cnl-psr:         PASS -> INCOMPLETE (fdo#105086)
      fi-cnl-y3:          PASS -> INCOMPLETE (fdo#105086)
      fi-bxt-j4205:       PASS -> INCOMPLETE (fdo#103927)
      fi-skl-gvtdvm:      PASS -> INCOMPLETE (fdo#105600)

    igt@kms_pipe_crc_basic@suspend-read-crc-pipe-b:
      fi-snb-2520m:       PASS -> INCOMPLETE (fdo#103713)

    
    ==== Possible fixes ====

    igt@kms_pipe_crc_basic@suspend-read-crc-pipe-c:
      fi-ivb-3520m:       DMESG-WARN (fdo#106084) -> PASS

    
  {name}: This element is suppressed. This means it is ignored when computing
          the status of the difference (SUCCESS, WARNING, or FAILURE).

  fdo#103359 https://bugs.freedesktop.org/show_bug.cgi?id=103359
  fdo#103713 https://bugs.freedesktop.org/show_bug.cgi?id=103713
  fdo#103927 https://bugs.freedesktop.org/show_bug.cgi?id=103927
  fdo#105086 https://bugs.freedesktop.org/show_bug.cgi?id=105086
  fdo#105600 https://bugs.freedesktop.org/show_bug.cgi?id=105600
  fdo#106084 https://bugs.freedesktop.org/show_bug.cgi?id=106084
  k.org#198133 https://bugzilla.kernel.org/show_bug.cgi?id=198133


== Participating hosts (36 -> 32) ==

  Missing    (4): fi-ctg-p8600 fi-ilk-m540 fi-skl-6700hq fi-cfl-u 


== Build changes ==

    * Linux: CI_DRM_4078 -> Patchwork_8772

  CI_DRM_4078: 9391010824b34ec58217f816ba5e314e7312191d @ git://anongit.freedesktop.org/gfx-ci/linux
  IGT_4444: dcc44347494231feabc588c2a76998cbc9afdf8c @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools
  Patchwork_8772: 2b96d52d778b75c784da54bc5a6cda1dc937c0d5 @ git://anongit.freedesktop.org/gfx-ci/linux
  piglit_4444: a2f486679f467cd6e82578384f56d4aabaa8cf2e @ git://anongit.freedesktop.org/piglit


== Linux commits ==

2b96d52d778b drm/i915: Lazily unbind vma on close
13fe29e79460 drm/i915: Split i915_gem_timeline into individual timelines
c0197b0d3111 drm/i915: Move timeline from GTT to ring
7a4324010faa drm/i915: Only track live rings for retiring
8456001c1d6e drm/i915: Retire requests along rings
cdd8eb08a9de drm/i915: Stop tracking timeline->inflight_seqnos


== Kernel 32bit build ==

Warning: Kernel 32bit buildtest failed:
https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_8772/build_32bit_failure.log

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_8772/issues.html
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: ✗ Fi.CI.BAT: failure for series starting with [1/6] drm/i915: Stop tracking timeline->inflight_seqnos
  2018-04-23 13:40 ` ✗ Fi.CI.BAT: failure " Patchwork
@ 2018-04-23 13:49   ` Chris Wilson
  0 siblings, 0 replies; 20+ messages in thread
From: Chris Wilson @ 2018-04-23 13:49 UTC (permalink / raw)
  To: Patchwork; +Cc: intel-gfx

Quoting Patchwork (2018-04-23 14:40:51)
>     igt@core_auth@basic-auth:
>       fi-glk-j4005:       PASS -> INCOMPLETE (k.org#198133, fdo#103359)
>       fi-bdw-gvtdvm:      PASS -> INCOMPLETE (fdo#105600)
>       fi-bxt-dsi:         PASS -> INCOMPLETE (fdo#103927)
>       fi-cnl-psr:         PASS -> INCOMPLETE (fdo#105086)
>       fi-cnl-y3:          PASS -> INCOMPLETE (fdo#105086)
>       fi-bxt-j4205:       PASS -> INCOMPLETE (fdo#103927)
>       fi-skl-gvtdvm:      PASS -> INCOMPLETE (fdo#105600)

Oh sausage. engine->last_retired_context needs to be in engine order,
but ring->head needs to be in ring order.
-Chris
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

* ✗ Fi.CI.BAT: failure for series starting with [1/6] drm/i915: Stop tracking timeline->inflight_seqnos
  2018-04-24 13:14 [PATCH 1/6] " Chris Wilson
@ 2018-04-24 15:05 ` Patchwork
  0 siblings, 0 replies; 20+ messages in thread
From: Patchwork @ 2018-04-24 15:05 UTC (permalink / raw)
  To: Chris Wilson; +Cc: intel-gfx

== Series Details ==

Series: series starting with [1/6] drm/i915: Stop tracking timeline->inflight_seqnos
URL   : https://patchwork.freedesktop.org/series/42192/
State : failure

== Summary ==

= CI Bug Log - changes from CI_DRM_4087 -> Patchwork_8789 =

== Summary - FAILURE ==

  Serious unknown changes coming with Patchwork_8789 absolutely need to be
  verified manually.
  
  If you think the reported changes have nothing to do with the changes
  introduced in Patchwork_8789, please notify your bug team to allow them
  to document this new failure mode, which will reduce false positives in CI.

  External URL: https://patchwork.freedesktop.org/api/1.0/series/42192/revisions/1/mbox/

== Possible new issues ==

  Here are the unknown changes that may have been introduced in Patchwork_8789:

  === IGT changes ===

    ==== Possible regressions ====

    igt@gem_ctx_switch@basic-default:
      fi-bsw-n3050:       PASS -> INCOMPLETE

    igt@gem_exec_suspend@basic-s4-devices:
      fi-skl-guc:         PASS -> FAIL +1

    
== Known issues ==

  Here are the changes found in Patchwork_8789 that come from known issues:

  === IGT changes ===

    ==== Issues hit ====

    igt@debugfs_test@read_all_entries:
      fi-snb-2520m:       PASS -> INCOMPLETE (fdo#103713)

    igt@kms_flip@basic-flip-vs-wf_vblank:
      fi-cnl-psr:         PASS -> FAIL (fdo#103928, fdo#100368)

    
  fdo#100368 https://bugs.freedesktop.org/show_bug.cgi?id=100368
  fdo#103713 https://bugs.freedesktop.org/show_bug.cgi?id=103713
  fdo#103928 https://bugs.freedesktop.org/show_bug.cgi?id=103928


== Participating hosts (37 -> 34) ==

  Missing    (3): fi-ctg-p8600 fi-ilk-m540 fi-skl-6700hq 


== Build changes ==

    * Linux: CI_DRM_4087 -> Patchwork_8789

  CI_DRM_4087: d04fd4f6d93cea918521059db8358ff9e7a4a03b @ git://anongit.freedesktop.org/gfx-ci/linux
  IGT_4446: e5e8dafc991ee922ec159491c680caff0cfe9235 @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools
  Patchwork_8789: d938078a7beb1500563ccee9c822dd911d3e3ce0 @ git://anongit.freedesktop.org/gfx-ci/linux
  piglit_4446: a2f486679f467cd6e82578384f56d4aabaa8cf2e @ git://anongit.freedesktop.org/piglit


== Linux commits ==

d938078a7beb drm/i915: Lazily unbind vma on close
42ca2a119df3 drm/i915: Split i915_gem_timeline into individual timelines
18236bd5830a drm/i915: Move timeline from GTT to ring
82ec7fbb67fc drm/i915: Only track live rings for retiring
fe5cc72fab33 drm/i915: Retire requests along rings
9a8374d0cd41 drm/i915: Stop tracking timeline->inflight_seqnos

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_8789/issues.html
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2018-04-24 15:05 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-04-23 10:13 [PATCH 1/6] drm/i915: Stop tracking timeline->inflight_seqnos Chris Wilson
2018-04-23 10:13 ` [PATCH 2/6] drm/i915: Retire requests along rings Chris Wilson
2018-04-23 10:18   ` Tvrtko Ursulin
2018-04-23 10:13 ` [PATCH 3/6] drm/i915: Only track live rings for retiring Chris Wilson
2018-04-23 10:25   ` Tvrtko Ursulin
2018-04-23 10:36     ` Chris Wilson
2018-04-23 10:50       ` Tvrtko Ursulin
2018-04-23 10:13 ` [PATCH 4/6] drm/i915: Move timeline from GTT to ring Chris Wilson
2018-04-23 10:44   ` Tvrtko Ursulin
2018-04-23 12:51     ` Chris Wilson
2018-04-23 10:13 ` [PATCH 5/6] drm/i915: Split i915_gem_timeline into individual timelines Chris Wilson
2018-04-23 12:33   ` Tvrtko Ursulin
2018-04-23 12:55     ` Chris Wilson
2018-04-23 10:14 ` [PATCH 6/6] drm/i915: Lazily unbind vma on close Chris Wilson
2018-04-23 13:08   ` Tvrtko Ursulin
2018-04-23 13:24 ` ✗ Fi.CI.CHECKPATCH: warning for series starting with [1/6] drm/i915: Stop tracking timeline->inflight_seqnos Patchwork
2018-04-23 13:27 ` ✗ Fi.CI.SPARSE: " Patchwork
2018-04-23 13:40 ` ✗ Fi.CI.BAT: failure " Patchwork
2018-04-23 13:49   ` Chris Wilson
2018-04-24 13:14 [PATCH 1/6] " Chris Wilson
2018-04-24 15:05 ` ✗ Fi.CI.BAT: failure for series starting with [1/6] " Patchwork

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.