All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/7] drm/i915: Stop tracking timeline->inflight_seqnos
@ 2018-04-26 17:49 Chris Wilson
  2018-04-26 17:49 ` [PATCH 2/7] drm/i915: Wrap engine->context_pin() and engine->context_unpin() Chris Wilson
                   ` (12 more replies)
  0 siblings, 13 replies; 24+ messages in thread
From: Chris Wilson @ 2018-04-26 17:49 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!)

v2: Keep a global counter of all requests ever submitted and force the
reset when it wraps.

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>
---
 drivers/gpu/drm/i915/i915_debugfs.c      |  5 ++--
 drivers/gpu/drm/i915/i915_drv.h          |  1 +
 drivers/gpu/drm/i915/i915_gem_timeline.h |  6 -----
 drivers/gpu/drm/i915/i915_request.c      | 33 ++++++++++++------------
 drivers/gpu/drm/i915/intel_engine_cs.c   |  5 ++--
 5 files changed, 22 insertions(+), 28 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 1c88805d3354..83c86257fe1c 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_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 8444ca8d5aa3..8fd9fb6efba5 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2061,6 +2061,7 @@ struct drm_i915_private {
 		struct list_head timelines;
 		struct i915_gem_timeline global_timeline;
 		u32 active_requests;
+		u32 request_serial;
 
 		/**
 		 * Is the GPU currently considered idle, or busy executing
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..b1993d4a1a53 100644
--- a/drivers/gpu/drm/i915/i915_request.c
+++ b/drivers/gpu/drm/i915/i915_request.c
@@ -241,6 +241,7 @@ static int reset_all_global_seqno(struct drm_i915_private *i915, u32 seqno)
 			       sizeof(timeline->engine[id].global_sync));
 	}
 
+	i915->gt.request_serial = seqno;
 	return 0;
 }
 
@@ -257,18 +258,22 @@ int i915_gem_set_global_seqno(struct drm_device *dev, u32 seqno)
 	return reset_all_global_seqno(i915, seqno - 1);
 }
 
-static int reserve_engine(struct intel_engine_cs *engine)
+static int reserve_gt(struct drm_i915_private *i915)
 {
-	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))) {
+	/*
+	 * Reservation is fine until we may need to wrap around
+	 *
+	 * By incrementing the serial for every request, we know that no
+	 * individual engine may exceed that serial (as each is reset to 0
+	 * on any wrap). This protects even the most pessimistic of migrations
+	 * of every request from all engines onto just one.
+	 */
+	while (unlikely(++i915->gt.request_serial == 0)) {
 		ret = reset_all_global_seqno(i915, 0);
 		if (ret) {
-			engine->timeline->inflight_seqnos--;
+			i915->gt.request_serial--;
 			return ret;
 		}
 	}
@@ -279,15 +284,10 @@ static int reserve_engine(struct intel_engine_cs *engine)
 	return 0;
 }
 
-static void unreserve_engine(struct intel_engine_cs *engine)
+static void unreserve_gt(struct drm_i915_private *i915)
 {
-	struct drm_i915_private *i915 = engine->i915;
-
 	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,
@@ -362,7 +362,6 @@ static void i915_request_retire(struct i915_request *request)
 	list_del_init(&request->link);
 	spin_unlock_irq(&engine->timeline->lock);
 
-	unreserve_engine(request->engine);
 	advance_ring(request);
 
 	free_capture_list(request);
@@ -424,6 +423,8 @@ static void i915_request_retire(struct i915_request *request)
 	}
 	spin_unlock_irq(&request->lock);
 
+	unreserve_gt(request->i915);
+
 	i915_sched_node_fini(request->i915, &request->sched);
 	i915_request_put(request);
 }
@@ -642,7 +643,7 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx)
 		return ERR_CAST(ring);
 	GEM_BUG_ON(!ring);
 
-	ret = reserve_engine(engine);
+	ret = reserve_gt(i915);
 	if (ret)
 		goto err_unpin;
 
@@ -784,7 +785,7 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx)
 
 	kmem_cache_free(i915->requests, rq);
 err_unreserve:
-	unreserve_engine(engine);
+	unreserve_gt(i915);
 err_unpin:
 	engine->context_unpin(engine, ctx);
 	return ERR_PTR(ret);
diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c
index ac009f10c948..eba81d55dc3a 100644
--- a/drivers/gpu/drm/i915/intel_engine_cs.c
+++ b/drivers/gpu/drm/i915/intel_engine_cs.c
@@ -1321,12 +1321,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] 24+ messages in thread

* [PATCH 2/7] drm/i915: Wrap engine->context_pin() and engine->context_unpin()
  2018-04-26 17:49 [PATCH 1/7] drm/i915: Stop tracking timeline->inflight_seqnos Chris Wilson
@ 2018-04-26 17:49 ` Chris Wilson
  2018-04-27 12:35   ` Tvrtko Ursulin
  2018-04-26 17:49 ` [PATCH 3/7] drm/i915: Retire requests along rings Chris Wilson
                   ` (11 subsequent siblings)
  12 siblings, 1 reply; 24+ messages in thread
From: Chris Wilson @ 2018-04-26 17:49 UTC (permalink / raw)
  To: intel-gfx

Make life easier in upcoming patches by moving the context_pin and
context_unpin vfuncs into inline helpers.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/gvt/mmio_context.c      |  2 +-
 drivers/gpu/drm/i915/gvt/scheduler.c         | 20 ++++++-------
 drivers/gpu/drm/i915/i915_debugfs.c          | 20 +++++++------
 drivers/gpu/drm/i915/i915_gem.c              |  4 +--
 drivers/gpu/drm/i915/i915_gem_context.c      |  8 +++---
 drivers/gpu/drm/i915/i915_gem_context.h      | 30 +++++++++++++++++++-
 drivers/gpu/drm/i915/i915_gpu_error.c        |  3 +-
 drivers/gpu/drm/i915/i915_perf.c             |  9 +++---
 drivers/gpu/drm/i915/i915_request.c          |  6 ++--
 drivers/gpu/drm/i915/intel_engine_cs.c       | 13 ++++-----
 drivers/gpu/drm/i915/intel_guc_ads.c         |  3 +-
 drivers/gpu/drm/i915/intel_guc_submission.c  |  5 ++--
 drivers/gpu/drm/i915/intel_lrc.c             | 29 +++++++++++--------
 drivers/gpu/drm/i915/intel_lrc.h             |  2 +-
 drivers/gpu/drm/i915/intel_ringbuffer.c      | 19 +++++++------
 drivers/gpu/drm/i915/selftests/mock_engine.c |  2 +-
 16 files changed, 108 insertions(+), 67 deletions(-)

diff --git a/drivers/gpu/drm/i915/gvt/mmio_context.c b/drivers/gpu/drm/i915/gvt/mmio_context.c
index a5bac83d53a9..0f949554d118 100644
--- a/drivers/gpu/drm/i915/gvt/mmio_context.c
+++ b/drivers/gpu/drm/i915/gvt/mmio_context.c
@@ -448,7 +448,7 @@ static void switch_mocs(struct intel_vgpu *pre, struct intel_vgpu *next,
 
 bool is_inhibit_context(struct i915_gem_context *ctx, int ring_id)
 {
-	u32 *reg_state = ctx->engine[ring_id].lrc_reg_state;
+	u32 *reg_state = ctx->__engine[ring_id].lrc_reg_state;
 	u32 inhibit_mask =
 		_MASKED_BIT_ENABLE(CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT);
 
diff --git a/drivers/gpu/drm/i915/gvt/scheduler.c b/drivers/gpu/drm/i915/gvt/scheduler.c
index 35f7cfd7a6b4..ffb45a9ee228 100644
--- a/drivers/gpu/drm/i915/gvt/scheduler.c
+++ b/drivers/gpu/drm/i915/gvt/scheduler.c
@@ -58,7 +58,7 @@ static void update_shadow_pdps(struct intel_vgpu_workload *workload)
 	int ring_id = workload->ring_id;
 	struct i915_gem_context *shadow_ctx = vgpu->submission.shadow_ctx;
 	struct drm_i915_gem_object *ctx_obj =
-		shadow_ctx->engine[ring_id].state->obj;
+		shadow_ctx->__engine[ring_id].state->obj;
 	struct execlist_ring_context *shadow_ring_context;
 	struct page *page;
 
@@ -130,7 +130,7 @@ static int populate_shadow_context(struct intel_vgpu_workload *workload)
 	int ring_id = workload->ring_id;
 	struct i915_gem_context *shadow_ctx = vgpu->submission.shadow_ctx;
 	struct drm_i915_gem_object *ctx_obj =
-		shadow_ctx->engine[ring_id].state->obj;
+		shadow_ctx->__engine[ring_id].state->obj;
 	struct execlist_ring_context *shadow_ring_context;
 	struct page *page;
 	void *dst;
@@ -283,7 +283,7 @@ static int shadow_context_status_change(struct notifier_block *nb,
 static void shadow_context_descriptor_update(struct i915_gem_context *ctx,
 		struct intel_engine_cs *engine)
 {
-	struct intel_context *ce = &ctx->engine[engine->id];
+	struct intel_context *ce = to_intel_context(ctx, engine);
 	u64 desc = 0;
 
 	desc = ce->lrc_desc;
@@ -389,7 +389,7 @@ int intel_gvt_scan_and_shadow_workload(struct intel_vgpu_workload *workload)
 	 * shadow_ctx pages invalid. So gvt need to pin itself. After update
 	 * the guest context, gvt can unpin the shadow_ctx safely.
 	 */
-	ring = engine->context_pin(engine, shadow_ctx);
+	ring = intel_context_pin(shadow_ctx, engine);
 	if (IS_ERR(ring)) {
 		ret = PTR_ERR(ring);
 		gvt_vgpu_err("fail to pin shadow context\n");
@@ -403,7 +403,7 @@ int intel_gvt_scan_and_shadow_workload(struct intel_vgpu_workload *workload)
 	return 0;
 
 err_unpin:
-	engine->context_unpin(engine, shadow_ctx);
+	intel_context_unpin(shadow_ctx, engine);
 err_shadow:
 	release_shadow_wa_ctx(&workload->wa_ctx);
 err_scan:
@@ -437,7 +437,7 @@ static int intel_gvt_generate_request(struct intel_vgpu_workload *workload)
 	return 0;
 
 err_unpin:
-	engine->context_unpin(engine, shadow_ctx);
+	intel_context_unpin(shadow_ctx, engine);
 	release_shadow_wa_ctx(&workload->wa_ctx);
 	return ret;
 }
@@ -526,7 +526,7 @@ static int update_wa_ctx_2_shadow_ctx(struct intel_shadow_wa_ctx *wa_ctx)
 	struct intel_vgpu_submission *s = &workload->vgpu->submission;
 	struct i915_gem_context *shadow_ctx = s->shadow_ctx;
 	struct drm_i915_gem_object *ctx_obj =
-		shadow_ctx->engine[ring_id].state->obj;
+		shadow_ctx->__engine[ring_id].state->obj;
 	struct execlist_ring_context *shadow_ring_context;
 	struct page *page;
 
@@ -688,7 +688,7 @@ static int dispatch_workload(struct intel_vgpu_workload *workload)
 
 	ret = prepare_workload(workload);
 	if (ret) {
-		engine->context_unpin(engine, shadow_ctx);
+		intel_context_unpin(shadow_ctx, engine);
 		goto out;
 	}
 
@@ -771,7 +771,7 @@ static void update_guest_context(struct intel_vgpu_workload *workload)
 	struct i915_gem_context *shadow_ctx = s->shadow_ctx;
 	int ring_id = workload->ring_id;
 	struct drm_i915_gem_object *ctx_obj =
-		shadow_ctx->engine[ring_id].state->obj;
+		shadow_ctx->__engine[ring_id].state->obj;
 	struct execlist_ring_context *shadow_ring_context;
 	struct page *page;
 	void *src;
@@ -898,7 +898,7 @@ static void complete_current_workload(struct intel_gvt *gvt, int ring_id)
 		}
 		mutex_lock(&dev_priv->drm.struct_mutex);
 		/* unpin shadow ctx as the shadow_ctx update is done */
-		engine->context_unpin(engine, s->shadow_ctx);
+		intel_context_unpin(s->shadow_ctx, engine);
 		mutex_unlock(&dev_priv->drm.struct_mutex);
 	}
 
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 83c86257fe1c..601041c6f9ae 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -377,16 +377,19 @@ static void print_batch_pool_stats(struct seq_file *m,
 	print_file_stats(m, "[k]batch pool", stats);
 }
 
-static int per_file_ctx_stats(int id, void *ptr, void *data)
+static int per_file_ctx_stats(int idx, void *ptr, void *data)
 {
 	struct i915_gem_context *ctx = ptr;
-	int n;
+	struct intel_engine_cs *engine;
+	enum intel_engine_id id;
+
+	for_each_engine(engine, ctx->i915, id) {
+		struct intel_context *ce = to_intel_context(ctx, engine);
 
-	for (n = 0; n < ARRAY_SIZE(ctx->engine); n++) {
-		if (ctx->engine[n].state)
-			per_file_stats(0, ctx->engine[n].state->obj, data);
-		if (ctx->engine[n].ring)
-			per_file_stats(0, ctx->engine[n].ring->vma->obj, data);
+		if (ce->state)
+			per_file_stats(0, ce->state->obj, data);
+		if (ce->ring)
+			per_file_stats(0, ce->ring->vma->obj, data);
 	}
 
 	return 0;
@@ -1959,7 +1962,8 @@ static int i915_context_status(struct seq_file *m, void *unused)
 		seq_putc(m, '\n');
 
 		for_each_engine(engine, dev_priv, id) {
-			struct intel_context *ce = &ctx->engine[engine->id];
+			struct intel_context *ce =
+				to_intel_context(ctx, engine);
 
 			seq_printf(m, "%s: ", engine->name);
 			if (ce->state)
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 6b0c67a4f214..4090bfdda340 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -3234,7 +3234,7 @@ void i915_gem_reset(struct drm_i915_private *dev_priv,
 				      stalled_mask & ENGINE_MASK(id));
 		ctx = fetch_and_zero(&engine->last_retired_context);
 		if (ctx)
-			engine->context_unpin(engine, ctx);
+			intel_context_unpin(ctx, engine);
 
 		/*
 		 * Ostensibily, we always want a context loaded for powersaving,
@@ -5291,7 +5291,7 @@ static int __intel_engines_record_defaults(struct drm_i915_private *i915)
 	for_each_engine(engine, i915, id) {
 		struct i915_vma *state;
 
-		state = ctx->engine[id].state;
+		state = to_intel_context(ctx, engine)->state;
 		if (!state)
 			continue;
 
diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
index 74435affe23f..59d4bd4a7b73 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/i915_gem_context.c
@@ -117,15 +117,15 @@ static void lut_close(struct i915_gem_context *ctx)
 
 static void i915_gem_context_free(struct i915_gem_context *ctx)
 {
-	int i;
+	unsigned int n;
 
 	lockdep_assert_held(&ctx->i915->drm.struct_mutex);
 	GEM_BUG_ON(!i915_gem_context_is_closed(ctx));
 
 	i915_ppgtt_put(ctx->ppgtt);
 
-	for (i = 0; i < I915_NUM_ENGINES; i++) {
-		struct intel_context *ce = &ctx->engine[i];
+	for (n = 0; n < ARRAY_SIZE(ctx->__engine); n++) {
+		struct intel_context *ce = &ctx->__engine[n];
 
 		if (!ce->state)
 			continue;
@@ -521,7 +521,7 @@ void i915_gem_contexts_lost(struct drm_i915_private *dev_priv)
 		if (!engine->last_retired_context)
 			continue;
 
-		engine->context_unpin(engine, engine->last_retired_context);
+		intel_context_unpin(engine->last_retired_context, engine);
 		engine->last_retired_context = NULL;
 	}
 }
diff --git a/drivers/gpu/drm/i915/i915_gem_context.h b/drivers/gpu/drm/i915/i915_gem_context.h
index b12a8a8c5af9..ace3b129c189 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.h
+++ b/drivers/gpu/drm/i915/i915_gem_context.h
@@ -149,7 +149,7 @@ struct i915_gem_context {
 		u32 *lrc_reg_state;
 		u64 lrc_desc;
 		int pin_count;
-	} engine[I915_NUM_ENGINES];
+	} __engine[I915_NUM_ENGINES];
 
 	/** ring_size: size for allocating the per-engine ring buffer */
 	u32 ring_size;
@@ -256,6 +256,34 @@ static inline bool i915_gem_context_is_kernel(struct i915_gem_context *ctx)
 	return !ctx->file_priv;
 }
 
+static inline struct intel_context *
+to_intel_context(struct i915_gem_context *ctx,
+		 const struct intel_engine_cs *engine)
+{
+	return &ctx->__engine[engine->id];
+}
+
+static inline struct intel_ring *
+intel_context_pin(struct i915_gem_context *ctx, struct intel_engine_cs *engine)
+{
+	return engine->context_pin(engine, ctx);
+}
+
+static inline void __intel_context_pin(struct i915_gem_context *ctx,
+				       const struct intel_engine_cs *engine)
+{
+	struct intel_context *ce = to_intel_context(ctx, engine);
+
+	GEM_BUG_ON(!ce->pin_count);
+	ce->pin_count++;
+}
+
+static inline void intel_context_unpin(struct i915_gem_context *ctx,
+				       struct intel_engine_cs *engine)
+{
+	engine->context_unpin(engine, ctx);
+}
+
 /* i915_gem_context.c */
 int __must_check i915_gem_contexts_init(struct drm_i915_private *dev_priv);
 void i915_gem_contexts_lost(struct drm_i915_private *dev_priv);
diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c
index 671ffa37614e..c0127965b578 100644
--- a/drivers/gpu/drm/i915/i915_gpu_error.c
+++ b/drivers/gpu/drm/i915/i915_gpu_error.c
@@ -1472,7 +1472,8 @@ static void gem_record_rings(struct i915_gpu_state *error)
 
 			ee->ctx =
 				i915_error_object_create(i915,
-							 request->ctx->engine[i].state);
+							 to_intel_context(request->ctx,
+									  engine)->state);
 
 			error->simulated |=
 				i915_gem_context_no_error_capture(request->ctx);
diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c
index bfc906cd4e5e..4b1da01168ae 100644
--- a/drivers/gpu/drm/i915/i915_perf.c
+++ b/drivers/gpu/drm/i915/i915_perf.c
@@ -1234,7 +1234,7 @@ static int oa_get_render_ctx_id(struct i915_perf_stream *stream)
 		 *
 		 * NB: implied RCS engine...
 		 */
-		ring = engine->context_pin(engine, stream->ctx);
+		ring = intel_context_pin(stream->ctx, engine);
 		mutex_unlock(&dev_priv->drm.struct_mutex);
 		if (IS_ERR(ring))
 			return PTR_ERR(ring);
@@ -1246,7 +1246,7 @@ static int oa_get_render_ctx_id(struct i915_perf_stream *stream)
 		 * with gen8+ and execlists
 		 */
 		dev_priv->perf.oa.specific_ctx_id =
-			i915_ggtt_offset(stream->ctx->engine[engine->id].state);
+			i915_ggtt_offset(to_intel_context(stream->ctx, engine)->state);
 	}
 
 	return 0;
@@ -1271,7 +1271,7 @@ static void oa_put_render_ctx_id(struct i915_perf_stream *stream)
 		mutex_lock(&dev_priv->drm.struct_mutex);
 
 		dev_priv->perf.oa.specific_ctx_id = INVALID_CTX_ID;
-		engine->context_unpin(engine, stream->ctx);
+		intel_context_unpin(stream->ctx, engine);
 
 		mutex_unlock(&dev_priv->drm.struct_mutex);
 	}
@@ -1759,6 +1759,7 @@ static int gen8_switch_to_updated_kernel_context(struct drm_i915_private *dev_pr
 static int gen8_configure_all_contexts(struct drm_i915_private *dev_priv,
 				       const struct i915_oa_config *oa_config)
 {
+	struct intel_engine_cs *engine = dev_priv->engine[RCS];
 	struct i915_gem_context *ctx;
 	int ret;
 	unsigned int wait_flags = I915_WAIT_LOCKED;
@@ -1789,7 +1790,7 @@ static int gen8_configure_all_contexts(struct drm_i915_private *dev_priv,
 
 	/* Update all contexts now that we've stalled the submission. */
 	list_for_each_entry(ctx, &dev_priv->contexts.list, link) {
-		struct intel_context *ce = &ctx->engine[RCS];
+		struct intel_context *ce = to_intel_context(ctx, engine);
 		u32 *regs;
 
 		/* OA settings will be set upon first use */
diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c
index b1993d4a1a53..9358f2cf0c32 100644
--- a/drivers/gpu/drm/i915/i915_request.c
+++ b/drivers/gpu/drm/i915/i915_request.c
@@ -409,7 +409,7 @@ static void i915_request_retire(struct i915_request *request)
 	 * the subsequent request.
 	 */
 	if (engine->last_retired_context)
-		engine->context_unpin(engine, engine->last_retired_context);
+		intel_context_unpin(engine->last_retired_context, engine);
 	engine->last_retired_context = request->ctx;
 
 	spin_lock_irq(&request->lock);
@@ -638,7 +638,7 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx)
 	 * GGTT space, so do this first before we reserve a seqno for
 	 * ourselves.
 	 */
-	ring = engine->context_pin(engine, ctx);
+	ring = intel_context_pin(ctx, engine);
 	if (IS_ERR(ring))
 		return ERR_CAST(ring);
 	GEM_BUG_ON(!ring);
@@ -787,7 +787,7 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx)
 err_unreserve:
 	unreserve_gt(i915);
 err_unpin:
-	engine->context_unpin(engine, ctx);
+	intel_context_unpin(ctx, engine);
 	return ERR_PTR(ret);
 }
 
diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c
index eba81d55dc3a..238c8d3da041 100644
--- a/drivers/gpu/drm/i915/intel_engine_cs.c
+++ b/drivers/gpu/drm/i915/intel_engine_cs.c
@@ -685,7 +685,7 @@ int intel_engine_init_common(struct intel_engine_cs *engine)
 	 * be available. To avoid this we always pin the default
 	 * context.
 	 */
-	ring = engine->context_pin(engine, engine->i915->kernel_context);
+	ring = intel_context_pin(engine->i915->kernel_context, engine);
 	if (IS_ERR(ring))
 		return PTR_ERR(ring);
 
@@ -694,8 +694,7 @@ int intel_engine_init_common(struct intel_engine_cs *engine)
 	 * we can interrupt the engine at any time.
 	 */
 	if (engine->i915->preempt_context) {
-		ring = engine->context_pin(engine,
-					   engine->i915->preempt_context);
+		ring = intel_context_pin(engine->i915->preempt_context, engine);
 		if (IS_ERR(ring)) {
 			ret = PTR_ERR(ring);
 			goto err_unpin_kernel;
@@ -719,9 +718,9 @@ int intel_engine_init_common(struct intel_engine_cs *engine)
 	intel_engine_fini_breadcrumbs(engine);
 err_unpin_preempt:
 	if (engine->i915->preempt_context)
-		engine->context_unpin(engine, engine->i915->preempt_context);
+		intel_context_unpin(engine->i915->preempt_context, engine);
 err_unpin_kernel:
-	engine->context_unpin(engine, engine->i915->kernel_context);
+	intel_context_unpin(engine->i915->kernel_context, engine);
 	return ret;
 }
 
@@ -749,8 +748,8 @@ void intel_engine_cleanup_common(struct intel_engine_cs *engine)
 		i915_gem_object_put(engine->default_state);
 
 	if (engine->i915->preempt_context)
-		engine->context_unpin(engine, engine->i915->preempt_context);
-	engine->context_unpin(engine, engine->i915->kernel_context);
+		intel_context_unpin(engine->i915->preempt_context, engine);
+	intel_context_unpin(engine->i915->kernel_context, engine);
 }
 
 u64 intel_engine_get_active_head(const struct intel_engine_cs *engine)
diff --git a/drivers/gpu/drm/i915/intel_guc_ads.c b/drivers/gpu/drm/i915/intel_guc_ads.c
index 334cb5202e1c..dcaa3fb71765 100644
--- a/drivers/gpu/drm/i915/intel_guc_ads.c
+++ b/drivers/gpu/drm/i915/intel_guc_ads.c
@@ -121,7 +121,8 @@ int intel_guc_ads_create(struct intel_guc *guc)
 	 * to find it. Note that we have to skip our header (1 page),
 	 * because our GuC shared data is there.
 	 */
-	kernel_ctx_vma = dev_priv->kernel_context->engine[RCS].state;
+	kernel_ctx_vma = to_intel_context(dev_priv->kernel_context,
+					  dev_priv->engine[RCS])->state;
 	blob->ads.golden_context_lrca =
 		intel_guc_ggtt_offset(guc, kernel_ctx_vma) + skipped_offset;
 
diff --git a/drivers/gpu/drm/i915/intel_guc_submission.c b/drivers/gpu/drm/i915/intel_guc_submission.c
index 02da05875aa7..6e6ed0f46bd3 100644
--- a/drivers/gpu/drm/i915/intel_guc_submission.c
+++ b/drivers/gpu/drm/i915/intel_guc_submission.c
@@ -362,7 +362,7 @@ static void guc_stage_desc_init(struct intel_guc *guc,
 	desc->db_id = client->doorbell_id;
 
 	for_each_engine_masked(engine, dev_priv, client->engines, tmp) {
-		struct intel_context *ce = &ctx->engine[engine->id];
+		struct intel_context *ce = to_intel_context(ctx, engine);
 		u32 guc_engine_id = engine->guc_id;
 		struct guc_execlist_context *lrc = &desc->lrc[guc_engine_id];
 
@@ -990,7 +990,8 @@ static void guc_fill_preempt_context(struct intel_guc *guc)
 	enum intel_engine_id id;
 
 	for_each_engine(engine, dev_priv, id) {
-		struct intel_context *ce = &client->owner->engine[id];
+		struct intel_context *ce =
+			to_intel_context(client->owner, engine);
 		u32 addr = intel_hws_preempt_done_address(engine);
 		u32 *cs;
 
diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index ce23d5116482..79af778621a1 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -223,7 +223,7 @@ static void
 intel_lr_context_descriptor_update(struct i915_gem_context *ctx,
 				   struct intel_engine_cs *engine)
 {
-	struct intel_context *ce = &ctx->engine[engine->id];
+	struct intel_context *ce = to_intel_context(ctx, engine);
 	u64 desc;
 
 	BUILD_BUG_ON(MAX_CONTEXT_HW_ID > (BIT(GEN8_CTX_ID_WIDTH)));
@@ -414,7 +414,7 @@ execlists_update_context_pdps(struct i915_hw_ppgtt *ppgtt, u32 *reg_state)
 
 static u64 execlists_update_context(struct i915_request *rq)
 {
-	struct intel_context *ce = &rq->ctx->engine[rq->engine->id];
+	struct intel_context *ce = to_intel_context(rq->ctx, rq->engine);
 	struct i915_hw_ppgtt *ppgtt =
 		rq->ctx->ppgtt ?: rq->i915->mm.aliasing_ppgtt;
 	u32 *reg_state = ce->lrc_reg_state;
@@ -523,7 +523,7 @@ static void inject_preempt_context(struct intel_engine_cs *engine)
 {
 	struct intel_engine_execlists *execlists = &engine->execlists;
 	struct intel_context *ce =
-		&engine->i915->preempt_context->engine[engine->id];
+		to_intel_context(engine->i915->preempt_context, engine);
 	unsigned int n;
 
 	GEM_BUG_ON(execlists->preempt_complete_status !=
@@ -1328,7 +1328,7 @@ static struct intel_ring *
 execlists_context_pin(struct intel_engine_cs *engine,
 		      struct i915_gem_context *ctx)
 {
-	struct intel_context *ce = &ctx->engine[engine->id];
+	struct intel_context *ce = to_intel_context(ctx, engine);
 	void *vaddr;
 	int ret;
 
@@ -1381,7 +1381,7 @@ execlists_context_pin(struct intel_engine_cs *engine,
 static void execlists_context_unpin(struct intel_engine_cs *engine,
 				    struct i915_gem_context *ctx)
 {
-	struct intel_context *ce = &ctx->engine[engine->id];
+	struct intel_context *ce = to_intel_context(ctx, engine);
 
 	lockdep_assert_held(&ctx->i915->drm.struct_mutex);
 	GEM_BUG_ON(ce->pin_count == 0);
@@ -1400,8 +1400,8 @@ static void execlists_context_unpin(struct intel_engine_cs *engine,
 
 static int execlists_request_alloc(struct i915_request *request)
 {
-	struct intel_engine_cs *engine = request->engine;
-	struct intel_context *ce = &request->ctx->engine[engine->id];
+	struct intel_context *ce =
+		to_intel_context(request->ctx, request->engine);
 	int ret;
 
 	GEM_BUG_ON(!ce->pin_count);
@@ -1855,7 +1855,7 @@ static void reset_common_ring(struct intel_engine_cs *engine,
 	 * future request will be after userspace has had the opportunity
 	 * to recreate its own state.
 	 */
-	ce = &request->ctx->engine[engine->id];
+	ce = to_intel_context(request->ctx, engine);
 	execlists_init_reg_state(ce->lrc_reg_state,
 				 request->ctx, engine, ce->ring);
 
@@ -2296,9 +2296,13 @@ static int logical_ring_init(struct intel_engine_cs *engine)
 	}
 
 	engine->execlists.preempt_complete_status = ~0u;
-	if (engine->i915->preempt_context)
+	if (engine->i915->preempt_context) {
+		struct intel_context *ce =
+			to_intel_context(engine->i915->preempt_context, engine);
+
 		engine->execlists.preempt_complete_status =
-			upper_32_bits(engine->i915->preempt_context->engine[engine->id].lrc_desc);
+			upper_32_bits(ce->lrc_desc);
+	}
 
 	return 0;
 
@@ -2580,7 +2584,7 @@ static int execlists_context_deferred_alloc(struct i915_gem_context *ctx,
 					    struct intel_engine_cs *engine)
 {
 	struct drm_i915_gem_object *ctx_obj;
-	struct intel_context *ce = &ctx->engine[engine->id];
+	struct intel_context *ce = to_intel_context(ctx, engine);
 	struct i915_vma *vma;
 	uint32_t context_size;
 	struct intel_ring *ring;
@@ -2651,7 +2655,8 @@ void intel_lr_context_resume(struct drm_i915_private *dev_priv)
 	 */
 	list_for_each_entry(ctx, &dev_priv->contexts.list, link) {
 		for_each_engine(engine, dev_priv, id) {
-			struct intel_context *ce = &ctx->engine[engine->id];
+			struct intel_context *ce =
+				to_intel_context(ctx, engine);
 			u32 *reg;
 
 			if (!ce->state)
diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h
index 59d7b86012e9..4ec7d8dd13c8 100644
--- a/drivers/gpu/drm/i915/intel_lrc.h
+++ b/drivers/gpu/drm/i915/intel_lrc.h
@@ -108,7 +108,7 @@ static inline uint64_t
 intel_lr_context_descriptor(struct i915_gem_context *ctx,
 			    struct intel_engine_cs *engine)
 {
-	return ctx->engine[engine->id].lrc_desc;
+	return to_intel_context(ctx, engine)->lrc_desc;
 }
 
 #endif /* _INTEL_LRC_H_ */
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index c06c22c953b3..69ffc0dfe92b 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -558,7 +558,8 @@ static void reset_ring_common(struct intel_engine_cs *engine,
 	 */
 	if (request) {
 		struct drm_i915_private *dev_priv = request->i915;
-		struct intel_context *ce = &request->ctx->engine[engine->id];
+		struct intel_context *ce = to_intel_context(request->ctx,
+							    engine);
 		struct i915_hw_ppgtt *ppgtt;
 
 		if (ce->state) {
@@ -1163,9 +1164,9 @@ intel_ring_free(struct intel_ring *ring)
 	kfree(ring);
 }
 
-static int context_pin(struct i915_gem_context *ctx)
+static int context_pin(struct intel_context *ce)
 {
-	struct i915_vma *vma = ctx->engine[RCS].state;
+	struct i915_vma *vma = ce->state;
 	int ret;
 
 	/*
@@ -1256,7 +1257,7 @@ static struct intel_ring *
 intel_ring_context_pin(struct intel_engine_cs *engine,
 		       struct i915_gem_context *ctx)
 {
-	struct intel_context *ce = &ctx->engine[engine->id];
+	struct intel_context *ce = to_intel_context(ctx, engine);
 	int ret;
 
 	lockdep_assert_held(&ctx->i915->drm.struct_mutex);
@@ -1278,7 +1279,7 @@ intel_ring_context_pin(struct intel_engine_cs *engine,
 	}
 
 	if (ce->state) {
-		ret = context_pin(ctx);
+		ret = context_pin(ce);
 		if (ret)
 			goto err;
 
@@ -1299,7 +1300,7 @@ intel_ring_context_pin(struct intel_engine_cs *engine,
 static void intel_ring_context_unpin(struct intel_engine_cs *engine,
 				     struct i915_gem_context *ctx)
 {
-	struct intel_context *ce = &ctx->engine[engine->id];
+	struct intel_context *ce = to_intel_context(ctx, engine);
 
 	lockdep_assert_held(&ctx->i915->drm.struct_mutex);
 	GEM_BUG_ON(ce->pin_count == 0);
@@ -1427,7 +1428,7 @@ static inline int mi_set_context(struct i915_request *rq, u32 flags)
 
 	*cs++ = MI_NOOP;
 	*cs++ = MI_SET_CONTEXT;
-	*cs++ = i915_ggtt_offset(rq->ctx->engine[RCS].state) | flags;
+	*cs++ = i915_ggtt_offset(to_intel_context(rq->ctx, engine)->state) | flags;
 	/*
 	 * w/a: MI_SET_CONTEXT must always be followed by MI_NOOP
 	 * WaMiSetContext_Hang:snb,ivb,vlv
@@ -1518,7 +1519,7 @@ static int switch_context(struct i915_request *rq)
 		hw_flags = MI_FORCE_RESTORE;
 	}
 
-	if (to_ctx->engine[engine->id].state &&
+	if (to_intel_context(to_ctx, engine)->state &&
 	    (to_ctx != from_ctx || hw_flags & MI_FORCE_RESTORE)) {
 		GEM_BUG_ON(engine->id != RCS);
 
@@ -1566,7 +1567,7 @@ static int ring_request_alloc(struct i915_request *request)
 {
 	int ret;
 
-	GEM_BUG_ON(!request->ctx->engine[request->engine->id].pin_count);
+	GEM_BUG_ON(!to_intel_context(request->ctx, request->engine)->pin_count);
 
 	/* Flush enough space to reduce the likelihood of waiting after
 	 * we start building the request - in which case we will just
diff --git a/drivers/gpu/drm/i915/selftests/mock_engine.c b/drivers/gpu/drm/i915/selftests/mock_engine.c
index 78a89efa1119..3ed0557316d4 100644
--- a/drivers/gpu/drm/i915/selftests/mock_engine.c
+++ b/drivers/gpu/drm/i915/selftests/mock_engine.c
@@ -217,7 +217,7 @@ void mock_engine_free(struct intel_engine_cs *engine)
 	GEM_BUG_ON(timer_pending(&mock->hw_delay));
 
 	if (engine->last_retired_context)
-		engine->context_unpin(engine, engine->last_retired_context);
+		intel_context_unpin(engine->last_retired_context, engine);
 
 	intel_engine_fini_breadcrumbs(engine);
 
-- 
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] 24+ messages in thread

* [PATCH 3/7] drm/i915: Retire requests along rings
  2018-04-26 17:49 [PATCH 1/7] drm/i915: Stop tracking timeline->inflight_seqnos Chris Wilson
  2018-04-26 17:49 ` [PATCH 2/7] drm/i915: Wrap engine->context_pin() and engine->context_unpin() Chris Wilson
@ 2018-04-26 17:49 ` Chris Wilson
  2018-04-27 12:50   ` Tvrtko Ursulin
  2018-04-26 17:49 ` [PATCH 4/7] drm/i915: Only track live rings for retiring Chris Wilson
                   ` (10 subsequent siblings)
  12 siblings, 1 reply; 24+ messages in thread
From: Chris Wilson @ 2018-04-26 17:49 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!

v2: We need both engine-order and ring-order processing to maintain our
knowledge of where individual rings have completed upto as well as
knowing what was last executing on any engine. And finally by decoupling
retiring the contexts on the engine and the timelines along the rings,
we do have to keep a reference to the context on each request
(previously it was guaranteed by the context being pinned).

v3: Not just a reference to the context, but we need to keep it pinned
as we manipulate the rings; i.e. we need a pin for both the manipulation
of the engine state during its retirements, and a separate pin for the
manipulation of the ring state.

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           | 150 +++++++++++-------
 drivers/gpu/drm/i915/i915_utils.h             |   6 +
 drivers/gpu/drm/i915/intel_ringbuffer.c       |   6 +-
 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 +
 8 files changed, 131 insertions(+), 65 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 8fd9fb6efba5..1837c01d44d0 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;
 		u32 request_serial;
 
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 4090bfdda340..f0644d1fbd75 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 9358f2cf0c32..e6535255d445 100644
--- a/drivers/gpu/drm/i915/i915_request.c
+++ b/drivers/gpu/drm/i915/i915_request.c
@@ -286,6 +286,7 @@ static int reserve_gt(struct drm_i915_private *i915)
 
 static void unreserve_gt(struct drm_i915_private *i915)
 {
+	GEM_BUG_ON(!i915->gt.active_requests);
 	if (!--i915->gt.active_requests)
 		i915_gem_park(i915);
 }
@@ -298,6 +299,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;
 
 	/*
@@ -309,7 +311,8 @@ 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(!list_is_first(&request->ring_link, &ring->request_list));
+	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
@@ -322,9 +325,9 @@ static void advance_ring(struct i915_request *request)
 	} else {
 		tail = request->postfix;
 	}
-	list_del(&request->ring_link);
+	list_del_init(&request->ring_link);
 
-	request->ring->head = tail;
+	ring->head = tail;
 }
 
 static void free_capture_list(struct i915_request *request)
@@ -340,30 +343,84 @@ static void free_capture_list(struct i915_request *request)
 	}
 }
 
+static void __retire_engine_request(struct intel_engine_cs *engine,
+				    struct i915_request *rq)
+{
+	GEM_TRACE("%s(%s) fence %llx:%d, global=%d, current %d\n",
+		  __func__, engine->name,
+		  rq->fence.context, rq->fence.seqno,
+		  rq->global_seqno,
+		  intel_engine_get_seqno(engine));
+
+	GEM_BUG_ON(!i915_request_completed(rq));
+
+	local_irq_disable();
+
+	spin_lock(&engine->timeline->lock);
+	GEM_BUG_ON(!list_is_first(&rq->link, &engine->timeline->requests));
+	list_del_init(&rq->link);
+	spin_unlock(&engine->timeline->lock);
+
+	spin_lock(&rq->lock);
+	if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &rq->fence.flags))
+		dma_fence_signal_locked(&rq->fence);
+	if (test_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, &rq->fence.flags))
+		intel_engine_cancel_signaling(rq);
+	if (rq->waitboost) {
+		GEM_BUG_ON(!atomic_read(&rq->i915->gt_pm.rps.num_waiters));
+		atomic_dec(&rq->i915->gt_pm.rps.num_waiters);
+	}
+	spin_unlock(&rq->lock);
+
+	local_irq_enable();
+
+	/*
+	 * The backing object for the context is done after switching to the
+	 * *next* context. Therefore we cannot retire the previous context until
+	 * the next context has already started running. However, since we
+	 * cannot take the required locks at i915_request_submit() we
+	 * defer the unpinning of the active context to now, retirement of
+	 * the subsequent request.
+	 */
+	if (engine->last_retired_context)
+		intel_context_unpin(engine->last_retired_context, engine);
+	engine->last_retired_context = rq->ctx;
+}
+
+static void __retire_engine_upto(struct intel_engine_cs *engine,
+				 struct i915_request *rq)
+{
+	struct i915_request *tmp;
+
+	if (list_empty(&rq->link))
+		return;
+
+	do {
+		tmp = list_first_entry(&engine->timeline->requests,
+				       typeof(*tmp), link);
+
+		GEM_BUG_ON(tmp->engine != engine);
+		__retire_engine_request(engine, tmp);
+	} while (tmp != rq);
+}
+
 static void i915_request_retire(struct i915_request *request)
 {
-	struct intel_engine_cs *engine = request->engine;
 	struct i915_gem_active *active, *next;
 
 	GEM_TRACE("%s fence %llx:%d, global=%d, current %d\n",
-		  engine->name,
+		  request->engine->name,
 		  request->fence.context, request->fence.seqno,
 		  request->global_seqno,
-		  intel_engine_get_seqno(engine));
+		  intel_engine_get_seqno(request->engine));
 
 	lockdep_assert_held(&request->i915->drm.struct_mutex);
 	GEM_BUG_ON(!i915_sw_fence_signaled(&request->submit));
 	GEM_BUG_ON(!i915_request_completed(request));
-	GEM_BUG_ON(!request->i915->gt.active_requests);
 
 	trace_i915_request_retire(request);
 
-	spin_lock_irq(&engine->timeline->lock);
-	list_del_init(&request->link);
-	spin_unlock_irq(&engine->timeline->lock);
-
 	advance_ring(request);
-
 	free_capture_list(request);
 
 	/*
@@ -399,29 +456,9 @@ static void i915_request_retire(struct i915_request *request)
 
 	/* Retirement decays the ban score as it is a sign of ctx progress */
 	atomic_dec_if_positive(&request->ctx->ban_score);
+	intel_context_unpin(request->ctx, request->engine);
 
-	/*
-	 * The backing object for the context is done after switching to the
-	 * *next* context. Therefore we cannot retire the previous context until
-	 * the next context has already started running. However, since we
-	 * cannot take the required locks at i915_request_submit() we
-	 * defer the unpinning of the active context to now, retirement of
-	 * the subsequent request.
-	 */
-	if (engine->last_retired_context)
-		intel_context_unpin(engine->last_retired_context, engine);
-	engine->last_retired_context = request->ctx;
-
-	spin_lock_irq(&request->lock);
-	if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &request->fence.flags))
-		dma_fence_signal_locked(&request->fence);
-	if (test_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, &request->fence.flags))
-		intel_engine_cancel_signaling(request);
-	if (request->waitboost) {
-		GEM_BUG_ON(!atomic_read(&request->i915->gt_pm.rps.num_waiters));
-		atomic_dec(&request->i915->gt_pm.rps.num_waiters);
-	}
-	spin_unlock_irq(&request->lock);
+	__retire_engine_upto(request->engine, request);
 
 	unreserve_gt(request->i915);
 
@@ -431,18 +468,24 @@ 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;
 
+	GEM_TRACE("%s fence %llx:%d, global=%d, current %d\n",
+		  rq->engine->name,
+		  rq->fence.context, rq->fence.seqno,
+		  rq->global_seqno,
+		  intel_engine_get_seqno(rq->engine));
+
 	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);
@@ -651,9 +694,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);
 
@@ -771,6 +814,9 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx)
 	if (ret)
 		goto err_unwind;
 
+	/* Keep a second pin for the dual retirement along engine and ring */
+	__intel_context_pin(rq->ctx, engine);
+
 	/* Check that we didn't interrupt ourselves with a new request */
 	GEM_BUG_ON(rq->timeline->seqno != rq->fence.seqno);
 	return rq;
@@ -1357,38 +1403,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/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 69ffc0dfe92b..ae8958007df5 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -1066,7 +1066,6 @@ int intel_ring_pin(struct intel_ring *ring,
 
 void intel_ring_reset(struct intel_ring *ring, u32 tail)
 {
-	GEM_BUG_ON(!list_empty(&ring->request_list));
 	ring->tail = tail;
 	ring->head = tail;
 	ring->emit = tail;
@@ -1125,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)
@@ -1150,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;
 }
 
@@ -1161,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 24af3f1088ba..deb80d01e0bd 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -130,6 +130,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 3ed0557316d4..42967fc09eb0 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)
 		intel_context_unpin(engine->last_retired_context, engine);
 
+	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] 24+ messages in thread

* [PATCH 4/7] drm/i915: Only track live rings for retiring
  2018-04-26 17:49 [PATCH 1/7] drm/i915: Stop tracking timeline->inflight_seqnos Chris Wilson
  2018-04-26 17:49 ` [PATCH 2/7] drm/i915: Wrap engine->context_pin() and engine->context_unpin() Chris Wilson
  2018-04-26 17:49 ` [PATCH 3/7] drm/i915: Retire requests along rings Chris Wilson
@ 2018-04-26 17:49 ` Chris Wilson
  2018-04-27 12:52   ` Tvrtko Ursulin
  2018-04-26 17:49 ` [PATCH 5/7] drm/i915: Move timeline from GTT to ring Chris Wilson
                   ` (9 subsequent siblings)
  12 siblings, 1 reply; 24+ messages in thread
From: Chris Wilson @ 2018-04-26 17:49 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.

v2: s/live/active/ for consistency with gt.active_requests

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                  |  3 ++-
 drivers/gpu/drm/i915/i915_gem.c                  |  6 ++++--
 drivers/gpu/drm/i915/i915_request.c              | 10 ++++++++--
 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 |  5 +++--
 7 files changed, 18 insertions(+), 16 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 1837c01d44d0..54351cace362 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2060,7 +2060,8 @@ struct drm_i915_private {
 
 		struct i915_gem_timeline global_timeline;
 		struct list_head timelines;
-		struct list_head rings;
+
+		struct list_head active_rings;
 		u32 active_requests;
 		u32 request_serial;
 
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index f0644d1fbd75..fa1d94a4eb5f 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.active_rings));
 
 	if (!i915->gt.awake)
 		return I915_EPOCH_INVALID;
@@ -5599,9 +5600,10 @@ 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.rings);
 	INIT_LIST_HEAD(&dev_priv->gt.timelines);
+	INIT_LIST_HEAD(&dev_priv->gt.active_rings);
+
+	mutex_lock(&dev_priv->drm.struct_mutex);
 	err = i915_gem_timeline_init__global(dev_priv);
 	mutex_unlock(&dev_priv->drm.struct_mutex);
 	if (err)
diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c
index e6535255d445..c8fc4b323e62 100644
--- a/drivers/gpu/drm/i915/i915_request.c
+++ b/drivers/gpu/drm/i915/i915_request.c
@@ -322,6 +322,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->active_link);
 	} else {
 		tail = request->postfix;
 	}
@@ -1096,6 +1097,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->active_link, &request->i915->gt.active_rings);
 	request->emitted_jiffies = jiffies;
 
 	/*
@@ -1418,14 +1421,17 @@ static void ring_retire_requests(struct intel_ring *ring)
 
 void i915_retire_requests(struct drm_i915_private *i915)
 {
-	struct intel_ring *ring, *next;
+	struct intel_ring *ring, *tmp;
 
 	lockdep_assert_held(&i915->drm.struct_mutex);
 
 	if (!i915->gt.active_requests)
 		return;
 
-	list_for_each_entry_safe(ring, next, &i915->gt.rings, link)
+	/* An outstanding request must be on a still active ring somewhere */
+	GEM_BUG_ON(list_empty(&i915->gt.active_rings));
+
+	list_for_each_entry_safe(ring, tmp, &i915->gt.active_rings, active_link)
 		ring_retire_requests(ring);
 }
 
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index ae8958007df5..007449cfa22b 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 deb80d01e0bd..fd679cec9ac6 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -130,7 +130,7 @@ struct intel_ring {
 	void *vaddr;
 
 	struct list_head request_list;
-	struct list_head link;
+	struct list_head active_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 42967fc09eb0..629870aeb547 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..f22a2b35a283 100644
--- a/drivers/gpu/drm/i915/selftests/mock_gem_device.c
+++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
@@ -224,9 +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.rings);
 	INIT_LIST_HEAD(&i915->gt.timelines);
+	INIT_LIST_HEAD(&i915->gt.active_rings);
+
+	mutex_lock(&i915->drm.struct_mutex);
 	err = i915_gem_timeline_init__global(i915);
 	if (err) {
 		mutex_unlock(&i915->drm.struct_mutex);
-- 
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] 24+ messages in thread

* [PATCH 5/7] drm/i915: Move timeline from GTT to ring
  2018-04-26 17:49 [PATCH 1/7] drm/i915: Stop tracking timeline->inflight_seqnos Chris Wilson
                   ` (2 preceding siblings ...)
  2018-04-26 17:49 ` [PATCH 4/7] drm/i915: Only track live rings for retiring Chris Wilson
@ 2018-04-26 17:49 ` Chris Wilson
  2018-04-27 13:01   ` Tvrtko Ursulin
  2018-04-26 17:49 ` [PATCH 6/7] drm/i915: Split i915_gem_timeline into individual timelines Chris Wilson
                   ` (8 subsequent siblings)
  12 siblings, 1 reply; 24+ messages in thread
From: Chris Wilson @ 2018-04-26 17:49 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.

v2: Reinforce that one isn't allowed to mix the engine execution
timeline with the client timeline from userspace (on the ring).

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           | 13 +++--
 drivers/gpu/drm/i915/intel_engine_cs.c        |  3 +-
 drivers/gpu/drm/i915/intel_lrc.c              |  2 +-
 drivers/gpu/drm/i915/intel_ringbuffer.c       | 10 +++-
 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(+), 41 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 54351cace362..b9bd8328f501 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 active_rings;
@@ -3234,16 +3235,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 fa1d94a4eb5f..438a2fc5bba0 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;
@@ -5652,7 +5652,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 59d4bd4a7b73..1f4987dc6616 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 (n = 0; n < ARRAY_SIZE(ctx->__engine); n++) {
@@ -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 ace3b129c189..ec53ba06f836 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 c8fc4b323e62..7bb613c00cc3 100644
--- a/drivers/gpu/drm/i915/i915_request.c
+++ b/drivers/gpu/drm/i915/i915_request.c
@@ -758,7 +758,12 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx)
 		}
 	}
 
-	rq->timeline = i915_gem_context_lookup_timeline(ctx, engine);
+	INIT_LIST_HEAD(&rq->active_list);
+	rq->i915 = i915;
+	rq->engine = engine;
+	rq->ctx = ctx;
+	rq->ring = ring;
+	rq->timeline = ring->timeline;
 	GEM_BUG_ON(rq->timeline == engine->timeline);
 
 	spin_lock_init(&rq->lock);
@@ -774,12 +779,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 238c8d3da041..9d127e65113b 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 79af778621a1..ef888f3c0f44 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -2613,7 +2613,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 007449cfa22b..b73e700c3048 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -1117,13 +1117,16 @@ 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;
 
 	GEM_BUG_ON(!is_power_of_2(size));
 	GEM_BUG_ON(RING_CTL_SIZE(size) & ~RING_NR_PAGES);
+	GEM_BUG_ON(&timeline->engine[engine->id] == engine->timeline);
 	lockdep_assert_held(&engine->i915->drm.struct_mutex);
 
 	ring = kzalloc(sizeof(*ring), GFP_KERNEL);
@@ -1131,6 +1134,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 +1331,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 fd679cec9ac6..da53aa2973a7 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -129,6 +129,7 @@ struct intel_ring {
 	struct i915_vma *vma;
 	void *vaddr;
 
+	struct intel_timeline *timeline;
 	struct list_head request_list;
 	struct list_head active_link;
 
@@ -768,7 +769,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 629870aeb547..6835edf278fe 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 f22a2b35a283..f11c83e8ff32 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] 24+ messages in thread

* [PATCH 6/7] drm/i915: Split i915_gem_timeline into individual timelines
  2018-04-26 17:49 [PATCH 1/7] drm/i915: Stop tracking timeline->inflight_seqnos Chris Wilson
                   ` (3 preceding siblings ...)
  2018-04-26 17:49 ` [PATCH 5/7] drm/i915: Move timeline from GTT to ring Chris Wilson
@ 2018-04-26 17:49 ` Chris Wilson
  2018-04-27 14:37   ` Tvrtko Ursulin
  2018-04-26 17:49 ` [PATCH 7/7] drm/i915: Lazily unbind vma on close Chris Wilson
                   ` (7 subsequent siblings)
  12 siblings, 1 reply; 24+ messages in thread
From: Chris Wilson @ 2018-04-26 17:49 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.

v2: Tweak wait_for_idle to stop the compiling thinking that ret may be
uninitialised.

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               | 129 +++++-------
 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           |  68 +++---
 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       |  25 ++-
 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  |  10 +-
 .../gpu/drm/i915/selftests/mock_timeline.c    |  45 ++--
 .../gpu/drm/i915/selftests/mock_timeline.h    |  28 +--
 23 files changed, 398 insertions(+), 570 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 b9bd8328f501..dab15b6abc3c 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 active_rings;
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 438a2fc5bba0..484354f25f98 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,17 +3731,9 @@ 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)
+static int wait_for_timeline(struct i915_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;
+	return i915_gem_active_wait(&tl->last_request, flags);
 }
 
 static int wait_for_engines(struct drm_i915_private *i915)
@@ -3762,30 +3751,37 @@ static int wait_for_engines(struct drm_i915_private *i915)
 
 int i915_gem_wait_for_idle(struct drm_i915_private *i915, unsigned int flags)
 {
-	int ret;
-
 	/* If the device is asleep, we have no requests outstanding */
 	if (!READ_ONCE(i915->gt.awake))
 		return 0;
 
 	if (flags & I915_WAIT_LOCKED) {
-		struct i915_gem_timeline *tl;
+		struct i915_timeline *tl;
+		int err;
 
 		lockdep_assert_held(&i915->drm.struct_mutex);
 
 		list_for_each_entry(tl, &i915->gt.timelines, link) {
-			ret = wait_for_timeline(tl, flags);
-			if (ret)
-				return ret;
+			err = wait_for_timeline(tl, flags);
+			if (err)
+				return err;
 		}
 		i915_retire_requests(i915);
 
-		ret = wait_for_engines(i915);
+		return wait_for_engines(i915);
 	} else {
-		ret = wait_for_timeline(&i915->gt.execution_timeline, flags);
-	}
+		struct intel_engine_cs *engine;
+		enum intel_engine_id id;
+		int err;
 
-	return ret;
+		for_each_engine(engine, i915, id) {
+			err = wait_for_timeline(&engine->timeline, flags);
+			if (err)
+				return err;
+		}
+
+		return 0;
+	}
 }
 
 static void __i915_gem_object_flush_for_display(struct drm_i915_gem_object *obj)
@@ -4954,7 +4950,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);
 	}
 }
@@ -5603,12 +5599,6 @@ int i915_gem_init_early(struct drm_i915_private *dev_priv)
 	INIT_LIST_HEAD(&dev_priv->gt.timelines);
 	INIT_LIST_HEAD(&dev_priv->gt.active_rings);
 
-	mutex_lock(&dev_priv->drm.struct_mutex);
-	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);
 
 	INIT_DELAYED_WORK(&dev_priv->gt.retire_work,
@@ -5628,8 +5618,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:
@@ -5650,12 +5638,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 1f4987dc6616..c9cdf88693bc 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 (n = 0; n < ARRAY_SIZE(ctx->__engine); n++) {
@@ -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 ec53ba06f836..ace3b129c189 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 c0127965b578..5fd7cfd771a7 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 4b1da01168ae..d9341415df40 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 7bb613c00cc3..5acf869f3ca3 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,18 +228,18 @@ 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));
+
 	i915->gt.request_serial = seqno;
+
 	return 0;
 }
 
@@ -357,10 +355,10 @@ static void __retire_engine_request(struct intel_engine_cs *engine,
 
 	local_irq_disable();
 
-	spin_lock(&engine->timeline->lock);
-	GEM_BUG_ON(!list_is_first(&rq->link, &engine->timeline->requests));
+	spin_lock(&engine->timeline.lock);
+	GEM_BUG_ON(!list_is_first(&rq->link, &engine->timeline.requests));
 	list_del_init(&rq->link);
-	spin_unlock(&engine->timeline->lock);
+	spin_unlock(&engine->timeline.lock);
 
 	spin_lock(&rq->lock);
 	if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &rq->fence.flags))
@@ -397,7 +395,7 @@ static void __retire_engine_upto(struct intel_engine_cs *engine,
 		return;
 
 	do {
-		tmp = list_first_entry(&engine->timeline->requests,
+		tmp = list_first_entry(&engine->timeline.requests,
 				       typeof(*tmp), link);
 
 		GEM_BUG_ON(tmp->engine != engine);
@@ -492,16 +490,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);
@@ -516,15 +514,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));
 
@@ -539,7 +537,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);
 
@@ -552,11 +550,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)
@@ -570,17 +568,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);
@@ -607,11 +605,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
@@ -764,7 +762,7 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx)
 	rq->ctx = ctx;
 	rq->ring = ring;
 	rq->timeline = ring->timeline;
-	GEM_BUG_ON(rq->timeline == engine->timeline);
+	GEM_BUG_ON(rq->timeline == &engine->timeline);
 
 	spin_lock_init(&rq->lock);
 	dma_fence_init(&rq->fence,
@@ -929,7 +927,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))
@@ -943,7 +941,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;
@@ -1020,7 +1018,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 9d127e65113b..268339203598 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);
@@ -751,6 +746,8 @@ void intel_engine_cleanup_common(struct intel_engine_cs *engine)
 	if (engine->i915->preempt_context)
 		intel_context_unpin(engine->i915->preempt_context, engine);
 	intel_context_unpin(engine->i915->kernel_context, engine);
+
+	i915_timeline_fini(&engine->timeline);
 }
 
 u64 intel_engine_get_active_head(const struct intel_engine_cs *engine)
@@ -1003,7 +1000,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
@@ -1334,14 +1331,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);
@@ -1373,11 +1370,11 @@ 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);
+	spin_lock_irq(&engine->timeline.lock);
 
 	last = NULL;
 	count = 0;
-	list_for_each_entry(rq, &engine->timeline->requests, link) {
+	list_for_each_entry(rq, &engine->timeline.requests, link) {
 		if (count++ < MAX_REQUESTS_TO_SHOW - 1)
 			print_request(m, rq, "\t\tE ");
 		else
@@ -1415,7 +1412,7 @@ void intel_engine_dump(struct intel_engine_cs *engine,
 		print_request(m, last, "\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 6e6ed0f46bd3..8aafbf2e01d0 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 ef888f3c0f44..9a9b4e777d7f 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);
@@ -893,10 +893,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);
@@ -928,7 +928,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);
 }
@@ -1166,7 +1166,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));
@@ -1174,7 +1174,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)
@@ -1190,8 +1190,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;
@@ -1274,7 +1274,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) {
@@ -1298,7 +1298,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)
@@ -1827,9 +1827,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);
 
@@ -2588,6 +2588,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)
@@ -2603,8 +2604,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);
@@ -2613,7 +2614,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 b73e700c3048..8f19349a6055 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -697,17 +697,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;
@@ -1126,7 +1126,7 @@ intel_engine_create_ring(struct intel_engine_cs *engine,
 
 	GEM_BUG_ON(!is_power_of_2(size));
 	GEM_BUG_ON(RING_CTL_SIZE(size) & ~RING_NR_PAGES);
-	GEM_BUG_ON(&timeline->engine[engine->id] == engine->timeline);
+	GEM_BUG_ON(timeline == &engine->timeline);
 	lockdep_assert_held(&engine->i915->drm.struct_mutex);
 
 	ring = kzalloc(sizeof(*ring), GFP_KERNEL);
@@ -1134,7 +1134,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
@@ -1165,6 +1165,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);
 }
 
@@ -1323,6 +1324,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);
@@ -1331,9 +1333,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 da53aa2973a7..010750e8ee44 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -6,12 +6,12 @@
 #include <linux/seqlock.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;
@@ -129,7 +129,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 active_link;
 
@@ -338,7 +338,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;
 
@@ -770,7 +771,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,
@@ -889,7 +890,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 6835edf278fe..cfa92d5d5bf0 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 f11c83e8ff32..a662c0450e77 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);
 
@@ -230,12 +228,6 @@ struct drm_i915_private *mock_gem_device(void)
 	INIT_LIST_HEAD(&i915->gt.active_rings);
 
 	mutex_lock(&i915->drm.struct_mutex);
-	err = i915_gem_timeline_init__global(i915);
-	if (err) {
-		mutex_unlock(&i915->drm.struct_mutex);
-		goto err_priorities;
-	}
-
 	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] 24+ messages in thread

* [PATCH 7/7] drm/i915: Lazily unbind vma on close
  2018-04-26 17:49 [PATCH 1/7] drm/i915: Stop tracking timeline->inflight_seqnos Chris Wilson
                   ` (4 preceding siblings ...)
  2018-04-26 17:49 ` [PATCH 6/7] drm/i915: Split i915_gem_timeline into individual timelines Chris Wilson
@ 2018-04-26 17:49 ` Chris Wilson
  2018-04-27 15:38   ` Tvrtko Ursulin
  2018-04-27  8:52 ` ✗ Fi.CI.CHECKPATCH: warning for series starting with [1/7] drm/i915: Stop tracking timeline->inflight_seqnos Patchwork
                   ` (6 subsequent siblings)
  12 siblings, 1 reply; 24+ messages in thread
From: Chris Wilson @ 2018-04-26 17:49 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.

v2: s/__i915_vma_final_close/i915_vma_destroy/ etc.

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    |  3 +-
 drivers/gpu/drm/i915/i915_gem_gtt.c           | 14 +++--
 drivers/gpu/drm/i915/i915_vma.c               | 61 +++++++++++++------
 drivers/gpu/drm/i915/i915_vma.h               |  6 ++
 drivers/gpu/drm/i915/selftests/huge_pages.c   |  2 +-
 .../gpu/drm/i915/selftests/mock_gem_device.c  |  1 +
 8 files changed, 67 insertions(+), 25 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index dab15b6abc3c..d4da9f941d04 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2061,6 +2061,7 @@ struct drm_i915_private {
 		struct list_head timelines;
 
 		struct list_head active_rings;
+		struct list_head closed_vma;
 		u32 active_requests;
 		u32 request_serial;
 
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 484354f25f98..5ece6ae4bdff 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;
 
@@ -4795,7 +4796,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_destroy(vma);
 		}
 		GEM_BUG_ON(!list_empty(&obj->vma_list));
 		GEM_BUG_ON(!RB_EMPTY_ROOT(&obj->vma_tree));
@@ -5598,6 +5599,7 @@ int i915_gem_init_early(struct drm_i915_private *dev_priv)
 
 	INIT_LIST_HEAD(&dev_priv->gt.timelines);
 	INIT_LIST_HEAD(&dev_priv->gt.active_rings);
+	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..f627a8c47c58 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -762,7 +762,8 @@ static int eb_lookup_vmas(struct i915_execbuffer *eb)
 		}
 
 		/* transfer ref to ctx */
-		vma->open_count++;
+		if (!vma->open_count++)
+			i915_vma_reopen(vma);
 		list_add(&lut->obj_link, &obj->lut_list);
 		list_add(&lut->ctx_link, &eb->ctx->handles_list);
 		lut->ctx = eb->ctx;
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index e9d828324f67..272d6bb407cc 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_destroy_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_destroy(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_destroy_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..81fa652ad78d 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;
@@ -684,13 +681,31 @@ int __i915_vma_do_pin(struct i915_vma *vma,
 	return ret;
 }
 
-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;
+
+	list_add_tail(&vma->closed_link, &vma->vm->i915->gt.closed_vma);
+}
+
+void i915_vma_reopen(struct i915_vma *vma)
+{
+	lockdep_assert_held(&vma->vm->i915->drm.struct_mutex);
+
+	if (vma->flags & I915_VMA_CLOSED) {
+		vma->flags &= ~I915_VMA_CLOSED;
+		list_del(&vma->closed_link);
+	}
+}
+
+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 +714,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));
@@ -706,15 +722,30 @@ static void i915_vma_destroy(struct i915_vma *vma)
 	kmem_cache_free(to_i915(vma->obj->base.dev)->vmas, vma);
 }
 
-void i915_vma_close(struct i915_vma *vma)
+void i915_vma_destroy(struct i915_vma *vma)
 {
-	GEM_BUG_ON(i915_vma_is_closed(vma));
-	vma->flags |= I915_VMA_CLOSED;
+	lockdep_assert_held(&vma->vm->i915->drm.struct_mutex);
 
-	rb_erase(&vma->obj_node, &vma->obj->vma_tree);
+	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);
 
-	if (!i915_vma_is_active(vma) && !i915_vma_is_pinned(vma))
-		WARN_ON(i915_vma_unbind(vma));
+	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) {
+		GEM_BUG_ON(!i915_vma_is_closed(vma));
+		i915_vma_destroy(vma);
+	}
+
+	GEM_BUG_ON(!list_empty(&i915->gt.closed_vma));
 }
 
 static void __i915_vma_iounmap(struct i915_vma *vma)
@@ -804,7 +835,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 +872,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..fc4294cfaa91 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,8 @@ 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_reopen(struct i915_vma *vma);
+void i915_vma_destroy(struct i915_vma *vma);
 
 int __i915_vma_do_pin(struct i915_vma *vma,
 		      u64 size, u64 alignment, u64 flags);
@@ -408,6 +412,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..d7c8ef8e6764 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_destroy(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 a662c0450e77..4b6622c6986a 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.timelines);
 	INIT_LIST_HEAD(&i915->gt.active_rings);
+	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] 24+ messages in thread

* ✗ Fi.CI.CHECKPATCH: warning for series starting with [1/7] drm/i915: Stop tracking timeline->inflight_seqnos
  2018-04-26 17:49 [PATCH 1/7] drm/i915: Stop tracking timeline->inflight_seqnos Chris Wilson
                   ` (5 preceding siblings ...)
  2018-04-26 17:49 ` [PATCH 7/7] drm/i915: Lazily unbind vma on close Chris Wilson
@ 2018-04-27  8:52 ` Patchwork
  2018-04-27  8:55 ` ✗ Fi.CI.SPARSE: " Patchwork
                   ` (5 subsequent siblings)
  12 siblings, 0 replies; 24+ messages in thread
From: Patchwork @ 2018-04-27  8:52 UTC (permalink / raw)
  To: Chris Wilson; +Cc: intel-gfx

== Series Details ==

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

== Summary ==

$ dim checkpatch origin/drm-tip
35d1fe2b7f54 drm/i915: Stop tracking timeline->inflight_seqnos
-:17: 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")'
#17: 
References: 9b6586ae9f6b ("drm/i915: Keep a global seqno per-engine")

total: 1 errors, 0 warnings, 0 checks, 128 lines checked
20c25ecb6898 drm/i915: Wrap engine->context_pin() and engine->context_unpin()
934b5fb6717d drm/i915: Retire requests along rings
0b75afb49522 drm/i915: Only track live rings for retiring
74dfea354317 drm/i915: Move timeline from GTT to ring
8acc3a732d03 drm/i915: Split i915_gem_timeline into individual timelines
-:464: WARNING:FILE_PATH_CHANGES: added, moved or deleted file(s), does MAINTAINERS need updating?
#464: 
deleted file mode 100644

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

total: 0 errors, 2 warnings, 0 checks, 1638 lines checked
67838145b9cf 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] 24+ messages in thread

* ✗ Fi.CI.SPARSE: warning for series starting with [1/7] drm/i915: Stop tracking timeline->inflight_seqnos
  2018-04-26 17:49 [PATCH 1/7] drm/i915: Stop tracking timeline->inflight_seqnos Chris Wilson
                   ` (6 preceding siblings ...)
  2018-04-27  8:52 ` ✗ Fi.CI.CHECKPATCH: warning for series starting with [1/7] drm/i915: Stop tracking timeline->inflight_seqnos Patchwork
@ 2018-04-27  8:55 ` Patchwork
  2018-04-27  9:07 ` ✗ Fi.CI.BAT: failure " Patchwork
                   ` (4 subsequent siblings)
  12 siblings, 0 replies; 24+ messages in thread
From: Patchwork @ 2018-04-27  8:55 UTC (permalink / raw)
  To: Chris Wilson; +Cc: intel-gfx

== Series Details ==

Series: series starting with [1/7] drm/i915: Stop tracking timeline->inflight_seqnos
URL   : https://patchwork.freedesktop.org/series/42360/
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/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: Wrap engine->context_pin() and engine->context_unpin()
Okay!

Commit: drm/i915: Retire requests along rings
-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:3661:16: warning: expression using sizeof(void)

Commit: drm/i915: Only track live rings for retiring
-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:3661:16: warning: expression using sizeof(void)
+drivers/gpu/drm/i915/selftests/../i915_drv.h:2214:33: warning: constant 0xffffea0000000000 is so big it is unsigned long
+drivers/gpu/drm/i915/selftests/../i915_drv.h:3662:16: warning: expression using sizeof(void)

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

Commit: drm/i915: Split i915_gem_timeline into individual timelines
-drivers/gpu/drm/i915/selftests/../i915_drv.h:2215:33: warning: constant 0xffffea0000000000 is so big it is unsigned long
-drivers/gpu/drm/i915/selftests/../i915_drv.h:3653: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: Lazily unbind vma on close
-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:2214:33: warning: constant 0xffffea0000000000 is so big it is unsigned long
+drivers/gpu/drm/i915/selftests/../i915_drv.h:3652: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] 24+ messages in thread

* ✗ Fi.CI.BAT: failure for series starting with [1/7] drm/i915: Stop tracking timeline->inflight_seqnos
  2018-04-26 17:49 [PATCH 1/7] drm/i915: Stop tracking timeline->inflight_seqnos Chris Wilson
                   ` (7 preceding siblings ...)
  2018-04-27  8:55 ` ✗ Fi.CI.SPARSE: " Patchwork
@ 2018-04-27  9:07 ` Patchwork
  2018-04-27 10:34 ` ✗ Fi.CI.CHECKPATCH: warning " Patchwork
                   ` (3 subsequent siblings)
  12 siblings, 0 replies; 24+ messages in thread
From: Patchwork @ 2018-04-27  9:07 UTC (permalink / raw)
  To: Chris Wilson; +Cc: intel-gfx

== Series Details ==

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

== Summary ==

= CI Bug Log - changes from CI_DRM_4106 -> Patchwork_8818 =

== Summary - FAILURE ==

  Serious unknown changes coming with Patchwork_8818 absolutely need to be
  verified manually.
  
  If you think the reported changes have nothing to do with the changes
  introduced in Patchwork_8818, 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/42360/revisions/1/mbox/

== Possible new issues ==

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

  === IGT changes ===

    ==== Possible regressions ====

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

    
    ==== Warnings ====

    igt@gem_exec_gttfill@basic:
      fi-pnv-d510:        SKIP -> PASS

    
== Known issues ==

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

  === IGT changes ===

    ==== Issues hit ====

    igt@gem_exec_suspend@basic-s4-devices:
      fi-kbl-7500u:       PASS -> DMESG-WARN (fdo#105128)

    igt@kms_pipe_crc_basic@suspend-read-crc-pipe-a:
      fi-cnl-y3:          PASS -> DMESG-WARN (fdo#104951)

    
    ==== Possible fixes ====

    igt@gem_mmap_gtt@basic-small-bo-tiledx:
      fi-gdg-551:         FAIL (fdo#102575) -> PASS

    igt@prime_vgem@basic-fence-flip:
      fi-ilk-650:         FAIL (fdo#104008) -> PASS

    
  fdo#102575 https://bugs.freedesktop.org/show_bug.cgi?id=102575
  fdo#104008 https://bugs.freedesktop.org/show_bug.cgi?id=104008
  fdo#104951 https://bugs.freedesktop.org/show_bug.cgi?id=104951
  fdo#105128 https://bugs.freedesktop.org/show_bug.cgi?id=105128


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

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


== Build changes ==

    * Linux: CI_DRM_4106 -> Patchwork_8818

  CI_DRM_4106: dd4a65248ce636039848b97f0b8e4704aa2f32b2 @ git://anongit.freedesktop.org/gfx-ci/linux
  IGT_4450: 0350f0e7f6a0e07281445fc3082aa70419f4aac7 @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools
  Patchwork_8818: 67838145b9cf732858cee3bb3da7d88ea5f22321 @ git://anongit.freedesktop.org/gfx-ci/linux
  piglit_4450: b57600ba58ae0cdbad86826fd653aa0191212f27 @ git://anongit.freedesktop.org/piglit


== Linux commits ==

67838145b9cf drm/i915: Lazily unbind vma on close
8acc3a732d03 drm/i915: Split i915_gem_timeline into individual timelines
74dfea354317 drm/i915: Move timeline from GTT to ring
0b75afb49522 drm/i915: Only track live rings for retiring
934b5fb6717d drm/i915: Retire requests along rings
20c25ecb6898 drm/i915: Wrap engine->context_pin() and engine->context_unpin()
35d1fe2b7f54 drm/i915: Stop tracking timeline->inflight_seqnos

== Logs ==

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

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

* ✗ Fi.CI.CHECKPATCH: warning for series starting with [1/7] drm/i915: Stop tracking timeline->inflight_seqnos
  2018-04-26 17:49 [PATCH 1/7] drm/i915: Stop tracking timeline->inflight_seqnos Chris Wilson
                   ` (8 preceding siblings ...)
  2018-04-27  9:07 ` ✗ Fi.CI.BAT: failure " Patchwork
@ 2018-04-27 10:34 ` Patchwork
  2018-04-27 10:37 ` ✗ Fi.CI.SPARSE: " Patchwork
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 24+ messages in thread
From: Patchwork @ 2018-04-27 10:34 UTC (permalink / raw)
  To: Chris Wilson; +Cc: intel-gfx

== Series Details ==

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

== Summary ==

$ dim checkpatch origin/drm-tip
346302027794 drm/i915: Stop tracking timeline->inflight_seqnos
-:17: 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")'
#17: 
References: 9b6586ae9f6b ("drm/i915: Keep a global seqno per-engine")

total: 1 errors, 0 warnings, 0 checks, 128 lines checked
8ab432091db4 drm/i915: Wrap engine->context_pin() and engine->context_unpin()
d13d6277b1d2 drm/i915: Retire requests along rings
8941cb5a2ee6 drm/i915: Only track live rings for retiring
d7448ce207cd drm/i915: Move timeline from GTT to ring
c2a1803dcc45 drm/i915: Split i915_gem_timeline into individual timelines
-:464: WARNING:FILE_PATH_CHANGES: added, moved or deleted file(s), does MAINTAINERS need updating?
#464: 
deleted file mode 100644

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

total: 0 errors, 2 warnings, 0 checks, 1638 lines checked
04c6fc7bf967 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] 24+ messages in thread

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

== Series Details ==

Series: series starting with [1/7] drm/i915: Stop tracking timeline->inflight_seqnos
URL   : https://patchwork.freedesktop.org/series/42360/
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/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: Wrap engine->context_pin() and engine->context_unpin()
Okay!

Commit: drm/i915: Retire requests along rings
-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:3661:16: warning: expression using sizeof(void)

Commit: drm/i915: Only track live rings for retiring
-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:3661:16: warning: expression using sizeof(void)
+drivers/gpu/drm/i915/selftests/../i915_drv.h:2214:33: warning: constant 0xffffea0000000000 is so big it is unsigned long
+drivers/gpu/drm/i915/selftests/../i915_drv.h:3662:16: warning: expression using sizeof(void)

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

Commit: drm/i915: Split i915_gem_timeline into individual timelines
-drivers/gpu/drm/i915/selftests/../i915_drv.h:2215:33: warning: constant 0xffffea0000000000 is so big it is unsigned long
-drivers/gpu/drm/i915/selftests/../i915_drv.h:3653: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: Lazily unbind vma on close
-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:2214:33: warning: constant 0xffffea0000000000 is so big it is unsigned long
+drivers/gpu/drm/i915/selftests/../i915_drv.h:3652: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] 24+ messages in thread

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

== Series Details ==

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

== Summary ==

= CI Bug Log - changes from CI_DRM_4107 -> Patchwork_8822 =

== Summary - FAILURE ==

  Serious unknown changes coming with Patchwork_8822 absolutely need to be
  verified manually.
  
  If you think the reported changes have nothing to do with the changes
  introduced in Patchwork_8822, 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/42360/revisions/1/mbox/

== Possible new issues ==

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

  === IGT changes ===

    ==== Possible regressions ====

    igt@drv_module_reload@basic-reload:
      fi-bsw-n3050:       PASS -> DMESG-FAIL

    
== Known issues ==

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

  === IGT changes ===

    ==== Issues hit ====

    igt@kms_flip@basic-flip-vs-wf_vblank:
      fi-glk-j4005:       PASS -> FAIL (fdo#100368)

    
    ==== Possible fixes ====

    igt@gem_exec_suspend@basic-s3:
      fi-ivb-3520m:       DMESG-WARN (fdo#106084) -> PASS

    igt@kms_busy@basic-flip-c:
      fi-bxt-dsi:         INCOMPLETE (fdo#103927) -> PASS

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

    igt@kms_pipe_crc_basic@nonblocking-crc-pipe-a-frame-sequence:
      fi-cnl-psr:         FAIL (fdo#103481) -> PASS

    
  fdo#100368 https://bugs.freedesktop.org/show_bug.cgi?id=100368
  fdo#103481 https://bugs.freedesktop.org/show_bug.cgi?id=103481
  fdo#103927 https://bugs.freedesktop.org/show_bug.cgi?id=103927
  fdo#106084 https://bugs.freedesktop.org/show_bug.cgi?id=106084


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

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


== Build changes ==

    * Linux: CI_DRM_4107 -> Patchwork_8822

  CI_DRM_4107: f711c0b36f2382983c964bd69d6c477482e604f1 @ git://anongit.freedesktop.org/gfx-ci/linux
  IGT_4450: 0350f0e7f6a0e07281445fc3082aa70419f4aac7 @ git://anongit.freedesktop.org/xorg/app/intel-gpu-tools
  Patchwork_8822: 04c6fc7bf967158517c3c25335363844f5721a4e @ git://anongit.freedesktop.org/gfx-ci/linux
  piglit_4450: b57600ba58ae0cdbad86826fd653aa0191212f27 @ git://anongit.freedesktop.org/piglit


== Linux commits ==

04c6fc7bf967 drm/i915: Lazily unbind vma on close
c2a1803dcc45 drm/i915: Split i915_gem_timeline into individual timelines
d7448ce207cd drm/i915: Move timeline from GTT to ring
8941cb5a2ee6 drm/i915: Only track live rings for retiring
d13d6277b1d2 drm/i915: Retire requests along rings
8ab432091db4 drm/i915: Wrap engine->context_pin() and engine->context_unpin()
346302027794 drm/i915: Stop tracking timeline->inflight_seqnos

== Logs ==

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

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

* Re: [PATCH 1/7] drm/i915: Stop tracking timeline->inflight_seqnos
  2018-04-26 17:49 [PATCH 1/7] drm/i915: Stop tracking timeline->inflight_seqnos Chris Wilson
                   ` (11 preceding siblings ...)
  2018-04-27 10:49 ` ✗ Fi.CI.BAT: failure " Patchwork
@ 2018-04-27 12:20 ` Tvrtko Ursulin
  12 siblings, 0 replies; 24+ messages in thread
From: Tvrtko Ursulin @ 2018-04-27 12:20 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx


On 26/04/2018 18:49, Chris Wilson wrote:
> 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!)
> 
> v2: Keep a global counter of all requests ever submitted and force the
> reset when it wraps.
> 
> 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>
> ---
>   drivers/gpu/drm/i915/i915_debugfs.c      |  5 ++--
>   drivers/gpu/drm/i915/i915_drv.h          |  1 +
>   drivers/gpu/drm/i915/i915_gem_timeline.h |  6 -----
>   drivers/gpu/drm/i915/i915_request.c      | 33 ++++++++++++------------
>   drivers/gpu/drm/i915/intel_engine_cs.c   |  5 ++--
>   5 files changed, 22 insertions(+), 28 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> index 1c88805d3354..83c86257fe1c 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_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 8444ca8d5aa3..8fd9fb6efba5 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -2061,6 +2061,7 @@ struct drm_i915_private {
>   		struct list_head timelines;
>   		struct i915_gem_timeline global_timeline;
>   		u32 active_requests;
> +		u32 request_serial;
>   
>   		/**
>   		 * Is the GPU currently considered idle, or busy executing
> 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..b1993d4a1a53 100644
> --- a/drivers/gpu/drm/i915/i915_request.c
> +++ b/drivers/gpu/drm/i915/i915_request.c
> @@ -241,6 +241,7 @@ static int reset_all_global_seqno(struct drm_i915_private *i915, u32 seqno)
>   			       sizeof(timeline->engine[id].global_sync));
>   	}
>   
> +	i915->gt.request_serial = seqno;
>   	return 0;
>   }
>   
> @@ -257,18 +258,22 @@ int i915_gem_set_global_seqno(struct drm_device *dev, u32 seqno)
>   	return reset_all_global_seqno(i915, seqno - 1);
>   }
>   
> -static int reserve_engine(struct intel_engine_cs *engine)
> +static int reserve_gt(struct drm_i915_private *i915)
>   {
> -	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))) {
> +	/*
> +	 * Reservation is fine until we may need to wrap around
> +	 *
> +	 * By incrementing the serial for every request, we know that no
> +	 * individual engine may exceed that serial (as each is reset to 0
> +	 * on any wrap). This protects even the most pessimistic of migrations
> +	 * of every request from all engines onto just one.
> +	 */
> +	while (unlikely(++i915->gt.request_serial == 0)) {
>   		ret = reset_all_global_seqno(i915, 0);
>   		if (ret) {
> -			engine->timeline->inflight_seqnos--;
> +			i915->gt.request_serial--;
>   			return ret;
>   		}
>   	}
> @@ -279,15 +284,10 @@ static int reserve_engine(struct intel_engine_cs *engine)
>   	return 0;
>   }
>   
> -static void unreserve_engine(struct intel_engine_cs *engine)
> +static void unreserve_gt(struct drm_i915_private *i915)
>   {
> -	struct drm_i915_private *i915 = engine->i915;
> -
>   	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,
> @@ -362,7 +362,6 @@ static void i915_request_retire(struct i915_request *request)
>   	list_del_init(&request->link);
>   	spin_unlock_irq(&engine->timeline->lock);
>   
> -	unreserve_engine(request->engine);
>   	advance_ring(request);
>   
>   	free_capture_list(request);
> @@ -424,6 +423,8 @@ static void i915_request_retire(struct i915_request *request)
>   	}
>   	spin_unlock_irq(&request->lock);
>   
> +	unreserve_gt(request->i915);
> +
>   	i915_sched_node_fini(request->i915, &request->sched);
>   	i915_request_put(request);
>   }
> @@ -642,7 +643,7 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx)
>   		return ERR_CAST(ring);
>   	GEM_BUG_ON(!ring);
>   
> -	ret = reserve_engine(engine);
> +	ret = reserve_gt(i915);
>   	if (ret)
>   		goto err_unpin;
>   
> @@ -784,7 +785,7 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx)
>   
>   	kmem_cache_free(i915->requests, rq);
>   err_unreserve:
> -	unreserve_engine(engine);
> +	unreserve_gt(i915);
>   err_unpin:
>   	engine->context_unpin(engine, ctx);
>   	return ERR_PTR(ret);
> diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c
> index ac009f10c948..eba81d55dc3a 100644
> --- a/drivers/gpu/drm/i915/intel_engine_cs.c
> +++ b/drivers/gpu/drm/i915/intel_engine_cs.c
> @@ -1321,12 +1321,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));
> 

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] 24+ messages in thread

* Re: [PATCH 2/7] drm/i915: Wrap engine->context_pin() and engine->context_unpin()
  2018-04-26 17:49 ` [PATCH 2/7] drm/i915: Wrap engine->context_pin() and engine->context_unpin() Chris Wilson
@ 2018-04-27 12:35   ` Tvrtko Ursulin
  0 siblings, 0 replies; 24+ messages in thread
From: Tvrtko Ursulin @ 2018-04-27 12:35 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx


