Intel-GFX Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Dave Gordon <david.s.gordon@intel.com>
To: intel-gfx@lists.freedesktop.org
Subject: [PATCH v2 1/2] drm/i915: Track & check calls to intel(_logical)_ring_{begin, advance}
Date: Wed, 10 Dec 2014 16:12:14 +0000	[thread overview]
Message-ID: <1418227935-21630-2-git-send-email-david.s.gordon@intel.com> (raw)
In-Reply-To: <1418227935-21630-1-git-send-email-david.s.gordon@intel.com>

When adding instructions to a legacy or LRC ringbuffer, the sequence of
emit() calls must be preceded by a call to intel(_logical)_ring_begin()
to reserve the required amount of space, and followed by a matching call
to intel(_logical)_ring_advance() (note that this used to trigger
immediate submission to the h/w, but now actual submission is deferred
until all the instructions for a single batch submission have been
assembled). Historically some (display) code didn't use begin/advance,
but just inserted instructions ad hoc, which would then be sent to the
hardware along with the current or next batch, but this is not supported
and is now regarded as incorrect.

This commit therefore adds begin/advance tracking, with WARNings where
various forms of misuse are detected. These include:
* advance without begin
* begin without advance before submission to h/w
* multiple begins without an advance between
* exceeding the space reserved by begin
* leaving the ring misaligned
* ring buffer overrun (negative freespace)

Signed-off-by: Dave Gordon <david.s.gordon@intel.com>
---
 drivers/gpu/drm/i915/intel_lrc.c        |    4 ++-
 drivers/gpu/drm/i915/intel_lrc.h        |   11 ++++++-
 drivers/gpu/drm/i915/intel_ringbuffer.c |   10 ++++--
 drivers/gpu/drm/i915/intel_ringbuffer.h |   54 ++++++++++++++++++++++++++++++-
 4 files changed, 74 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index a82020e..56e3636 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -825,6 +825,7 @@ void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf)
 	struct intel_context *ctx = ringbuf->FIXME_lrc_ctx;
 
 	intel_logical_ring_advance(ringbuf);
+	WARN_ON(ringbuf->rsv_level != 0);
 
 	if (intel_ring_stopped(ring))
 		return;
@@ -1084,7 +1085,8 @@ int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, int num_dwords)
 	if (ret)
 		return ret;
 
-	ringbuf->space -= num_dwords * sizeof(uint32_t);
+	__intel_ringbuffer_begin(ringbuf, num_dwords);
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h
index 14b216b..9a0457e 100644
--- a/drivers/gpu/drm/i915/intel_lrc.h
+++ b/drivers/gpu/drm/i915/intel_lrc.h
@@ -48,8 +48,17 @@ void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf);
  */
 static inline void intel_logical_ring_advance(struct intel_ringbuffer *ringbuf)
 {
-	ringbuf->tail &= ringbuf->size - 1;
+	__intel_ringbuffer_check(ringbuf);
+
+	/*
+	 * Tail == effecive_size is legitimate (buffer exactly full).
+	 * Tail > effective_size is not, and should give a warning,
+	 * but we'll reset tail in both cases to prevent further chaos
+	 */
+	if (ringbuf->tail >= ringbuf->effective_size)
+		ringbuf->tail -= ringbuf->effective_size;
 }
