<div dir="ltr"><div style="font-family:arial,sans-serif;font-size:13.3333339691162px">Reviewed the patch & it looks fine.</div><div style="font-family:arial,sans-serif;font-size:13.3333339691162px">Reviewed-by: "Akash Goel <<a href="mailto:akash.goels@gmail.com" target="_blank">akash.goels@gmail.com</a>>"</div><div class="gmail_extra"><br><div class="gmail_quote">On Mon, Nov 3, 2014 at 6:59 PM, Dave Gordon <span dir="ltr"><<a href="mailto:david.s.gordon@intel.com" target="_blank">david.s.gordon@intel.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Fixes to both the LRC and the legacy ringbuffer code to correctly<br>
calculate and update the available space in a ring.<br>
<br>
The logical ring code was updating the software ring 'head' value<br>
by reading the hardware 'HEAD' register. In LRC mode, this is not<br>
valid as the hardware is not necessarily executing the same context<br>
that is being processed by the software. Thus reading the h/w HEAD<br>
could put an unrelated (undefined, effectively random) value into<br>
the s/w 'head' -- A Bad Thing for the free space calculations.<br>
<br>
In addition, the old code could update a ringbuffer's 'head' value<br>
from the 'last_retired_head' even when the latter hadn't been recently<br>
updated and therefore had a value of -1; this would also confuse the<br>
freespace calculations. Now, we consume 'last_retired_head' in just<br>
one place, ensuring that this confusion does not arise.<br>
<br>
Change-Id: Id7ce9096ed100a2882c68a54206f30b6c87e92fa<br>
Signed-off-by: Dave Gordon <<a href="mailto:david.s.gordon@intel.com">david.s.gordon@intel.com</a>><br>
---<br>
 drivers/gpu/drm/i915/i915_dma.c         |    5 ++-<br>
 drivers/gpu/drm/i915/intel_lrc.c        |   36 ++++++++++-----------<br>
 drivers/gpu/drm/i915/intel_ringbuffer.c |   53 ++++++++++++++++---------------<br>
 drivers/gpu/drm/i915/intel_ringbuffer.h |    1 +<br>
 4 files changed, 48 insertions(+), 47 deletions(-)<br>
<br>
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c<br>
index 9a73533..1646416 100644<br>
--- a/drivers/gpu/drm/i915/i915_dma.c<br>
+++ b/drivers/gpu/drm/i915/i915_dma.c<br>
@@ -154,11 +154,10 @@ void i915_kernel_lost_context(struct drm_device *dev)<br>
        if (drm_core_check_feature(dev, DRIVER_MODESET))<br>
                return;<br>
<br>
+       ringbuf->last_retired_head = -1;<br>
        ringbuf->head = I915_READ_HEAD(ring) & HEAD_ADDR;<br>
        ringbuf->tail = I915_READ_TAIL(ring) & TAIL_ADDR;<br>
-       ringbuf->space = ringbuf->head - (ringbuf->tail + I915_RING_FREE_SPACE);<br>
-       if (ringbuf->space < 0)<br>
-               ringbuf->space += ringbuf->size;<br>
+       intel_ring_update_space(ringbuf);<br>
<br>
        if (!dev->primary->master)<br>
                return;<br>
diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c<br>
index cd74e5c..11a9047 100644<br>
--- a/drivers/gpu/drm/i915/intel_lrc.c<br>
+++ b/drivers/gpu/drm/i915/intel_lrc.c<br>
@@ -827,16 +827,20 @@ static int logical_ring_wait_request(struct intel_ringbuffer *ringbuf,<br>
        u32 seqno = 0;<br>
        int ret;<br>
<br>
-       if (ringbuf->last_retired_head != -1) {<br>
-               ringbuf->head = ringbuf->last_retired_head;<br>
-               ringbuf->last_retired_head = -1;<br>
-<br>
-               ringbuf->space = intel_ring_space(ringbuf);<br>
-               if (ringbuf->space >= bytes)<br>
-                       return 0;<br>
-       }<br>
+       if (intel_ring_space(ringbuf) >= bytes)<br>
+               return 0;<br>
<br>
        list_for_each_entry(request, &ring->request_list, list) {<br>
+               /*<br>
+                * The request queue is per-engine, so can contain requests<br>
+                * from multiple ringbuffers. Here, we must ignore any that<br>
+                * aren't from the ringbuffer we're considering.<br>
+                */<br>
+               struct intel_context *ctx = request->ctx;<br>
+               if (ctx->engine[ring->id].ringbuf != ringbuf)<br>
+                       continue;<br>
+<br>
+               /* Would completion of this request free enough space? */<br>
                if (__intel_ring_space(request->tail, ringbuf->tail,<br>
                                       ringbuf->size) >= bytes) {<br>
                        seqno = request->seqno;<br>
@@ -852,11 +856,8 @@ static int logical_ring_wait_request(struct intel_ringbuffer *ringbuf,<br>
                return ret;<br>
<br>
        i915_gem_retire_requests_ring(ring);<br>
-       ringbuf->head = ringbuf->last_retired_head;<br>
-       ringbuf->last_retired_head = -1;<br>
<br>
-       ringbuf->space = intel_ring_space(ringbuf);<br>
-       return 0;<br>
+       return intel_ring_space(ringbuf) >= bytes ? 0 : -ENOSPC;<br>
 }<br>
<br>
 static int logical_ring_wait_for_space(struct intel_ringbuffer *ringbuf,<br>
@@ -882,13 +883,10 @@ static int logical_ring_wait_for_space(struct intel_ringbuffer *ringbuf,<br>
         * case by choosing an insanely large timeout. */<br>
        end = jiffies + 60 * HZ;<br>
<br>
+       ret = 0;<br>
        do {<br>
-               ringbuf->head = I915_READ_HEAD(ring);<br>
-               ringbuf->space = intel_ring_space(ringbuf);<br>
-               if (ringbuf->space >= bytes) {<br>
-                       ret = 0;<br>
+               if (intel_ring_space(ringbuf) >= bytes)<br>
                        break;<br>
-               }<br>
<br>
                msleep(1);<br>
<br>
@@ -929,7 +927,7 @@ static int logical_ring_wrap_buffer(struct intel_ringbuffer *ringbuf)<br>
                iowrite32(MI_NOOP, virt++);<br>
<br>
        ringbuf->tail = 0;<br>
-       ringbuf->space = intel_ring_space(ringbuf);<br>
+       intel_ring_update_space(ringbuf);<br>
<br>
        return 0;<br>
 }<br>
@@ -1708,8 +1706,8 @@ int intel_lr_context_deferred_create(struct intel_context *ctx,<br>
        ringbuf->effective_size = ringbuf->size;<br>
        ringbuf->head = 0;<br>
        ringbuf->tail = 0;<br>
-       ringbuf->space = ringbuf->size;<br>
        ringbuf->last_retired_head = -1;<br>
+       intel_ring_update_space(ringbuf);<br>
<br>
        /* TODO: For now we put this in the mappable region so that we can reuse<br>
         * the existing ringbuffer code which ioremaps it. When we start<br>
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c<br>
index a8f72e8..1150862 100644<br>
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c<br>
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c<br>
@@ -52,16 +52,27 @@ intel_ring_initialized(struct intel_engine_cs *ring)<br>
<br>
 int __intel_ring_space(int head, int tail, int size)<br>
 {<br>
-       int space = head - (tail + I915_RING_FREE_SPACE);<br>
-       if (space < 0)<br>
+       int space = head - tail;<br>
+       if (space <= 0)<br>
                space += size;<br>
-       return space;<br>
+       return space - I915_RING_FREE_SPACE;<br>
+}<br>
+<br>
+void intel_ring_update_space(struct intel_ringbuffer *ringbuf)<br>
+{<br>
+       if (ringbuf->last_retired_head != -1) {<br>
+               ringbuf->head = ringbuf->last_retired_head;<br>
+               ringbuf->last_retired_head = -1;<br>
+       }<br>
+<br>
+       ringbuf->space = __intel_ring_space(ringbuf->head & HEAD_ADDR,<br>
+                                           ringbuf->tail, ringbuf->size);<br>
 }<br>
<br>
 int intel_ring_space(struct intel_ringbuffer *ringbuf)<br>
 {<br>
-       return __intel_ring_space(ringbuf->head & HEAD_ADDR,<br>
-                                 ringbuf->tail, ringbuf->size);<br>
+       intel_ring_update_space(ringbuf);<br>
+       return ringbuf->space;<br>
 }<br>
<br>
 bool intel_ring_stopped(struct intel_engine_cs *ring)<br>
@@ -73,7 +84,7 @@ bool intel_ring_stopped(struct intel_engine_cs *ring)<br>
 void __intel_ring_advance(struct intel_engine_cs *ring)<br>
 {<br>
        struct intel_ringbuffer *ringbuf = ring->buffer;<br>
-       ringbuf->tail &= ringbuf->size - 1;<br>
+       intel_ring_advance(ring);<br>
        if (intel_ring_stopped(ring))<br>
                return;<br>
        ring->write_tail(ring, ringbuf->tail);<br>
@@ -592,10 +603,10 @@ static int init_ring_common(struct intel_engine_cs *ring)<br>
        if (!drm_core_check_feature(ring->dev, DRIVER_MODESET))<br>
                i915_kernel_lost_context(ring->dev);<br>
        else {<br>
+               ringbuf->last_retired_head = -1;<br>
                ringbuf->head = I915_READ_HEAD(ring);<br>
                ringbuf->tail = I915_READ_TAIL(ring) & TAIL_ADDR;<br>
-               ringbuf->space = intel_ring_space(ringbuf);<br>
-               ringbuf->last_retired_head = -1;<br>
+               intel_ring_update_space(ringbuf);<br>
        }<br>
<br>
        memset(&ring->hangcheck, 0, sizeof(ring->hangcheck));<br>
@@ -1876,14 +1887,8 @@ static int intel_ring_wait_request(struct intel_engine_cs *ring, int n)<br>
        u32 seqno = 0;<br>
        int ret;<br>
<br>
-       if (ringbuf->last_retired_head != -1) {<br>
-               ringbuf->head = ringbuf->last_retired_head;<br>
-               ringbuf->last_retired_head = -1;<br>
-<br>
-               ringbuf->space = intel_ring_space(ringbuf);<br>
-               if (ringbuf->space >= n)<br>
-                       return 0;<br>
-       }<br>
+       if (intel_ring_space(ringbuf) >= n)<br>
+               return 0;<br>
<br>
        list_for_each_entry(request, &ring->request_list, list) {<br>
                if (__intel_ring_space(request->tail, ringbuf->tail,<br>
@@ -1901,10 +1906,7 @@ static int intel_ring_wait_request(struct intel_engine_cs *ring, int n)<br>
                return ret;<br>
<br>
        i915_gem_retire_requests_ring(ring);<br>
-       ringbuf->head = ringbuf->last_retired_head;<br>
-       ringbuf->last_retired_head = -1;<br>
<br>
-       ringbuf->space = intel_ring_space(ringbuf);<br>
        return 0;<br>
 }<br>
<br>
@@ -1930,14 +1932,14 @@ static int ring_wait_for_space(struct intel_engine_cs *ring, int n)<br>
         * case by choosing an insanely large timeout. */<br>
        end = jiffies + 60 * HZ;<br>
<br>
+       ret = 0;<br>
        trace_i915_ring_wait_begin(ring);<br>
        do {<br>
+               if (intel_ring_space(ringbuf) >= n)<br>
+                       break;<br>
                ringbuf->head = I915_READ_HEAD(ring);<br>
-               ringbuf->space = intel_ring_space(ringbuf);<br>
-               if (ringbuf->space >= n) {<br>
-                       ret = 0;<br>
+               if (intel_ring_space(ringbuf) >= n)<br>
                        break;<br>
-               }<br>
<br>
                if (!drm_core_check_feature(dev, DRIVER_MODESET) &&<br>
                    dev->primary->master) {<br>
@@ -1985,7 +1987,7 @@ static int intel_wrap_ring_buffer(struct intel_engine_cs *ring)<br>
                iowrite32(MI_NOOP, virt++);<br>
<br>
        ringbuf->tail = 0;<br>
-       ringbuf->space = intel_ring_space(ringbuf);<br>
+       intel_ring_update_space(ringbuf);<br>
<br>
        return 0;<br>
 }<br>
@@ -2057,6 +2059,7 @@ int intel_ring_begin(struct intel_engine_cs *ring,<br>
                     int num_dwords)<br>
 {<br>
        struct drm_i915_private *dev_priv = ring->dev->dev_private;<br>
+       struct intel_ringbuffer *ringbuf = ring->buffer;<br>
        int ret;<br>
<br>
        ret = i915_gem_check_wedge(&dev_priv->gpu_error,<br>
@@ -2073,7 +2076,7 @@ int intel_ring_begin(struct intel_engine_cs *ring,<br>
        if (ret)<br>
                return ret;<br>
<br>
-       ring->buffer->space -= num_dwords * sizeof(uint32_t);<br>
+       ringbuf->space -= num_dwords * sizeof(uint32_t);<br>
        return 0;<br>
 }<br>
<br>
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h<br>
index 96479c8..2a1e484 100644<br>
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h<br>
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h<br>
@@ -403,6 +403,7 @@ static inline void intel_ring_advance(struct intel_engine_cs *ring)<br>
        ringbuf->tail &= ringbuf->size - 1;<br>
 }<br>
 int __intel_ring_space(int head, int tail, int size);<br>
+void intel_ring_update_space(struct intel_ringbuffer *ringbuf);<br>
 int intel_ring_space(struct intel_ringbuffer *ringbuf);<br>
 bool intel_ring_stopped(struct intel_engine_cs *ring);<br>
 void __intel_ring_advance(struct intel_engine_cs *ring);<br>
<span class="HOEnZb"><font color="#888888">--<br>
1.7.9.5<br>
<br>
_______________________________________________<br>
Intel-gfx mailing list<br>
<a href="mailto:Intel-gfx@lists.freedesktop.org">Intel-gfx@lists.freedesktop.org</a><br>
<a href="http://lists.freedesktop.org/mailman/listinfo/intel-gfx" target="_blank">http://lists.freedesktop.org/mailman/listinfo/intel-gfx</a><br>
</font></span></blockquote></div><br></div></div>