[PATCH 16/16] drm/i915/breadcrumbs: Flush fence signals on removing the breadcrumb

Chris Wilson chris at chris-wilson.co.uk
Thu Jan 4 18:26:09 UTC 2018


When the wait->seqno has passed and we have an attached fence, signal
the fence on removing the waiter.

Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/i915_gem_request.c  |  4 ++--
 drivers/gpu/drm/i915/i915_gem_request.h  |  6 ++++++
 drivers/gpu/drm/i915/i915_gem_timeline.c |  2 ++
 drivers/gpu/drm/i915/intel_breadcrumbs.c | 16 +++++++++++++++-
 4 files changed, 25 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_gem_request.c b/drivers/gpu/drm/i915/i915_gem_request.c
index 46848aef1648..d70add332997 100644
--- a/drivers/gpu/drm/i915/i915_gem_request.c
+++ b/drivers/gpu/drm/i915/i915_gem_request.c
@@ -496,7 +496,7 @@ void __i915_gem_request_submit(struct drm_i915_gem_request *request)
 	GEM_BUG_ON(i915_seqno_passed(intel_engine_get_seqno(engine), seqno));
 
 	/* We may be recursing from the signal callback of another i915 fence */
-	spin_lock_nested(&request->lock, SINGLE_DEPTH_NESTING);
+	spin_lock_nested(&request->lock, I915_REQUEST_LOCK_SUBMIT);
 	request->global_seqno = seqno;
 	if (test_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, &request->fence.flags))
 		intel_engine_enable_signaling(request, false);
@@ -541,7 +541,7 @@ void __i915_gem_request_unsubmit(struct drm_i915_gem_request *request)
 	engine->timeline->seqno--;
 
 	/* We may be recursing from the signal callback of another i915 fence */
-	spin_lock_nested(&request->lock, SINGLE_DEPTH_NESTING);
+	spin_lock_nested(&request->lock, I915_REQUEST_LOCK_SUBMIT);
 	request->global_seqno = 0;
 	if (test_bit(DMA_FENCE_FLAG_ENABLE_SIGNAL_BIT, &request->fence.flags))
 		intel_engine_cancel_signaling(request);
diff --git a/drivers/gpu/drm/i915/i915_gem_request.h b/drivers/gpu/drm/i915/i915_gem_request.h
index 6c607f8dbf92..c8a45e9f8e33 100644
--- a/drivers/gpu/drm/i915/i915_gem_request.h
+++ b/drivers/gpu/drm/i915/i915_gem_request.h
@@ -204,6 +204,12 @@ struct drm_i915_gem_request {
 	struct list_head client_link;
 };
 
+enum {
+	I915_REQUEST_LOCK_NORMAL = 0,
+	I915_REQUEST_LOCK_SUBMIT,
+	I915_REQUEST_LOCK_SIGNAL,
+};
+
 #define I915_FENCE_GFP (GFP_KERNEL | __GFP_RETRY_MAYFAIL | __GFP_NOWARN)
 
 extern const struct dma_fence_ops i915_fence_ops;
diff --git a/drivers/gpu/drm/i915/i915_gem_timeline.c b/drivers/gpu/drm/i915/i915_gem_timeline.c
index e9fd87604067..fba0ddb6fe65 100644
--- a/drivers/gpu/drm/i915/i915_gem_timeline.c
+++ b/drivers/gpu/drm/i915/i915_gem_timeline.c
@@ -35,6 +35,7 @@ static void __intel_timeline_init(struct intel_timeline *tl,
 	tl->common = parent;
 	spin_lock_init(&tl->lock);
 	lockdep_set_class_and_name(&tl->lock, lockclass, lockname);
+	lockdep_set_subclass(&tl->lock, tl - parent->engine);
 	init_request_active(&tl->last_request, NULL);
 	INIT_LIST_HEAD(&tl->requests);
 	i915_syncmap_init(&tl->sync);
@@ -65,6 +66,7 @@ static int __i915_gem_timeline_init(struct drm_i915_private *i915,
 	 * any page crossing penalties if they become an issue.
 	 */
 	BUILD_BUG_ON(KSYNCMAP < I915_NUM_ENGINES);
+	BUILD_BUG_ON(ARRAY_SIZE(timeline->engine) > MAX_LOCKDEP_SUBCLASSES);
 
 	timeline->i915 = i915;
 	timeline->name = kstrdup(name ?: "[kernel]", GFP_KERNEL);
diff --git a/drivers/gpu/drm/i915/intel_breadcrumbs.c b/drivers/gpu/drm/i915/intel_breadcrumbs.c
index c0469298b8e8..bc930d7b0022 100644
--- a/drivers/gpu/drm/i915/intel_breadcrumbs.c
+++ b/drivers/gpu/drm/i915/intel_breadcrumbs.c
@@ -355,10 +355,21 @@ static inline struct intel_wait *to_wait(struct rb_node *node)
 static inline void __intel_breadcrumbs_finish(struct intel_breadcrumbs *b,
 					      struct intel_wait *wait)
 {
+	struct drm_i915_gem_request *rq = wait->request;
+
 	lockdep_assert_held(&b->rb_lock);
 	GEM_BUG_ON(b->irq_wait == wait);
 
-	/* This request is completed, so remove it from the tree, mark it as
+	if (rq && intel_wait_check_request(wait, rq)) {
+		if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &rq->fence.flags)) {
+			spin_lock_nested(&rq->lock, I915_REQUEST_LOCK_SIGNAL);
+			dma_fence_signal_locked(&rq->fence);
+			spin_unlock(&rq->lock);
+		}
+	}
+
+	/*
+	 * This request is completed, so remove it from the tree, mark it as
 	 * complete, and *then* wake up the associated task. N.B. when the
 	 * task wakes up, it will find the empty rb_node, discern that it
 	 * has already been removed from the tree and skip the serialisation
@@ -867,6 +878,9 @@ int intel_engine_init_breadcrumbs(struct intel_engine_cs *engine)
 	spin_lock_init(&b->rb_lock);
 	spin_lock_init(&b->irq_lock);
 
+	/* We want to allow nesting of multiple engines locks */
+	lockdep_set_novalidate_class(b->rb_lock);
+
 	timer_setup(&b->fake_irq, intel_breadcrumbs_fake_irq, 0);
 	timer_setup(&b->hangcheck, intel_breadcrumbs_hangcheck, 0);
 
-- 
2.15.1



More information about the Intel-gfx-trybot mailing list