On 26/04/2018 18:49, Chris Wilson wrote:
> Make life easier in upcoming patches by moving the context_pin and
> context_unpin vfuncs into inline helpers.
> 
> Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
> ---
>   drivers/gpu/drm/i915/gvt/mmio_context.c      |  2 +-
>   drivers/gpu/drm/i915/gvt/scheduler.c         | 20 ++++++-------
>   drivers/gpu/drm/i915/i915_debugfs.c          | 20 +++++++------
>   drivers/gpu/drm/i915/i915_gem.c              |  4 +--
>   drivers/gpu/drm/i915/i915_gem_context.c      |  8 +++---
>   drivers/gpu/drm/i915/i915_gem_context.h      | 30 +++++++++++++++++++-
>   drivers/gpu/drm/i915/i915_gpu_error.c        |  3 +-
>   drivers/gpu/drm/i915/i915_perf.c             |  9 +++---
>   drivers/gpu/drm/i915/i915_request.c          |  6 ++--
>   drivers/gpu/drm/i915/intel_engine_cs.c       | 13 ++++-----
>   drivers/gpu/drm/i915/intel_guc_ads.c         |  3 +-
>   drivers/gpu/drm/i915/intel_guc_submission.c  |  5 ++--
>   drivers/gpu/drm/i915/intel_lrc.c             | 29 +++++++++++--------
>   drivers/gpu/drm/i915/intel_lrc.h             |  2 +-
>   drivers/gpu/drm/i915/intel_ringbuffer.c      | 19 +++++++------
>   drivers/gpu/drm/i915/selftests/mock_engine.c |  2 +-
>   16 files changed, 108 insertions(+), 67 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/gvt/mmio_context.c b/drivers/gpu/drm/i915/gvt/mmio_context.c
> index a5bac83d53a9..0f949554d118 100644
> --- a/drivers/gpu/drm/i915/gvt/mmio_context.c
> +++ b/drivers/gpu/drm/i915/gvt/mmio_context.c
> @@ -448,7 +448,7 @@ static void switch_mocs(struct intel_vgpu *pre, struct intel_vgpu *next,
>   
>   bool is_inhibit_context(struct i915_gem_context *ctx, int ring_id)
>   {
> -	u32 *reg_state = ctx->engine[ring_id].lrc_reg_state;
> +	u32 *reg_state = ctx->__engine[ring_id].lrc_reg_state;
>   	u32 inhibit_mask =
>   		_MASKED_BIT_ENABLE(CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT);
>   
> diff --git a/drivers/gpu/drm/i915/gvt/scheduler.c b/drivers/gpu/drm/i915/gvt/scheduler.c
> index 35f7cfd7a6b4..ffb45a9ee228 100644
> --- a/drivers/gpu/drm/i915/gvt/scheduler.c
> +++ b/drivers/gpu/drm/i915/gvt/scheduler.c
> @@ -58,7 +58,7 @@ static void update_shadow_pdps(struct intel_vgpu_workload *workload)
>   	int ring_id = workload->ring_id;
>   	struct i915_gem_context *shadow_ctx = vgpu->submission.shadow_ctx;
>   	struct drm_i915_gem_object *ctx_obj =
> -		shadow_ctx->engine[ring_id].state->obj;
> +		shadow_ctx->__engine[ring_id].state->obj;
>   	struct execlist_ring_context *shadow_ring_context;
>   	struct page *page;
>   
> @@ -130,7 +130,7 @@ static int populate_shadow_context(struct intel_vgpu_workload *workload)
>   	int ring_id = workload->ring_id;
>   	struct i915_gem_context *shadow_ctx = vgpu->submission.shadow_ctx;
>   	struct drm_i915_gem_object *ctx_obj =
> -		shadow_ctx->engine[ring_id].state->obj;
> +		shadow_ctx->__engine[ring_id].state->obj;
>   	struct execlist_ring_context *shadow_ring_context;
>   	struct page *page;
>   	void *dst;
> @@ -283,7 +283,7 @@ static int shadow_context_status_change(struct notifier_block *nb,
>   static void shadow_context_descriptor_update(struct i915_gem_context *ctx,
>   		struct intel_engine_cs *engine)
>   {
> -	struct intel_context *ce = &ctx->engine[engine->id];
> +	struct intel_context *ce = to_intel_context(ctx, engine);
>   	u64 desc = 0;
>   
>   	desc = ce->lrc_desc;
> @@ -389,7 +389,7 @@ int intel_gvt_scan_and_shadow_workload(struct intel_vgpu_workload *workload)
>   	 * shadow_ctx pages invalid. So gvt need to pin itself. After update
>   	 * the guest context, gvt can unpin the shadow_ctx safely.
>   	 */
> -	ring = engine->context_pin(engine, shadow_ctx);
> +	ring = intel_context_pin(shadow_ctx, engine);
>   	if (IS_ERR(ring)) {
>   		ret = PTR_ERR(ring);
>   		gvt_vgpu_err("fail to pin shadow context\n");
> @@ -403,7 +403,7 @@ int intel_gvt_scan_and_shadow_workload(struct intel_vgpu_workload *workload)
>   	return 0;
>   
>   err_unpin:
> -	engine->context_unpin(engine, shadow_ctx);
> +	intel_context_unpin(shadow_ctx, engine);
>   err_shadow:
>   	release_shadow_wa_ctx(&workload->wa_ctx);
>   err_scan:
> @@ -437,7 +437,7 @@ static int intel_gvt_generate_request(struct intel_vgpu_workload *workload)
>   	return 0;
>   
>   err_unpin:
> -	engine->context_unpin(engine, shadow_ctx);
> +	intel_context_unpin(shadow_ctx, engine);
>   	release_shadow_wa_ctx(&workload->wa_ctx);
>   	return ret;
>   }
> @@ -526,7 +526,7 @@ static int update_wa_ctx_2_shadow_ctx(struct intel_shadow_wa_ctx *wa_ctx)
>   	struct intel_vgpu_submission *s = &workload->vgpu->submission;
>   	struct i915_gem_context *shadow_ctx = s->shadow_ctx;
>   	struct drm_i915_gem_object *ctx_obj =
> -		shadow_ctx->engine[ring_id].state->obj;
> +		shadow_ctx->__engine[ring_id].state->obj;
>   	struct execlist_ring_context *shadow_ring_context;
>   	struct page *page;
>   
> @@ -688,7 +688,7 @@ static int dispatch_workload(struct intel_vgpu_workload *workload)
>   
>   	ret = prepare_workload(workload);
>   	if (ret) {
> -		engine->context_unpin(engine, shadow_ctx);
> +		intel_context_unpin(shadow_ctx, engine);
>   		goto out;
>   	}
>   
> @@ -771,7 +771,7 @@ static void update_guest_context(struct intel_vgpu_workload *workload)
>   	struct i915_gem_context *shadow_ctx = s->shadow_ctx;
>   	int ring_id = workload->ring_id;
>   	struct drm_i915_gem_object *ctx_obj =
> -		shadow_ctx->engine[ring_id].state->obj;
> +		shadow_ctx->__engine[ring_id].state->obj;
>   	struct execlist_ring_context *shadow_ring_context;
>   	struct page *page;
>   	void *src;
> @@ -898,7 +898,7 @@ static void complete_current_workload(struct intel_gvt *gvt, int ring_id)
>   		}
>   		mutex_lock(&dev_priv->drm.struct_mutex);
>   		/* unpin shadow ctx as the shadow_ctx update is done */
> -		engine->context_unpin(engine, s->shadow_ctx);
> +		intel_context_unpin(s->shadow_ctx, engine);
>   		mutex_unlock(&dev_priv->drm.struct_mutex);
>   	}
>   
> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> index 83c86257fe1c..601041c6f9ae 100644
> --- a/drivers/gpu/drm/i915/i915_debugfs.c
> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> @@ -377,16 +377,19 @@ static void print_batch_pool_stats(struct seq_file *m,
>   	print_file_stats(m, "[k]batch pool", stats);
>   }
>   
> -static int per_file_ctx_stats(int id, void *ptr, void *data)
> +static int per_file_ctx_stats(int idx, void *ptr, void *data)
>   {
>   	struct i915_gem_context *ctx = ptr;
> -	int n;
> +	struct intel_engine_cs *engine;
> +	enum intel_engine_id id;
> +
> +	for_each_engine(engine, ctx->i915, id) {
> +		struct intel_context *ce = to_intel_context(ctx, engine);
>   
> -	for (n = 0; n < ARRAY_SIZE(ctx->engine); n++) {
> -		if (ctx->engine[n].state)
> -			per_file_stats(0, ctx->engine[n].state->obj, data);
> -		if (ctx->engine[n].ring)
> -			per_file_stats(0, ctx->engine[n].ring->vma->obj, data);
> +		if (ce->state)
> +			per_file_stats(0, ce->state->obj, data);
> +		if (ce->ring)
> +			per_file_stats(0, ce->ring->vma->obj, data);
>   	}
>   
>   	return 0;
> @@ -1959,7 +1962,8 @@ static int i915_context_status(struct seq_file *m, void *unused)
>   		seq_putc(m, '\n');
>   
>   		for_each_engine(engine, dev_priv, id) {
> -			struct intel_context *ce = &ctx->engine[engine->id];
> +			struct intel_context *ce =
> +				to_intel_context(ctx, engine);
>   
>   			seq_printf(m, "%s: ", engine->name);
>   			if (ce->state)
> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> index 6b0c67a4f214..4090bfdda340 100644
> --- a/drivers/gpu/drm/i915/i915_gem.c
> +++ b/drivers/gpu/drm/i915/i915_gem.c
> @@ -3234,7 +3234,7 @@ void i915_gem_reset(struct drm_i915_private *dev_priv,
>   				      stalled_mask & ENGINE_MASK(id));
>   		ctx = fetch_and_zero(&engine->last_retired_context);
>   		if (ctx)
> -			engine->context_unpin(engine, ctx);
> +			intel_context_unpin(ctx, engine);
>   
>   		/*
>   		 * Ostensibily, we always want a context loaded for powersaving,
> @@ -5291,7 +5291,7 @@ static int __intel_engines_record_defaults(struct drm_i915_private *i915)
>   	for_each_engine(engine, i915, id) {
>   		struct i915_vma *state;
>   
> -		state = ctx->engine[id].state;
> +		state = to_intel_context(ctx, engine)->state;
>   		if (!state)
>   			continue;
>   
> diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
> index 74435affe23f..59d4bd4a7b73 100644
> --- a/drivers/gpu/drm/i915/i915_gem_context.c
> +++ b/drivers/gpu/drm/i915/i915_gem_context.c
> @@ -117,15 +117,15 @@ static void lut_close(struct i915_gem_context *ctx)
>   
>   static void i915_gem_context_free(struct i915_gem_context *ctx)
>   {
> -	int i;
> +	unsigned int n;
>   
>   	lockdep_assert_held(&ctx->i915->drm.struct_mutex);
>   	GEM_BUG_ON(!i915_gem_context_is_closed(ctx));
>   
>   	i915_ppgtt_put(ctx->ppgtt);
>   
> -	for (i = 0; i < I915_NUM_ENGINES; i++) {
> -		struct intel_context *ce = &ctx->engine[i];
> +	for (n = 0; n < ARRAY_SIZE(ctx->__engine); n++) {
> +		struct intel_context *ce = &ctx->__engine[n];
>   
>   		if (!ce->state)
>   			continue;
> @@ -521,7 +521,7 @@ void i915_gem_contexts_lost(struct drm_i915_private *dev_priv)
>   		if (!engine->last_retired_context)
>   			continue;
>   
> -		engine->context_unpin(engine, engine->last_retired_context);
> +		intel_context_unpin(engine->last_retired_context, engine);
>   		engine->last_retired_context = NULL;
>   	}
>   }
> diff --git a/drivers/gpu/drm/i915/i915_gem_context.h b/drivers/gpu/drm/i915/i915_gem_context.h
> index b12a8a8c5af9..ace3b129c189 100644
> --- a/drivers/gpu/drm/i915/i915_gem_context.h
> +++ b/drivers/gpu/drm/i915/i915_gem_context.h
> @@ -149,7 +149,7 @@ struct i915_gem_context {
>   		u32 *lrc_reg_state;
>   		u64 lrc_desc;
>   		int pin_count;
> -	} engine[I915_NUM_ENGINES];
> +	} __engine[I915_NUM_ENGINES];
>   
>   	/** ring_size: size for allocating the per-engine ring buffer */
>   	u32 ring_size;
> @@ -256,6 +256,34 @@ static inline bool i915_gem_context_is_kernel(struct i915_gem_context *ctx)
>   	return !ctx->file_priv;
>   }
>   
> +static inline struct intel_context *
> +to_intel_context(struct i915_gem_context *ctx,
> +		 const struct intel_engine_cs *engine)
> +{
> +	return &ctx->__engine[engine->id];
> +}
> +
> +static inline struct intel_ring *
> +intel_context_pin(struct i915_gem_context *ctx, struct intel_engine_cs *engine)
> +{
> +	return engine->context_pin(engine, ctx);
> +}
> +
> +static inline void __intel_context_pin(struct i915_gem_context *ctx,
> +				       const struct intel_engine_cs *engine)
> +{
> +	struct intel_context *ce = to_intel_context(ctx, engine);
> +
> +	GEM_BUG_ON(!ce->pin_count);
> +	ce->pin_count++;
> +}

Unused in this patch, but it also breaks layering to avoid a function 
call. Slight grumble but OK, not the worst thing in our codebase. I 
don't have any ideas on how to have it all.

> +
> +static inline void intel_context_unpin(struct i915_gem_context *ctx,
> +				       struct intel_engine_cs *engine)
> +{
> +	engine->context_unpin(engine, ctx);
> +}
> +
>   /* i915_gem_context.c */
>   int __must_check i915_gem_contexts_init(struct drm_i915_private *dev_priv);
>   void i915_gem_contexts_lost(struct drm_i915_private *dev_priv);
> diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c
> index 671ffa37614e..c0127965b578 100644
> --- a/drivers/gpu/drm/i915/i915_gpu_error.c
> +++ b/drivers/gpu/drm/i915/i915_gpu_error.c
> @@ -1472,7 +1472,8 @@ static void gem_record_rings(struct i915_gpu_state *error)
>   
>   			ee->ctx =
>   				i915_error_object_create(i915,
> -							 request->ctx->engine[i].state);
> +							 to_intel_context(request->ctx,
> +									  engine)->state);
>   
>   			error->simulated |=
>   				i915_gem_context_no_error_capture(request->ctx);
> diff --git a/drivers/gpu/drm/i915/i915_perf.c b/drivers/gpu/drm/i915/i915_perf.c
> index bfc906cd4e5e..4b1da01168ae 100644
> --- a/drivers/gpu/drm/i915/i915_perf.c
> +++ b/drivers/gpu/drm/i915/i915_perf.c
> @@ -1234,7 +1234,7 @@ static int oa_get_render_ctx_id(struct i915_perf_stream *stream)
>   		 *
>   		 * NB: implied RCS engine...
>   		 */
> -		ring = engine->context_pin(engine, stream->ctx);
> +		ring = intel_context_pin(stream->ctx, engine);
>   		mutex_unlock(&dev_priv->drm.struct_mutex);
>   		if (IS_ERR(ring))
>   			return PTR_ERR(ring);
> @@ -1246,7 +1246,7 @@ static int oa_get_render_ctx_id(struct i915_perf_stream *stream)
>   		 * with gen8+ and execlists
>   		 */
>   		dev_priv->perf.oa.specific_ctx_id =
> -			i915_ggtt_offset(stream->ctx->engine[engine->id].state);
> +			i915_ggtt_offset(to_intel_context(stream->ctx, engine)->state);
>   	}
>   
>   	return 0;
> @@ -1271,7 +1271,7 @@ static void oa_put_render_ctx_id(struct i915_perf_stream *stream)
>   		mutex_lock(&dev_priv->drm.struct_mutex);
>   
>   		dev_priv->perf.oa.specific_ctx_id = INVALID_CTX_ID;
> -		engine->context_unpin(engine, stream->ctx);
> +		intel_context_unpin(stream->ctx, engine);
>   
>   		mutex_unlock(&dev_priv->drm.struct_mutex);
>   	}
> @@ -1759,6 +1759,7 @@ static int gen8_switch_to_updated_kernel_context(struct drm_i915_private *dev_pr
>   static int gen8_configure_all_contexts(struct drm_i915_private *dev_priv,
>   				       const struct i915_oa_config *oa_config)
>   {
> +	struct intel_engine_cs *engine = dev_priv->engine[RCS];
>   	struct i915_gem_context *ctx;
>   	int ret;
>   	unsigned int wait_flags = I915_WAIT_LOCKED;
> @@ -1789,7 +1790,7 @@ static int gen8_configure_all_contexts(struct drm_i915_private *dev_priv,
>   
>   	/* Update all contexts now that we've stalled the submission. */
>   	list_for_each_entry(ctx, &dev_priv->contexts.list, link) {
> -		struct intel_context *ce = &ctx->engine[RCS];
> +		struct intel_context *ce = to_intel_context(ctx, engine);
>   		u32 *regs;
>   
>   		/* OA settings will be set upon first use */
> diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c
> index b1993d4a1a53..9358f2cf0c32 100644
> --- a/drivers/gpu/drm/i915/i915_request.c
> +++ b/drivers/gpu/drm/i915/i915_request.c
> @@ -409,7 +409,7 @@ static void i915_request_retire(struct i915_request *request)
>   	 * the subsequent request.
>   	 */
>   	if (engine->last_retired_context)
> -		engine->context_unpin(engine, engine->last_retired_context);
> +		intel_context_unpin(engine->last_retired_context, engine);
>   	engine->last_retired_context = request->ctx;
>   
>   	spin_lock_irq(&request->lock);
> @@ -638,7 +638,7 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx)
>   	 * GGTT space, so do this first before we reserve a seqno for
>   	 * ourselves.
>   	 */
> -	ring = engine->context_pin(engine, ctx);
> +	ring = intel_context_pin(ctx, engine);
>   	if (IS_ERR(ring))
>   		return ERR_CAST(ring);
>   	GEM_BUG_ON(!ring);
> @@ -787,7 +787,7 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx)
>   err_unreserve:
>   	unreserve_gt(i915);
>   err_unpin:
> -	engine->context_unpin(engine, ctx);
> +	intel_context_unpin(ctx, engine);
>   	return ERR_PTR(ret);
>   }
>   
> diff --git a/drivers/gpu/drm/i915/intel_engine_cs.c b/drivers/gpu/drm/i915/intel_engine_cs.c
> index eba81d55dc3a..238c8d3da041 100644
> --- a/drivers/gpu/drm/i915/intel_engine_cs.c
> +++ b/drivers/gpu/drm/i915/intel_engine_cs.c
> @@ -685,7 +685,7 @@ int intel_engine_init_common(struct intel_engine_cs *engine)
>   	 * be available. To avoid this we always pin the default
>   	 * context.
>   	 */
> -	ring = engine->context_pin(engine, engine->i915->kernel_context);
> +	ring = intel_context_pin(engine->i915->kernel_context, engine);
>   	if (IS_ERR(ring))
>   		return PTR_ERR(ring);
>   
> @@ -694,8 +694,7 @@ int intel_engine_init_common(struct intel_engine_cs *engine)
>   	 * we can interrupt the engine at any time.
>   	 */
>   	if (engine->i915->preempt_context) {
> -		ring = engine->context_pin(engine,
> -					   engine->i915->preempt_context);
> +		ring = intel_context_pin(engine->i915->preempt_context, engine);
>   		if (IS_ERR(ring)) {
>   			ret = PTR_ERR(ring);
>   			goto err_unpin_kernel;
> @@ -719,9 +718,9 @@ int intel_engine_init_common(struct intel_engine_cs *engine)
>   	intel_engine_fini_breadcrumbs(engine);
>   err_unpin_preempt:
>   	if (engine->i915->preempt_context)
> -		engine->context_unpin(engine, engine->i915->preempt_context);
> +		intel_context_unpin(engine->i915->preempt_context, engine);
>   err_unpin_kernel:
> -	engine->context_unpin(engine, engine->i915->kernel_context);
> +	intel_context_unpin(engine->i915->kernel_context, engine);
>   	return ret;
>   }
>   
> @@ -749,8 +748,8 @@ void intel_engine_cleanup_common(struct intel_engine_cs *engine)
>   		i915_gem_object_put(engine->default_state);
>   
>   	if (engine->i915->preempt_context)
> -		engine->context_unpin(engine, engine->i915->preempt_context);
> -	engine->context_unpin(engine, engine->i915->kernel_context);
> +		intel_context_unpin(engine->i915->preempt_context, engine);
> +	intel_context_unpin(engine->i915->kernel_context, engine);
>   }
>   
>   u64 intel_engine_get_active_head(const struct intel_engine_cs *engine)
> diff --git a/drivers/gpu/drm/i915/intel_guc_ads.c b/drivers/gpu/drm/i915/intel_guc_ads.c
> index 334cb5202e1c..dcaa3fb71765 100644
> --- a/drivers/gpu/drm/i915/intel_guc_ads.c
> +++ b/drivers/gpu/drm/i915/intel_guc_ads.c
> @@ -121,7 +121,8 @@ int intel_guc_ads_create(struct intel_guc *guc)
>   	 * to find it. Note that we have to skip our header (1 page),
>   	 * because our GuC shared data is there.
>   	 */
> -	kernel_ctx_vma = dev_priv->kernel_context->engine[RCS].state;
> +	kernel_ctx_vma = to_intel_context(dev_priv->kernel_context,
> +					  dev_priv->engine[RCS])->state;
>   	blob->ads.golden_context_lrca =
>   		intel_guc_ggtt_offset(guc, kernel_ctx_vma) + skipped_offset;
>   
> diff --git a/drivers/gpu/drm/i915/intel_guc_submission.c b/drivers/gpu/drm/i915/intel_guc_submission.c
> index 02da05875aa7..6e6ed0f46bd3 100644
> --- a/drivers/gpu/drm/i915/intel_guc_submission.c
> +++ b/drivers/gpu/drm/i915/intel_guc_submission.c
> @@ -362,7 +362,7 @@ static void guc_stage_desc_init(struct intel_guc *guc,
>   	desc->db_id = client->doorbell_id;
>   
>   	for_each_engine_masked(engine, dev_priv, client->engines, tmp) {
> -		struct intel_context *ce = &ctx->engine[engine->id];
> +		struct intel_context *ce = to_intel_context(ctx, engine);
>   		u32 guc_engine_id = engine->guc_id;
>   		struct guc_execlist_context *lrc = &desc->lrc[guc_engine_id];
>   
> @@ -990,7 +990,8 @@ static void guc_fill_preempt_context(struct intel_guc *guc)
>   	enum intel_engine_id id;
>   
>   	for_each_engine(engine, dev_priv, id) {
> -		struct intel_context *ce = &client->owner->engine[id];
> +		struct intel_context *ce =
> +			to_intel_context(client->owner, engine);
>   		u32 addr = intel_hws_preempt_done_address(engine);
>   		u32 *cs;
>   
> diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
> index ce23d5116482..79af778621a1 100644
> --- a/drivers/gpu/drm/i915/intel_lrc.c
> +++ b/drivers/gpu/drm/i915/intel_lrc.c
> @@ -223,7 +223,7 @@ static void
>   intel_lr_context_descriptor_update(struct i915_gem_context *ctx,
>   				   struct intel_engine_cs *engine)
>   {
> -	struct intel_context *ce = &ctx->engine[engine->id];
> +	struct intel_context *ce = to_intel_context(ctx, engine);
>   	u64 desc;
>   
>   	BUILD_BUG_ON(MAX_CONTEXT_HW_ID > (BIT(GEN8_CTX_ID_WIDTH)));
> @@ -414,7 +414,7 @@ execlists_update_context_pdps(struct i915_hw_ppgtt *ppgtt, u32 *reg_state)
>   
>   static u64 execlists_update_context(struct i915_request *rq)
>   {
> -	struct intel_context *ce = &rq->ctx->engine[rq->engine->id];
> +	struct intel_context *ce = to_intel_context(rq->ctx, rq->engine);
>   	struct i915_hw_ppgtt *ppgtt =
>   		rq->ctx->ppgtt ?: rq->i915->mm.aliasing_ppgtt;
>   	u32 *reg_state = ce->lrc_reg_state;
> @@ -523,7 +523,7 @@ static void inject_preempt_context(struct intel_engine_cs *engine)
>   {
>   	struct intel_engine_execlists *execlists = &engine->execlists;
>   	struct intel_context *ce =
> -		&engine->i915->preempt_context->engine[engine->id];
> +		to_intel_context(engine->i915->preempt_context, engine);
>   	unsigned int n;
>   
>   	GEM_BUG_ON(execlists->preempt_complete_status !=
> @@ -1328,7 +1328,7 @@ static struct intel_ring *
>   execlists_context_pin(struct intel_engine_cs *engine,
>   		      struct i915_gem_context *ctx)
>   {
> -	struct intel_context *ce = &ctx->engine[engine->id];
> +	struct intel_context *ce = to_intel_context(ctx, engine);
>   	void *vaddr;
>   	int ret;
>   
> @@ -1381,7 +1381,7 @@ execlists_context_pin(struct intel_engine_cs *engine,
>   static void execlists_context_unpin(struct intel_engine_cs *engine,
>   				    struct i915_gem_context *ctx)
>   {
> -	struct intel_context *ce = &ctx->engine[engine->id];
> +	struct intel_context *ce = to_intel_context(ctx, engine);
>   
>   	lockdep_assert_held(&ctx->i915->drm.struct_mutex);
>   	GEM_BUG_ON(ce->pin_count == 0);
> @@ -1400,8 +1400,8 @@ static void execlists_context_unpin(struct intel_engine_cs *engine,
>   
>   static int execlists_request_alloc(struct i915_request *request)
>   {
> -	struct intel_engine_cs *engine = request->engine;
> -	struct intel_context *ce = &request->ctx->engine[engine->id];
> +	struct intel_context *ce =
> +		to_intel_context(request->ctx, request->engine);
>   	int ret;
>   
>   	GEM_BUG_ON(!ce->pin_count);
> @@ -1855,7 +1855,7 @@ static void reset_common_ring(struct intel_engine_cs *engine,
>   	 * future request will be after userspace has had the opportunity
>   	 * to recreate its own state.
>   	 */
> -	ce = &request->ctx->engine[engine->id];
> +	ce = to_intel_context(request->ctx, engine);
>   	execlists_init_reg_state(ce->lrc_reg_state,
>   				 request->ctx, engine, ce->ring);
>   
> @@ -2296,9 +2296,13 @@ static int logical_ring_init(struct intel_engine_cs *engine)
>   	}
>   
>   	engine->execlists.preempt_complete_status = ~0u;
> -	if (engine->i915->preempt_context)
> +	if (engine->i915->preempt_context) {
> +		struct intel_context *ce =
> +			to_intel_context(engine->i915->preempt_context, engine);
> +
>   		engine->execlists.preempt_complete_status =
> -			upper_32_bits(engine->i915->preempt_context->engine[engine->id].lrc_desc);
> +			upper_32_bits(ce->lrc_desc);
> +	}
>   
>   	return 0;
>   
> @@ -2580,7 +2584,7 @@ static int execlists_context_deferred_alloc(struct i915_gem_context *ctx,
>   					    struct intel_engine_cs *engine)
>   {
>   	struct drm_i915_gem_object *ctx_obj;
> -	struct intel_context *ce = &ctx->engine[engine->id];
> +	struct intel_context *ce = to_intel_context(ctx, engine);
>   	struct i915_vma *vma;
>   	uint32_t context_size;
>   	struct intel_ring *ring;
> @@ -2651,7 +2655,8 @@ void intel_lr_context_resume(struct drm_i915_private *dev_priv)
>   	 */
>   	list_for_each_entry(ctx, &dev_priv->contexts.list, link) {
>   		for_each_engine(engine, dev_priv, id) {
> -			struct intel_context *ce = &ctx->engine[engine->id];
> +			struct intel_context *ce =
> +				to_intel_context(ctx, engine);
>   			u32 *reg;
>   
>   			if (!ce->state)
> diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h
> index 59d7b86012e9..4ec7d8dd13c8 100644
> --- a/drivers/gpu/drm/i915/intel_lrc.h
> +++ b/drivers/gpu/drm/i915/intel_lrc.h
> @@ -108,7 +108,7 @@ static inline uint64_t
>   intel_lr_context_descriptor(struct i915_gem_context *ctx,
>   			    struct intel_engine_cs *engine)
>   {
> -	return ctx->engine[engine->id].lrc_desc;
> +	return to_intel_context(ctx, engine)->lrc_desc;
>   }
>   
>   #endif /* _INTEL_LRC_H_ */
> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
> index c06c22c953b3..69ffc0dfe92b 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.c
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
> @@ -558,7 +558,8 @@ static void reset_ring_common(struct intel_engine_cs *engine,
>   	 */
>   	if (request) {
>   		struct drm_i915_private *dev_priv = request->i915;
> -		struct intel_context *ce = &request->ctx->engine[engine->id];
> +		struct intel_context *ce = to_intel_context(request->ctx,
> +							    engine);
>   		struct i915_hw_ppgtt *ppgtt;
>   
>   		if (ce->state) {
> @@ -1163,9 +1164,9 @@ intel_ring_free(struct intel_ring *ring)
>   	kfree(ring);
>   }
>   
> -static int context_pin(struct i915_gem_context *ctx)
> +static int context_pin(struct intel_context *ce)
>   {
> -	struct i915_vma *vma = ctx->engine[RCS].state;
> +	struct i915_vma *vma = ce->state;
>   	int ret;
>   
>   	/*
> @@ -1256,7 +1257,7 @@ static struct intel_ring *
>   intel_ring_context_pin(struct intel_engine_cs *engine,
>   		       struct i915_gem_context *ctx)
>   {
> -	struct intel_context *ce = &ctx->engine[engine->id];
> +	struct intel_context *ce = to_intel_context(ctx, engine);
>   	int ret;
>   
>   	lockdep_assert_held(&ctx->i915->drm.struct_mutex);
> @@ -1278,7 +1279,7 @@ intel_ring_context_pin(struct intel_engine_cs *engine,
>   	}
>   
>   	if (ce->state) {
> -		ret = context_pin(ctx);
> +		ret = context_pin(ce);
>   		if (ret)
>   			goto err;
>   
> @@ -1299,7 +1300,7 @@ intel_ring_context_pin(struct intel_engine_cs *engine,
>   static void intel_ring_context_unpin(struct intel_engine_cs *engine,
>   				     struct i915_gem_context *ctx)
>   {
> -	struct intel_context *ce = &ctx->engine[engine->id];
> +	struct intel_context *ce = to_intel_context(ctx, engine);
>   
>   	lockdep_assert_held(&ctx->i915->drm.struct_mutex);
>   	GEM_BUG_ON(ce->pin_count == 0);
> @@ -1427,7 +1428,7 @@ static inline int mi_set_context(struct i915_request *rq, u32 flags)
>   
>   	*cs++ = MI_NOOP;
>   	*cs++ = MI_SET_CONTEXT;
> -	*cs++ = i915_ggtt_offset(rq->ctx->engine[RCS].state) | flags;
> +	*cs++ = i915_ggtt_offset(to_intel_context(rq->ctx, engine)->state) | flags;
>   	/*
>   	 * w/a: MI_SET_CONTEXT must always be followed by MI_NOOP
>   	 * WaMiSetContext_Hang:snb,ivb,vlv
> @@ -1518,7 +1519,7 @@ static int switch_context(struct i915_request *rq)
>   		hw_flags = MI_FORCE_RESTORE;
>   	}
>   
> -	if (to_ctx->engine[engine->id].state &&
> +	if (to_intel_context(to_ctx, engine)->state &&
>   	    (to_ctx != from_ctx || hw_flags & MI_FORCE_RESTORE)) {
>   		GEM_BUG_ON(engine->id != RCS);
>   
> @@ -1566,7 +1567,7 @@ static int ring_request_alloc(struct i915_request *request)
>   {
>   	int ret;
>   
> -	GEM_BUG_ON(!request->ctx->engine[request->engine->id].pin_count);
> +	GEM_BUG_ON(!to_intel_context(request->ctx, request->engine)->pin_count);
>   
>   	/* Flush enough space to reduce the likelihood of waiting after
>   	 * we start building the request - in which case we will just
> diff --git a/drivers/gpu/drm/i915/selftests/mock_engine.c b/drivers/gpu/drm/i915/selftests/mock_engine.c
> index 78a89efa1119..3ed0557316d4 100644
> --- a/drivers/gpu/drm/i915/selftests/mock_engine.c
> +++ b/drivers/gpu/drm/i915/selftests/mock_engine.c
> @@ -217,7 +217,7 @@ void mock_engine_free(struct intel_engine_cs *engine)
>   	GEM_BUG_ON(timer_pending(&mock->hw_delay));
>   
>   	if (engine->last_retired_context)
> -		engine->context_unpin(engine, engine->last_retired_context);
> +		intel_context_unpin(engine->last_retired_context, engine);
>   
>   	intel_engine_fini_breadcrumbs(engine);
>   
> 

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] 24+ messages in thread

* Re: [PATCH 3/7] drm/i915: Retire requests along rings
  2018-04-26 17:49 ` [PATCH 3/7] drm/i915: Retire requests along rings Chris Wilson
@ 2018-04-27 12:50   ` Tvrtko Ursulin
  2018-04-27 13:00     ` Chris Wilson
  0 siblings, 1 reply; 24+ messages in thread
From: Tvrtko Ursulin @ 2018-04-27 12:50 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx


On 26/04/2018 18:49, 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!
> 
> v2: We need both engine-order and ring-order processing to maintain our
> knowledge of where individual rings have completed upto as well as
> knowing what was last executing on any engine. And finally by decoupling
> retiring the contexts on the engine and the timelines along the rings,
> we do have to keep a reference to the context on each request
> (previously it was guaranteed by the context being pinned).
> 
> v3: Not just a reference to the context, but we need to keep it pinned
> as we manipulate the rings; i.e. we need a pin for both the manipulation
> of the engine state during its retirements, and a separate pin for the
> manipulation of the ring state.
> 
> 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           | 150 +++++++++++-------
>   drivers/gpu/drm/i915/i915_utils.h             |   6 +
>   drivers/gpu/drm/i915/intel_ringbuffer.c       |   6 +-
>   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 +
>   8 files changed, 131 insertions(+), 65 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 8fd9fb6efba5..1837c01d44d0 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;
>   		u32 request_serial;
>   
> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> index 4090bfdda340..f0644d1fbd75 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 9358f2cf0c32..e6535255d445 100644
> --- a/drivers/gpu/drm/i915/i915_request.c
> +++ b/drivers/gpu/drm/i915/i915_request.c
> @@ -286,6 +286,7 @@ static int reserve_gt(struct drm_i915_private *i915)
>   
>   static void unreserve_gt(struct drm_i915_private *i915)
>   {
> +	GEM_BUG_ON(!i915->gt.active_requests);
>   	if (!--i915->gt.active_requests)
>   		i915_gem_park(i915);
>   }
> @@ -298,6 +299,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;
>   
>   	/*
> @@ -309,7 +311,8 @@ 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(!list_is_first(&request->ring_link, &ring->request_list));
> +	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
> @@ -322,9 +325,9 @@ static void advance_ring(struct i915_request *request)
>   	} else {
>   		tail = request->postfix;
>   	}
> -	list_del(&request->ring_link);
> +	list_del_init(&request->ring_link);
>   
> -	request->ring->head = tail;
> +	ring->head = tail;
>   }
>   
>   static void free_capture_list(struct i915_request *request)
> @@ -340,30 +343,84 @@ static void free_capture_list(struct i915_request *request)
>   	}
>   }
>   
> +static void __retire_engine_request(struct intel_engine_cs *engine,
> +				    struct i915_request *rq)
> +{
> +	GEM_TRACE("%s(%s) fence %llx:%d, global=%d, current %d\n",
> +		  __func__, engine->name,
> +		  rq->fence.context, rq->fence.seqno,
> +		  rq->global_seqno,
> +		  intel_engine_get_seqno(engine));
> +
> +	GEM_BUG_ON(!i915_request_completed(rq));
> +
> +	local_irq_disable();
> +
> +	spin_lock(&engine->timeline->lock);
> +	GEM_BUG_ON(!list_is_first(&rq->link, &engine->timeline->requests));

Assert not strictly needed because how the single caller pops the 
elements off, but maybe in the future something changes.

> +	list_del_init(&rq->link);
> +	spin_unlock(&engine->timeline->lock);
> +
> +	spin_lock(&rq->lock);
> +	if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &rq->fence.flags))
> +		dma_fence_signal_locked(&rq->fence);
> +	if (test_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, &rq->fence.flags))
> +		intel_engine_cancel_signaling(rq);
> +	if (rq->waitboost) {
> +		GEM_BUG_ON(!atomic_read(&rq->i915->gt_pm.rps.num_waiters));
> +		atomic_dec(&rq->i915->gt_pm.rps.num_waiters);
> +	}
> +	spin_unlock(&rq->lock);
> +
> +	local_irq_enable();
> +
> +	/*
> +	 * The backing object for the context is done after switching to the
> +	 * *next* context. Therefore we cannot retire the previous context until
> +	 * the next context has already started running. However, since we
> +	 * cannot take the required locks at i915_request_submit() we
> +	 * defer the unpinning of the active context to now, retirement of
> +	 * the subsequent request.
> +	 */
> +	if (engine->last_retired_context)
> +		intel_context_unpin(engine->last_retired_context, engine);
> +	engine->last_retired_context = rq->ctx;
> +}
> +
> +static void __retire_engine_upto(struct intel_engine_cs *engine,
> +				 struct i915_request *rq)
> +{
> +	struct i915_request *tmp;
> +
> +	if (list_empty(&rq->link))
> +		return;
> +
> +	do {
> +		tmp = list_first_entry(&engine->timeline->requests,
> +				       typeof(*tmp), link);
> +
> +		GEM_BUG_ON(tmp->engine != engine);

Very minor - move this assert to outside the loop as rq->engine != engine?

> +		__retire_engine_request(engine, tmp);
> +	} while (tmp != rq);
> +}
> +
>   static void i915_request_retire(struct i915_request *request)
>   {
> -	struct intel_engine_cs *engine = request->engine;
>   	struct i915_gem_active *active, *next;
>   
>   	GEM_TRACE("%s fence %llx:%d, global=%d, current %d\n",
> -		  engine->name,
> +		  request->engine->name,
>   		  request->fence.context, request->fence.seqno,
>   		  request->global_seqno,
> -		  intel_engine_get_seqno(engine));
> +		  intel_engine_get_seqno(request->engine));
>   
>   	lockdep_assert_held(&request->i915->drm.struct_mutex);
>   	GEM_BUG_ON(!i915_sw_fence_signaled(&request->submit));
>   	GEM_BUG_ON(!i915_request_completed(request));
> -	GEM_BUG_ON(!request->i915->gt.active_requests);
>   
>   	trace_i915_request_retire(request);
>   
> -	spin_lock_irq(&engine->timeline->lock);
> -	list_del_init(&request->link);
> -	spin_unlock_irq(&engine->timeline->lock);
> -
>   	advance_ring(request);
> -
>   	free_capture_list(request);
>   
>   	/*
> @@ -399,29 +456,9 @@ static void i915_request_retire(struct i915_request *request)
>   
>   	/* Retirement decays the ban score as it is a sign of ctx progress */
>   	atomic_dec_if_positive(&request->ctx->ban_score);
> +	intel_context_unpin(request->ctx, request->engine);
>   
> -	/*
> -	 * The backing object for the context is done after switching to the
> -	 * *next* context. Therefore we cannot retire the previous context until
> -	 * the next context has already started running. However, since we
> -	 * cannot take the required locks at i915_request_submit() we
> -	 * defer the unpinning of the active context to now, retirement of
> -	 * the subsequent request.
> -	 */
> -	if (engine->last_retired_context)
> -		intel_context_unpin(engine->last_retired_context, engine);
> -	engine->last_retired_context = request->ctx;
> -
> -	spin_lock_irq(&request->lock);
> -	if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &request->fence.flags))
> -		dma_fence_signal_locked(&request->fence);
> -	if (test_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, &request->fence.flags))
> -		intel_engine_cancel_signaling(request);
> -	if (request->waitboost) {
> -		GEM_BUG_ON(!atomic_read(&request->i915->gt_pm.rps.num_waiters));
> -		atomic_dec(&request->i915->gt_pm.rps.num_waiters);
> -	}
> -	spin_unlock_irq(&request->lock);
> +	__retire_engine_upto(request->engine, request);
>   
>   	unreserve_gt(request->i915);
>   
> @@ -431,18 +468,24 @@ 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;
>   
> +	GEM_TRACE("%s fence %llx:%d, global=%d, current %d\n",
> +		  rq->engine->name,
> +		  rq->fence.context, rq->fence.seqno,
> +		  rq->global_seqno,
> +		  intel_engine_get_seqno(rq->engine));

Maybe we could consolidate these with GEM_TRACE_RQ(rq, "prefix") or 
something.

> +
>   	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);
> @@ -651,9 +694,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);

This one I still think it will reduce the recycling effectiveness. But 
OK, can leave it for later if it will become noticeable.

>   	if (rq && i915_request_completed(rq))
>   		i915_request_retire(rq);
>   
> @@ -771,6 +814,9 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx)
>   	if (ret)
>   		goto err_unwind;
>   
> +	/* Keep a second pin for the dual retirement along engine and ring */
> +	__intel_context_pin(rq->ctx, engine);
> +
>   	/* Check that we didn't interrupt ourselves with a new request */
>   	GEM_BUG_ON(rq->timeline->seqno != rq->fence.seqno);
>   	return rq;
> @@ -1357,38 +1403,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/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 69ffc0dfe92b..ae8958007df5 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.c
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
> @@ -1066,7 +1066,6 @@ int intel_ring_pin(struct intel_ring *ring,
>   
>   void intel_ring_reset(struct intel_ring *ring, u32 tail)
>   {
> -	GEM_BUG_ON(!list_empty(&ring->request_list));
>   	ring->tail = tail;
>   	ring->head = tail;
>   	ring->emit = tail;
> @@ -1125,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)
> @@ -1150,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;
>   }
>   
> @@ -1161,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 24af3f1088ba..deb80d01e0bd 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.h
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
> @@ -130,6 +130,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 3ed0557316d4..42967fc09eb0 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)
>   		intel_context_unpin(engine->last_retired_context, engine);
>   
> +	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] 24+ messages in thread

* Re: [PATCH 4/7] drm/i915: Only track live rings for retiring
  2018-04-26 17:49 ` [PATCH 4/7] drm/i915: Only track live rings for retiring Chris Wilson
@ 2018-04-27 12:52   ` Tvrtko Ursulin
  0 siblings, 0 replies; 24+ messages in thread
From: Tvrtko Ursulin @ 2018-04-27 12:52 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx


On 26/04/2018 18:49, 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.
> 
> v2: s/live/active/ for consistency with gt.active_requests
> 
> 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                  |  3 ++-
>   drivers/gpu/drm/i915/i915_gem.c                  |  6 ++++--
>   drivers/gpu/drm/i915/i915_request.c              | 10 ++++++++--
>   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 |  5 +++--
>   7 files changed, 18 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 1837c01d44d0..54351cace362 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -2060,7 +2060,8 @@ struct drm_i915_private {
>   
>   		struct i915_gem_timeline global_timeline;
>   		struct list_head timelines;
> -		struct list_head rings;
> +
> +		struct list_head active_rings;
>   		u32 active_requests;
>   		u32 request_serial;
>   
> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> index f0644d1fbd75..fa1d94a4eb5f 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.active_rings));
>   
>   	if (!i915->gt.awake)
>   		return I915_EPOCH_INVALID;
> @@ -5599,9 +5600,10 @@ 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.rings);
>   	INIT_LIST_HEAD(&dev_priv->gt.timelines);
> +	INIT_LIST_HEAD(&dev_priv->gt.active_rings);
> +
> +	mutex_lock(&dev_priv->drm.struct_mutex);
>   	err = i915_gem_timeline_init__global(dev_priv);
>   	mutex_unlock(&dev_priv->drm.struct_mutex);
>   	if (err)
> diff --git a/drivers/gpu/drm/i915/i915_request.c b/drivers/gpu/drm/i915/i915_request.c
> index e6535255d445..c8fc4b323e62 100644
> --- a/drivers/gpu/drm/i915/i915_request.c
> +++ b/drivers/gpu/drm/i915/i915_request.c
> @@ -322,6 +322,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->active_link);
>   	} else {
>   		tail = request->postfix;
>   	}
> @@ -1096,6 +1097,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->active_link, &request->i915->gt.active_rings);
>   	request->emitted_jiffies = jiffies;
>   
>   	/*
> @@ -1418,14 +1421,17 @@ static void ring_retire_requests(struct intel_ring *ring)
>   
>   void i915_retire_requests(struct drm_i915_private *i915)
>   {
> -	struct intel_ring *ring, *next;
> +	struct intel_ring *ring, *tmp;
>   
>   	lockdep_assert_held(&i915->drm.struct_mutex);
>   
>   	if (!i915->gt.active_requests)
>   		return;
>   
> -	list_for_each_entry_safe(ring, next, &i915->gt.rings, link)
> +	/* An outstanding request must be on a still active ring somewhere */
> +	GEM_BUG_ON(list_empty(&i915->gt.active_rings));
> +
> +	list_for_each_entry_safe(ring, tmp, &i915->gt.active_rings, active_link)
>   		ring_retire_requests(ring);
>   }
>   
> diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
> index ae8958007df5..007449cfa22b 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 deb80d01e0bd..fd679cec9ac6 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.h
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
> @@ -130,7 +130,7 @@ struct intel_ring {
>   	void *vaddr;
>   
>   	struct list_head request_list;
> -	struct list_head link;
> +	struct list_head active_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 42967fc09eb0..629870aeb547 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..f22a2b35a283 100644
> --- a/drivers/gpu/drm/i915/selftests/mock_gem_device.c
> +++ b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
> @@ -224,9 +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.rings);
>   	INIT_LIST_HEAD(&i915->gt.timelines);
> +	INIT_LIST_HEAD(&i915->gt.active_rings);
> +
> +	mutex_lock(&i915->drm.struct_mutex);
>   	err = i915_gem_timeline_init__global(i915);
>   	if (err) {
>   		mutex_unlock(&i915->drm.struct_mutex);
> 

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] 24+ messages in thread

* Re: [PATCH 3/7] drm/i915: Retire requests along rings
  2018-04-27 12:50   ` Tvrtko Ursulin
@ 2018-04-27 13:00     ` Chris Wilson
  0 siblings, 0 replies; 24+ messages in thread
From: Chris Wilson @ 2018-04-27 13:00 UTC (permalink / raw)
  To: Tvrtko Ursulin, intel-gfx

Quoting Tvrtko Ursulin (2018-04-27 13:50:44)
> 
> On 26/04/2018 18:49, Chris Wilson wrote:
> > +static void __retire_engine_request(struct intel_engine_cs *engine,
> > +                                 struct i915_request *rq)
> > +{
> > +     GEM_TRACE("%s(%s) fence %llx:%d, global=%d, current %d\n",
> > +               __func__, engine->name,
> > +               rq->fence.context, rq->fence.seqno,
> > +               rq->global_seqno,
> > +               intel_engine_get_seqno(engine));
> > +
> > +     GEM_BUG_ON(!i915_request_completed(rq));
> > +
> > +     local_irq_disable();
> > +
> > +     spin_lock(&engine->timeline->lock);
> > +     GEM_BUG_ON(!list_is_first(&rq->link, &engine->timeline->requests));
> 
> Assert not strictly needed because how the single caller pops the 
> elements off, but maybe in the future something changes.

Indeed, useful if we do add a direct call here; and useful to reiterate
the point that the engine->last_retired_context depends on ordering.

> > +static void __retire_engine_upto(struct intel_engine_cs *engine,
> > +                              struct i915_request *rq)
> > +{
> > +     struct i915_request *tmp;
> > +
> > +     if (list_empty(&rq->link))
> > +             return;
> > +
> > +     do {
> > +             tmp = list_first_entry(&engine->timeline->requests,
> > +                                    typeof(*tmp), link);
> > +
> > +             GEM_BUG_ON(tmp->engine != engine);
> 
> Very minor - move this assert to outside the loop as rq->engine != engine?

I felt validating the engine backpointer along the list at various
points will be handy. Especially when request.engine becomes a bit more
volatile.

> >   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;
> >   
> > +     GEM_TRACE("%s fence %llx:%d, global=%d, current %d\n",
> > +               rq->engine->name,
> > +               rq->fence.context, rq->fence.seqno,
> > +               rq->global_seqno,
> > +               intel_engine_get_seqno(rq->engine));
> 
> Maybe we could consolidate these with GEM_TRACE_RQ(rq, "prefix") or 
> something.

Worth trying, if you mean to completely stop me from adding
inconsistency to every GEM_TRACE. Spoilsport.

> > @@ -651,9 +694,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);
> 
> This one I still think it will reduce the recycling effectiveness. But 
> OK, can leave it for later if it will become noticeable.

Or the inefficiency of retiring more than required. So long as we do
prune regularly, we can hold off the oom daemons.

Yes, it's not as neat as first planned.
-Chris
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 5/7] drm/i915: Move timeline from GTT to ring
  2018-04-26 17:49 ` [PATCH 5/7] drm/i915: Move timeline from GTT to ring Chris Wilson
@ 2018-04-27 13:01   ` Tvrtko Ursulin
  0 siblings, 0 replies; 24+ messages in thread
From: Tvrtko Ursulin @ 2018-04-27 13:01 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx


On 26/04/2018 18:49, 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.
> 
> v2: Reinforce that one isn't allowed to mix the engine execution
> timeline with the client timeline from userspace (on the ring).
> 
> 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           | 13 +++--
>   drivers/gpu/drm/i915/intel_engine_cs.c        |  3 +-
>   drivers/gpu/drm/i915/intel_lrc.c              |  2 +-
>   drivers/gpu/drm/i915/intel_ringbuffer.c       | 10 +++-
>   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(+), 41 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index 54351cace362..b9bd8328f501 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 active_rings;
> @@ -3234,16 +3235,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 fa1d94a4eb5f..438a2fc5bba0 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;
> @@ -5652,7 +5652,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 59d4bd4a7b73..1f4987dc6616 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 (n = 0; n < ARRAY_SIZE(ctx->__engine); n++) {
> @@ -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 ace3b129c189..ec53ba06f836 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 c8fc4b323e62..7bb613c00cc3 100644
> --- a/drivers/gpu/drm/i915/i915_request.c
> +++ b/drivers/gpu/drm/i915/i915_request.c
> @@ -758,7 +758,12 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx)
>   		}
>   	}
>   
> -	rq->timeline = i915_gem_context_lookup_timeline(ctx, engine);
> +	INIT_LIST_HEAD(&rq->active_list);
> +	rq->i915 = i915;
> +	rq->engine = engine;
> +	rq->ctx = ctx;
> +	rq->ring = ring;
> +	rq->timeline = ring->timeline;
>   	GEM_BUG_ON(rq->timeline == engine->timeline);
>   
>   	spin_lock_init(&rq->lock);
> @@ -774,12 +779,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 238c8d3da041..9d127e65113b 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 79af778621a1..ef888f3c0f44 100644
> --- a/drivers/gpu/drm/i915/intel_lrc.c
> +++ b/drivers/gpu/drm/i915/intel_lrc.c
> @@ -2613,7 +2613,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 007449cfa22b..b73e700c3048 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.c
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
> @@ -1117,13 +1117,16 @@ 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;
>   
>   	GEM_BUG_ON(!is_power_of_2(size));
>   	GEM_BUG_ON(RING_CTL_SIZE(size) & ~RING_NR_PAGES);
> +	GEM_BUG_ON(&timeline->engine[engine->id] == engine->timeline);
>   	lockdep_assert_held(&engine->i915->drm.struct_mutex);
>   
>   	ring = kzalloc(sizeof(*ring), GFP_KERNEL);
> @@ -1131,6 +1134,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 +1331,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 fd679cec9ac6..da53aa2973a7 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.h
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
> @@ -129,6 +129,7 @@ struct intel_ring {
>   	struct i915_vma *vma;
>   	void *vaddr;
>   
> +	struct intel_timeline *timeline;
>   	struct list_head request_list;
>   	struct list_head active_link;
>   
> @@ -768,7 +769,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 629870aeb547..6835edf278fe 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 f22a2b35a283..f11c83e8ff32 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;
> 

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] 24+ messages in thread

* Re: [PATCH 6/7] drm/i915: Split i915_gem_timeline into individual timelines
  2018-04-26 17:49 ` [PATCH 6/7] drm/i915: Split i915_gem_timeline into individual timelines Chris Wilson
@ 2018-04-27 14:37   ` Tvrtko Ursulin
  2018-04-27 15:00     ` Chris Wilson
  0 siblings, 1 reply; 24+ messages in thread
From: Tvrtko Ursulin @ 2018-04-27 14:37 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx


On 26/04/2018 18:49, 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.
> 
> v2: Tweak wait_for_idle to stop the compiling thinking that ret may be
> uninitialised.
> 
> 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               | 129 +++++-------
>   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           |  68 +++---
>   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       |  25 ++-
>   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  |  10 +-
>   .../gpu/drm/i915/selftests/mock_timeline.c    |  45 ++--
>   .../gpu/drm/i915/selftests/mock_timeline.h    |  28 +--
>   23 files changed, 398 insertions(+), 570 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 b9bd8328f501..dab15b6abc3c 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 active_rings;
> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> index 438a2fc5bba0..484354f25f98 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,17 +3731,9 @@ 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)
> +static int wait_for_timeline(struct i915_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;
> +	return i915_gem_active_wait(&tl->last_request, flags);
>   }
>   
>   static int wait_for_engines(struct drm_i915_private *i915)
> @@ -3762,30 +3751,37 @@ static int wait_for_engines(struct drm_i915_private *i915)
>   
>   int i915_gem_wait_for_idle(struct drm_i915_private *i915, unsigned int flags)
>   {
> -	int ret;
> -
>   	/* If the device is asleep, we have no requests outstanding */
>   	if (!READ_ONCE(i915->gt.awake))
>   		return 0;
>   
>   	if (flags & I915_WAIT_LOCKED) {
> -		struct i915_gem_timeline *tl;
> +		struct i915_timeline *tl;
> +		int err;
>   
>   		lockdep_assert_held(&i915->drm.struct_mutex);
>   
>   		list_for_each_entry(tl, &i915->gt.timelines, link) {
> -			ret = wait_for_timeline(tl, flags);
> -			if (ret)
> -				return ret;
> +			err = wait_for_timeline(tl, flags);
> +			if (err)
> +				return err;
>   		}
>   		i915_retire_requests(i915);
>   
> -		ret = wait_for_engines(i915);
> +		return wait_for_engines(i915);
>   	} else {
> -		ret = wait_for_timeline(&i915->gt.execution_timeline, flags);
> -	}
> +		struct intel_engine_cs *engine;
> +		enum intel_engine_id id;
> +		int err;
>   
> -	return ret;
> +		for_each_engine(engine, i915, id) {
> +			err = wait_for_timeline(&engine->timeline, flags);
> +			if (err)
> +				return err;
> +		}
> +
> +		return 0;
> +	}
>   }
>   
>   static void __i915_gem_object_flush_for_display(struct drm_i915_gem_object *obj)
> @@ -4954,7 +4950,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);
>   	}
>   }
> @@ -5603,12 +5599,6 @@ int i915_gem_init_early(struct drm_i915_private *dev_priv)
>   	INIT_LIST_HEAD(&dev_priv->gt.timelines);
>   	INIT_LIST_HEAD(&dev_priv->gt.active_rings);
>   
> -	mutex_lock(&dev_priv->drm.struct_mutex);
> -	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);
>   
>   	INIT_DELAYED_WORK(&dev_priv->gt.retire_work,
> @@ -5628,8 +5618,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:
> @@ -5650,12 +5638,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 1f4987dc6616..c9cdf88693bc 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 (n = 0; n < ARRAY_SIZE(ctx->__engine); n++) {
> @@ -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;

You are skipping engine timelines here? Would it be clearer if the 
caller did this in the list_for_each_entry loop?

>   
> -		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 ec53ba06f836..ace3b129c189 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 c0127965b578..5fd7cfd771a7 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 4b1da01168ae..d9341415df40 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 7bb613c00cc3..5acf869f3ca3 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,18 +228,18 @@ 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));
> +
>   	i915->gt.request_serial = seqno;
> +
>   	return 0;
>   }
>   
> @@ -357,10 +355,10 @@ static void __retire_engine_request(struct intel_engine_cs *engine,
>   
>   	local_irq_disable();
>   
> -	spin_lock(&engine->timeline->lock);
> -	GEM_BUG_ON(!list_is_first(&rq->link, &engine->timeline->requests));
> +	spin_lock(&engine->timeline.lock);
> +	GEM_BUG_ON(!list_is_first(&rq->link, &engine->timeline.requests));
>   	list_del_init(&rq->link);
> -	spin_unlock(&engine->timeline->lock);
> +	spin_unlock(&engine->timeline.lock);
>   
>   	spin_lock(&rq->lock);
>   	if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &rq->fence.flags))
> @@ -397,7 +395,7 @@ static void __retire_engine_upto(struct intel_engine_cs *engine,
>   		return;
>   
>   	do {
> -		tmp = list_first_entry(&engine->timeline->requests,
> +		tmp = list_first_entry(&engine->timeline.requests,
>   				       typeof(*tmp), link);
>   
>   		GEM_BUG_ON(tmp->engine != engine);
> @@ -492,16 +490,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);
> @@ -516,15 +514,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));
>   
> @@ -539,7 +537,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);
>   
> @@ -552,11 +550,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)
> @@ -570,17 +568,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);
> @@ -607,11 +605,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
> @@ -764,7 +762,7 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx)
>   	rq->ctx = ctx;
>   	rq->ring = ring;
>   	rq->timeline = ring->timeline;
> -	GEM_BUG_ON(rq->timeline == engine->timeline);
> +	GEM_BUG_ON(rq->timeline == &engine->timeline);
>   
>   	spin_lock_init(&rq->lock);
>   	dma_fence_init(&rq->fence,
> @@ -929,7 +927,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))
> @@ -943,7 +941,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;
> @@ -1020,7 +1018,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 9d127e65113b..268339203598 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);
> @@ -751,6 +746,8 @@ void intel_engine_cleanup_common(struct intel_engine_cs *engine)
>   	if (engine->i915->preempt_context)
>   		intel_context_unpin(engine->i915->preempt_context, engine);
>   	intel_context_unpin(engine->i915->kernel_context, engine);
> +
> +	i915_timeline_fini(&engine->timeline);
>   }
>   
>   u64 intel_engine_get_active_head(const struct intel_engine_cs *engine)
> @@ -1003,7 +1000,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
> @@ -1334,14 +1331,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);
> @@ -1373,11 +1370,11 @@ 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);
> +	spin_lock_irq(&engine->timeline.lock);
>   
>   	last = NULL;
>   	count = 0;
> -	list_for_each_entry(rq, &engine->timeline->requests, link) {
> +	list_for_each_entry(rq, &engine->timeline.requests, link) {
>   		if (count++ < MAX_REQUESTS_TO_SHOW - 1)
>   			print_request(m, rq, "\t\tE ");
>   		else
> @@ -1415,7 +1412,7 @@ void intel_engine_dump(struct intel_engine_cs *engine,
>   		print_request(m, last, "\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 6e6ed0f46bd3..8aafbf2e01d0 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 ef888f3c0f44..9a9b4e777d7f 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);
> @@ -893,10 +893,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);
> @@ -928,7 +928,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);
>   }
> @@ -1166,7 +1166,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));
> @@ -1174,7 +1174,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)
> @@ -1190,8 +1190,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;
> @@ -1274,7 +1274,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) {
> @@ -1298,7 +1298,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)
> @@ -1827,9 +1827,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);
>   
> @@ -2588,6 +2588,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)
> @@ -2603,8 +2604,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);
> @@ -2613,7 +2614,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 b73e700c3048..8f19349a6055 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.c
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
> @@ -697,17 +697,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;
> @@ -1126,7 +1126,7 @@ intel_engine_create_ring(struct intel_engine_cs *engine,
>   
>   	GEM_BUG_ON(!is_power_of_2(size));
>   	GEM_BUG_ON(RING_CTL_SIZE(size) & ~RING_NR_PAGES);
> -	GEM_BUG_ON(&timeline->engine[engine->id] == engine->timeline);
> +	GEM_BUG_ON(timeline == &engine->timeline);
>   	lockdep_assert_held(&engine->i915->drm.struct_mutex);
>   
>   	ring = kzalloc(sizeof(*ring), GFP_KERNEL);
> @@ -1134,7 +1134,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
> @@ -1165,6 +1165,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);
>   }
>   
> @@ -1323,6 +1324,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);
> @@ -1331,9 +1333,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 da53aa2973a7..010750e8ee44 100644
> --- a/drivers/gpu/drm/i915/intel_ringbuffer.h
> +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
> @@ -6,12 +6,12 @@
>   #include <linux/seqlock.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;
> @@ -129,7 +129,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 active_link;
>   
> @@ -338,7 +338,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;
>   
> @@ -770,7 +771,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,
> @@ -889,7 +890,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 6835edf278fe..cfa92d5d5bf0 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 f11c83e8ff32..a662c0450e77 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);
>   
> @@ -230,12 +228,6 @@ struct drm_i915_private *mock_gem_device(void)
>   	INIT_LIST_HEAD(&i915->gt.active_rings);
>   
>   	mutex_lock(&i915->drm.struct_mutex);
> -	err = i915_gem_timeline_init__global(i915);
> -	if (err) {
> -		mutex_unlock(&i915->drm.struct_mutex);
> -		goto err_priorities;
> -	}
> -
>   	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__ */
> 

A nice (to review) mix of renames, transformations and actual redesign. 
:) I did not spot any mistakes.

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] 24+ messages in thread

* Re: [PATCH 6/7] drm/i915: Split i915_gem_timeline into individual timelines
  2018-04-27 14:37   ` Tvrtko Ursulin
@ 2018-04-27 15:00     ` Chris Wilson
  0 siblings, 0 replies; 24+ messages in thread
From: Chris Wilson @ 2018-04-27 15:00 UTC (permalink / raw)
  To: Tvrtko Ursulin, intel-gfx

Quoting Tvrtko Ursulin (2018-04-27 15:37:58)
> 
> On 26/04/2018 18:49, Chris Wilson wrote:
> > -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;
> 
> You are skipping engine timelines here? Would it be clearer if the 
> caller did this in the list_for_each_entry loop?

Yeah, that we want to skip the engine->timeline isn't a property of
"last_timeline_request", but that of the caller.
-Chris
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* Re: [PATCH 7/7] drm/i915: Lazily unbind vma on close
  2018-04-26 17:49 ` [PATCH 7/7] drm/i915: Lazily unbind vma on close Chris Wilson
@ 2018-04-27 15:38   ` Tvrtko Ursulin
  2018-04-27 15:47     ` Chris Wilson
  0 siblings, 1 reply; 24+ messages in thread
From: Tvrtko Ursulin @ 2018-04-27 15:38 UTC (permalink / raw)
  To: Chris Wilson, intel-gfx


On 26/04/2018 18:49, 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.
> 
> v2: s/__i915_vma_final_close/i915_vma_destroy/ etc.
> 
> 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    |  3 +-
>   drivers/gpu/drm/i915/i915_gem_gtt.c           | 14 +++--
>   drivers/gpu/drm/i915/i915_vma.c               | 61 +++++++++++++------
>   drivers/gpu/drm/i915/i915_vma.h               |  6 ++
>   drivers/gpu/drm/i915/selftests/huge_pages.c   |  2 +-
>   .../gpu/drm/i915/selftests/mock_gem_device.c  |  1 +
>   8 files changed, 67 insertions(+), 25 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index dab15b6abc3c..d4da9f941d04 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -2061,6 +2061,7 @@ struct drm_i915_private {
>   		struct list_head timelines;
>   
>   		struct list_head active_rings;
> +		struct list_head closed_vma;
>   		u32 active_requests;
>   		u32 request_serial;
>   
> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> index 484354f25f98..5ece6ae4bdff 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;
>   
> @@ -4795,7 +4796,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_destroy(vma);
>   		}
>   		GEM_BUG_ON(!list_empty(&obj->vma_list));
>   		GEM_BUG_ON(!RB_EMPTY_ROOT(&obj->vma_tree));
> @@ -5598,6 +5599,7 @@ int i915_gem_init_early(struct drm_i915_private *dev_priv)
>   
>   	INIT_LIST_HEAD(&dev_priv->gt.timelines);
>   	INIT_LIST_HEAD(&dev_priv->gt.active_rings);
> +	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..f627a8c47c58 100644
> --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
> +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
> @@ -762,7 +762,8 @@ static int eb_lookup_vmas(struct i915_execbuffer *eb)
>   		}
>   
>   		/* transfer ref to ctx */
> -		vma->open_count++;
> +		if (!vma->open_count++)
> +			i915_vma_reopen(vma);

So only execbuf path gets to be able to reopen the VMA? I assume this is 
sufficient for the use case commit message describes? Other potential 
use cases are not interesting?

>   		list_add(&lut->obj_link, &obj->lut_list);
>   		list_add(&lut->ctx_link, &eb->ctx->handles_list);
>   		lut->ctx = eb->ctx;
> diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
> index e9d828324f67..272d6bb407cc 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_destroy_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;

There are no more references at this point so no need to mark it as 
closed I think.

> -
>   	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_destroy(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_destroy_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..81fa652ad78d 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;
> @@ -684,13 +681,31 @@ int __i915_vma_do_pin(struct i915_vma *vma,
>   	return ret;
>   }
>   
> -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));

I think the VMA code has gotten pretty messy. For instance a couple of 
external callers of is_vma_closed feel out of place. Like they should 
try to do what ever they want with the VMA, say pin it, or close it, and 
then that operation should either fail or handle the fact, respectively. 
But just another grumble at this point.

> +	vma->flags |= I915_VMA_CLOSED;
> +
> +	list_add_tail(&vma->closed_link, &vma->vm->i915->gt.closed_vma);
> +}

I think a comment next to this function might be good, doesn't have to 
be long, just to mention the rationale behind lazy unbind/destroy. Just 
because often after refactorings and code churn it is difficult to find 
the commit associated with some logical piece of the code.

> +
> +void i915_vma_reopen(struct i915_vma *vma)
> +{
> +	lockdep_assert_held(&vma->vm->i915->drm.struct_mutex);
> +
> +	if (vma->flags & I915_VMA_CLOSED) {
> +		vma->flags &= ~I915_VMA_CLOSED;
> +		list_del(&vma->closed_link);
> +	}
> +}

And then continuing the grumble, this helper wouldn't be needed. If 
someone had a vlaid vma reference, and tried to do something meaningful 
wiht it, the vma code would re-open it under the covers.

> +
> +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 +714,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));
> @@ -706,15 +722,30 @@ static void i915_vma_destroy(struct i915_vma *vma)
>   	kmem_cache_free(to_i915(vma->obj->base.dev)->vmas, vma);
>   }
>   
> -void i915_vma_close(struct i915_vma *vma)
> +void i915_vma_destroy(struct i915_vma *vma)
>   {
> -	GEM_BUG_ON(i915_vma_is_closed(vma));
> -	vma->flags |= I915_VMA_CLOSED;
> +	lockdep_assert_held(&vma->vm->i915->drm.struct_mutex);
>   
> -	rb_erase(&vma->obj_node, &vma->obj->vma_tree);
> +	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);
>   
> -	if (!i915_vma_is_active(vma) && !i915_vma_is_pinned(vma))
> -		WARN_ON(i915_vma_unbind(vma));
> +	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) {
> +		GEM_BUG_ON(!i915_vma_is_closed(vma));
> +		i915_vma_destroy(vma);
> +	}
> +
> +	GEM_BUG_ON(!list_empty(&i915->gt.closed_vma));
>   }
>   
>   static void __i915_vma_iounmap(struct i915_vma *vma)
> @@ -804,7 +835,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 +872,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);

Good this is gone, it was quite confusing why it was here.

> -
>   	return 0;
>   }
>   
> diff --git a/drivers/gpu/drm/i915/i915_vma.h b/drivers/gpu/drm/i915/i915_vma.h
> index 8c5022095418..fc4294cfaa91 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,8 @@ 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_reopen(struct i915_vma *vma);
> +void i915_vma_destroy(struct i915_vma *vma);
>   
>   int __i915_vma_do_pin(struct i915_vma *vma,
>   		      u64 size, u64 alignment, u64 flags);
> @@ -408,6 +412,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..d7c8ef8e6764 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_destroy(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 a662c0450e77..4b6622c6986a 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.timelines);
>   	INIT_LIST_HEAD(&i915->gt.active_rings);
> +	INIT_LIST_HEAD(&i915->gt.closed_vma);
>   
>   	mutex_lock(&i915->drm.struct_mutex);
>   	mock_init_ggtt(i915);
> 

Only two actionable things AFAIR. Then it looks OK to me. Although I 
would a) see if you can get Joonas to read through it - perhaps he spots 
something I missed, and b) ah no, won't mention any pencilling in of 
looking at overall vma handling in the future.

Regards,

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

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

* Re: [PATCH 7/7] drm/i915: Lazily unbind vma on close
  2018-04-27 15:38   ` Tvrtko Ursulin
@ 2018-04-27 15:47     ` Chris Wilson
  0 siblings, 0 replies; 24+ messages in thread
From: Chris Wilson @ 2018-04-27 15:47 UTC (permalink / raw)
  To: Tvrtko Ursulin, intel-gfx

Quoting Tvrtko Ursulin (2018-04-27 16:38:47)
> 
> On 26/04/2018 18:49, Chris Wilson wrote:
> > diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
> > index c74f5df3fb5a..f627a8c47c58 100644
> > --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
> > +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
> > @@ -762,7 +762,8 @@ static int eb_lookup_vmas(struct i915_execbuffer *eb)
> >               }
> >   
> >               /* transfer ref to ctx */
> > -             vma->open_count++;
> > +             if (!vma->open_count++)
> > +                     i915_vma_reopen(vma);
> 
> So only execbuf path gets to be able to reopen the VMA? I assume this is 
> sufficient for the use case commit message describes? Other potential 
> use cases are not interesting?

It's the only generator/consumer of user vma. Everything else is the
global gtt. Think PIN_USER vs PIN_GLOBAL.

> > diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
> > index e9d828324f67..272d6bb407cc 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_destroy_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;
> 
> There are no more references at this point so no need to mark it as 
> closed I think.

It's a trick for a quicker i915_vma_unbind that skips the PTE updates as
we know the ppgtt is being torn down.

> > -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));
> 
> I think the VMA code has gotten pretty messy. For instance a couple of 
> external callers of is_vma_closed feel out of place. Like they should 
> try to do what ever they want with the VMA, say pin it, or close it, and 
> then that operation should either fail or handle the fact, respectively. 
> But just another grumble at this point.

But closing twice would be weird. The assert is here because the code as
is would be broken if called twice.

> > +     vma->flags |= I915_VMA_CLOSED;
> > +
> > +     list_add_tail(&vma->closed_link, &vma->vm->i915->gt.closed_vma);
> > +}
> 
> I think a comment next to this function might be good, doesn't have to 
> be long, just to mention the rationale behind lazy unbind/destroy. Just 
> because often after refactorings and code churn it is difficult to find 
> the commit associated with some logical piece of the code.
> 
> > +
> > +void i915_vma_reopen(struct i915_vma *vma)
> > +{
> > +     lockdep_assert_held(&vma->vm->i915->drm.struct_mutex);
> > +
> > +     if (vma->flags & I915_VMA_CLOSED) {
> > +             vma->flags &= ~I915_VMA_CLOSED;
> > +             list_del(&vma->closed_link);
> > +     }
> > +}
> 
> And then continuing the grumble, this helper wouldn't be needed. If 
> someone had a vlaid vma reference, and tried to do something meaningful 
> wiht it, the vma code would re-open it under the covers.

Oh no, no, no, no ;)

Magically reappearing vma reeks of uabi exposure.

> > diff --git a/drivers/gpu/drm/i915/selftests/mock_gem_device.c b/drivers/gpu/drm/i915/selftests/mock_gem_device.c
> > index a662c0450e77..4b6622c6986a 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.timelines);
> >       INIT_LIST_HEAD(&i915->gt.active_rings);
> > +     INIT_LIST_HEAD(&i915->gt.closed_vma);
> >   
> >       mutex_lock(&i915->drm.struct_mutex);
> >       mock_init_ggtt(i915);
> > 
> 
> Only two actionable things AFAIR. Then it looks OK to me. Although I 
> would a) see if you can get Joonas to read through it - perhaps he spots 
> something I missed, and b) ah no, won't mention any pencilling in of 
> looking at overall vma handling in the future.

You would only have to read it and execbuffer.c again :-p
-Chris
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

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

* [PATCH 5/7] drm/i915: Move timeline from GTT to ring
  2018-04-25 10:52 [PATCH 1/7] drm/i915/execlists: Skip lite restore on the currently executing request Chris Wilson
@ 2018-04-25 10:52 ` Chris Wilson
  0 siblings, 0 replies; 24+ messages in thread
From: Chris Wilson @ 2018-04-25 10:52 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.

v2: Reinforce that one isn't allowed to mix the engine execution
timeline with the client timeline from userspace (on the ring).

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           | 13 +++--
 drivers/gpu/drm/i915/intel_engine_cs.c        |  3 +-
 drivers/gpu/drm/i915/intel_lrc.c              |  2 +-
 drivers/gpu/drm/i915/intel_ringbuffer.c       | 10 +++-
 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(+), 41 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 54351cace362..b9bd8328f501 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 active_rings;
@@ -3234,16 +3235,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 56c79df5ebce..d60f3bd4bc66 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;
@@ -5652,7 +5652,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 6301fb0d2319..7c0fa2c544bb 100644
--- a/drivers/gpu/drm/i915/i915_request.c
+++ b/drivers/gpu/drm/i915/i915_request.c
@@ -748,7 +748,12 @@ i915_request_alloc(struct intel_engine_cs *engine, struct i915_gem_context *ctx)
 		}
 	}
 
-	rq->timeline = i915_gem_context_lookup_timeline(ctx, engine);
+	INIT_LIST_HEAD(&rq->active_list);
+	rq->i915 = i915;
+	rq->engine = engine;
+	rq->ctx = i915_gem_context_get(ctx);
+	rq->ring = ring;
+	rq->timeline = ring->timeline;
 	GEM_BUG_ON(rq->timeline == engine->timeline);
 
 	spin_lock_init(&rq->lock);
@@ -764,12 +769,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 = i915_gem_context_get(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 ea63493b5ea7..d6c2882a3b5f 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 5c50263e45d3..f7e430b83942 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -2597,7 +2597,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 3d02b2c779e7..897e73ec51cf 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -1116,13 +1116,16 @@ 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;
 
 	GEM_BUG_ON(!is_power_of_2(size));
 	GEM_BUG_ON(RING_CTL_SIZE(size) & ~RING_NR_PAGES);
+	GEM_BUG_ON(&timeline->engine[engine->id] == engine->timeline);
 	lockdep_assert_held(&engine->i915->drm.struct_mutex);
 
 	ring = kzalloc(sizeof(*ring), GFP_KERNEL);
@@ -1130,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
@@ -1326,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 e8d17bcd9bee..b3c3f8f47f38 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 active_link;
 
@@ -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 f22a2b35a283..f11c83e8ff32 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] 24+ messages in thread

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

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-04-26 17:49 [PATCH 1/7] drm/i915: Stop tracking timeline->inflight_seqnos Chris Wilson
2018-04-26 17:49 ` [PATCH 2/7] drm/i915: Wrap engine->context_pin() and engine->context_unpin() Chris Wilson
2018-04-27 12:35   ` Tvrtko Ursulin
2018-04-26 17:49 ` [PATCH 3/7] drm/i915: Retire requests along rings Chris Wilson
2018-04-27 12:50   ` Tvrtko Ursulin
2018-04-27 13:00     ` Chris Wilson
2018-04-26 17:49 ` [PATCH 4/7] drm/i915: Only track live rings for retiring Chris Wilson
2018-04-27 12:52   ` Tvrtko Ursulin
2018-04-26 17:49 ` [PATCH 5/7] drm/i915: Move timeline from GTT to ring Chris Wilson
2018-04-27 13:01   ` Tvrtko Ursulin
2018-04-26 17:49 ` [PATCH 6/7] drm/i915: Split i915_gem_timeline into individual timelines Chris Wilson
2018-04-27 14:37   ` Tvrtko Ursulin
2018-04-27 15:00     ` Chris Wilson
2018-04-26 17:49 ` [PATCH 7/7] drm/i915: Lazily unbind vma on close Chris Wilson
2018-04-27 15:38   ` Tvrtko Ursulin
2018-04-27 15:47     ` Chris Wilson
2018-04-27  8:52 ` ✗ Fi.CI.CHECKPATCH: warning for series starting with [1/7] drm/i915: Stop tracking timeline->inflight_seqnos Patchwork
2018-04-27  8:55 ` ✗ Fi.CI.SPARSE: " Patchwork
2018-04-27  9:07 ` ✗ Fi.CI.BAT: failure " Patchwork
2018-04-27 10:34 ` ✗ Fi.CI.CHECKPATCH: warning " Patchwork
2018-04-27 10:37 ` ✗ Fi.CI.SPARSE: " Patchwork
2018-04-27 10:49 ` ✗ Fi.CI.BAT: failure " Patchwork
2018-04-27 12:20 ` [PATCH 1/7] " Tvrtko Ursulin
  -- strict thread matches above, loose matches on Subject: below --
2018-04-25 10:52 [PATCH 1/7] drm/i915/execlists: Skip lite restore on the currently executing request Chris Wilson
2018-04-25 10:52 ` [PATCH 5/7] drm/i915: Move timeline from GTT to ring Chris Wilson

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.