+
 /**
  * intel_logical_ring_emit() - write a DWORD to the ringbuffer.
  * @ringbuf: Ringbuffer to write to.
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index 83accb7..5874eab 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -55,6 +55,7 @@ int __intel_ring_space(int head, int tail, int size)
 	int space = head - tail;
 	if (space <= 0)
 		space += size;
+	WARN_ON(space < I915_RING_FREE_SPACE);
 	return space - I915_RING_FREE_SPACE;
 }
 
@@ -84,7 +85,10 @@ bool intel_ring_stopped(struct intel_engine_cs *ring)
 void __intel_ring_advance(struct intel_engine_cs *ring)
 {
 	struct intel_ringbuffer *ringbuf = ring->buffer;
-	ringbuf->tail &= ringbuf->size - 1;
+
+	intel_ring_advance(ring);
+	WARN_ON(ringbuf->rsv_level != 0);
+
 	if (intel_ring_stopped(ring))
 		return;
 	ring->write_tail(ring, ringbuf->tail);
@@ -1911,6 +1915,7 @@ static int intel_ring_wait_request(struct intel_engine_cs *ring, int n)
 		return 0;
 
 	list_for_each_entry(request, &ring->request_list, list) {
+		/* Would completion of this request free enough space? */
 		if (__intel_ring_space(request->tail, ringbuf->tail,
 				       ringbuf->size) >= n) {
 			break;
@@ -2096,7 +2101,8 @@ int intel_ring_begin(struct intel_engine_cs *ring,
 	if (ret)
 		return ret;
 
-	ring->buffer->space -= num_dwords * sizeof(uint32_t);
+	__intel_ringbuffer_begin(ring->buffer, num_dwords);
+
 	return 0;
 }
 
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index 6dbb6f4..a6660c1 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -112,6 +112,11 @@ struct intel_ringbuffer {
 	int size;
 	int effective_size;
 
+	/* these let advance() check for misuse */
+	int rsv_level;	/* reservation nesting level */
+	int rsv_size;	/* size passed to begin() */
+	int rsv_start;	/* tail when begin() last returned */
+
 	/** We track the position of the requests in the ring buffer, and
 	 * when each is retired we increment last_retired_head as the GPU
 	 * must have finished processing the request and so we know we
@@ -401,11 +406,58 @@ static inline void intel_ring_emit(struct intel_engine_cs *ring,
 	iowrite32(data, ringbuf->virtual_start + ringbuf->tail);
 	ringbuf->tail += 4;
 }
+
+static inline void __intel_ringbuffer_begin(struct intel_ringbuffer *ringbuf,
+					    int num_dwords)
+{
+	int nbytes = num_dwords * sizeof(uint32_t);
+
+	WARN_ON(num_dwords & 1);
+	WARN_ON(nbytes <= 0);
+
+	if (ringbuf->rsv_level++) {
+		/* begin() called twice or more without advance() */
+		WARN_ON(1);
+	} else {
+		/*
+		 * A new reservation; validate and record the start and
+		 * size, then deduct the size from the remaining space
+		 */
+		WARN_ON(ringbuf->tail & 7);
+		WARN_ON(ringbuf->tail > ringbuf->effective_size-8);
+		WARN_ON(ringbuf->tail + nbytes > ringbuf->effective_size);
+		WARN_ON(ringbuf->space < nbytes);
+	}
+
+	ringbuf->rsv_start = ringbuf->tail;
+	ringbuf->rsv_size = nbytes;
+	ringbuf->space -= nbytes;
+}
+
+static inline void __intel_ringbuffer_check(struct intel_ringbuffer *ringbuf)
+{
+	WARN_ON(ringbuf->rsv_level-- != 1);
+	WARN_ON(ringbuf->rsv_start < 0 || ringbuf->rsv_size < 0);
+	WARN_ON(ringbuf->tail & 7);
+	WARN_ON(ringbuf->tail > ringbuf->rsv_start + ringbuf->rsv_size);
+	WARN_ON(ringbuf->tail > ringbuf->effective_size);
+}
+
 static inline void intel_ring_advance(struct intel_engine_cs *ring)
 {
 	struct intel_ringbuffer *ringbuf = ring->buffer;
-	ringbuf->tail &= ringbuf->size - 1;
+
+	__intel_ringbuffer_check(ringbuf);
+
+	/*
+	 * Tail == effecive_size is legitimate (buffer exactly full).
+	 * Tail > effective_size is not, and should give a warning,
+	 * but we'll reset tail in both cases to prevent further chaos
+	 */
+	if (ringbuf->tail >= ringbuf->effective_size)
+		ringbuf->tail -= ringbuf->effective_size;
 }
+
 int __intel_ring_space(int head, int tail, int size);
 void intel_ring_update_space(struct intel_ringbuffer *ringbuf);
 int intel_ring_space(struct intel_ringbuffer *ringbuf);
-- 
1.7.9.5

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

  reply	other threads:[~2014-12-10 16:18 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-12-10 15:07 [PATCH 0/2] Track calls to intel(_logical)_ring_{begin, advance} Dave Gordon
2014-12-10 15:07 ` [PATCH 1/2] drm/i915: Track & check " Dave Gordon
2014-12-10 15:44   ` Daniel Vetter
2014-12-10 15:07 ` [PATCH 2/2] drm/i915: Track nested " Dave Gordon
2014-12-10 22:46   ` shuang.he
2014-12-10 16:12 ` [PATCH v2 0/2] Track " Dave Gordon
2014-12-10 16:12   ` Dave Gordon [this message]
2014-12-10 16:12   ` [PATCH v2 2/2] drm/i915: Track nested " Dave Gordon
2014-12-11  0:30     ` shuang.he
2014-12-10 16:23 ` [PATCH 0/2] Track " Chris Wilson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1418227935-21630-2-git-send-email-david.s.gordon@intel.com \
    --to=david.s.gordon@intel.com \
    --cc=intel-gfx@lists.freedesktop.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox