<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><div class="gmail_extra"><br><div class="gmail_quote">On Thu, Nov 13, 2014 at 3:58 PM, Thomas Daniel <span dir="ltr"><<a href="mailto:thomas.daniel@intel.com" target="_blank">thomas.daniel@intel.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">Same as with the context, pinning to GGTT regardless is harmful (it<br>
badly fragments the GGTT and can even exhaust it).<br>
<br>
Unfortunately, this case is also more complex than the previous one<br>
because we need to map and access the ringbuffer in several places<br>
along the execbuffer path (and we cannot make do by leaving the<br>
default ringbuffer pinned, as before). Also, the context object<br>
itself contains a pointer to the ringbuffer address that we have to<br>
keep updated if we are going to allow the ringbuffer to move around.<br>
<br>
v2: Same as with the context pinning, we cannot really do it during<br>
an interrupt. Also, pin the default ringbuffers objects regardless<br>
(makes error capture a lot easier).<br>
<br>
v3: Rebased. Take a pin reference of the ringbuffer for each item<br>
in the execlist request queue because the hardware may still be using<br>
the ringbuffer after the MI_USER_INTERRUPT to notify the seqno update<br>
is executed.  The ringbuffer must remain pinned until the context save<br>
is complete.  No longer pin and unpin ringbuffer in<br>
populate_lr_context() - this transient address is meaningless and the<br>
pinning can cause a sleep while atomic.<br>
<br>
v4: Moved ringbuffer pin and unpin into the lr_context_pin functions.<br>
Downgraded pinning check BUG_ONs to WARN_ONs.<br>
<br>
</span>v5: Reinstated WARN_ONs for unexpected execlist states.  Removed unused<br>
variable.<br>
<span class=""><br>
Issue: VIZ-4277<br>
Signed-off-by: Oscar Mateo <<a href="mailto:oscar.mateo@intel.com">oscar.mateo@intel.com</a>><br>
Signed-off-by: Thomas Daniel <<a href="mailto:thomas.daniel@intel.com">thomas.daniel@intel.com</a>><br>
---<br>
</span> drivers/gpu/drm/i915/intel_lrc.c        |  102 +++++++++++++++++++++++--------<br>
 drivers/gpu/drm/i915/intel_ringbuffer.c |   85 +++++++++++++++-----------<br>
 drivers/gpu/drm/i915/intel_ringbuffer.h |    3 +<br>
 3 files changed, 128 insertions(+), 62 deletions(-)<br>
<br>
diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c<br>
index f7fa0f7..ca20f91 100644<br>
<div><div class="h5">--- a/drivers/gpu/drm/i915/intel_lrc.c<br>
+++ b/drivers/gpu/drm/i915/intel_lrc.c<br>
@@ -202,6 +202,9 @@ enum {<br>
 };<br>
 #define GEN8_CTX_ID_SHIFT 32<br>
<br>
+static int intel_lr_context_pin(struct intel_engine_cs *ring,<br>
+               struct intel_context *ctx);<br>
+<br>
 /**<br>
  * intel_sanitize_enable_execlists() - sanitize i915.enable_execlists<br>
  * @dev: DRM device.<br>
@@ -339,7 +342,9 @@ static void execlists_elsp_write(struct intel_engine_cs *ring,<br>
        spin_unlock_irqrestore(&dev_priv->uncore.lock, flags);<br>
 }<br>
<br>
-static int execlists_ctx_write_tail(struct drm_i915_gem_object *ctx_obj, u32 tail)<br>
+static int execlists_update_context(struct drm_i915_gem_object *ctx_obj,<br>
+                                   struct drm_i915_gem_object *ring_obj,<br>
+                                   u32 tail)<br>
 {<br>
        struct page *page;<br>
        uint32_t *reg_state;<br>
@@ -348,6 +353,7 @@ static int execlists_ctx_write_tail(struct drm_i915_gem_object *ctx_obj, u32 tai<br>
        reg_state = kmap_atomic(page);<br>
<br>
        reg_state[CTX_RING_TAIL+1] = tail;<br>
+       reg_state[CTX_RING_BUFFER_START+1] = i915_gem_obj_ggtt_offset(ring_obj);<br>
<br>
        kunmap_atomic(reg_state);<br>
<br>
@@ -358,21 +364,25 @@ static int execlists_submit_context(struct intel_engine_cs *ring,<br>
                                    struct intel_context *to0, u32 tail0,<br>
                                    struct intel_context *to1, u32 tail1)<br>
 {<br>
-       struct drm_i915_gem_object *ctx_obj0;<br>
+       struct drm_i915_gem_object *ctx_obj0 = to0->engine[ring->id].state;<br>
+       struct intel_ringbuffer *ringbuf0 = to0->engine[ring->id].ringbuf;<br>
        struct drm_i915_gem_object *ctx_obj1 = NULL;<br>
+       struct intel_ringbuffer *ringbuf1 = NULL;<br>
<br>
-       ctx_obj0 = to0->engine[ring->id].state;<br>
        BUG_ON(!ctx_obj0);<br>
        WARN_ON(!i915_gem_obj_is_pinned(ctx_obj0));<br>
+       WARN_ON(!i915_gem_obj_is_pinned(ringbuf0->obj));<br>
<br>
-       execlists_ctx_write_tail(ctx_obj0, tail0);<br>
+       execlists_update_context(ctx_obj0, ringbuf0->obj, tail0);<br>
<br>
        if (to1) {<br>
+               ringbuf1 = to1->engine[ring->id].ringbuf;<br>
                ctx_obj1 = to1->engine[ring->id].state;<br>
                BUG_ON(!ctx_obj1);<br>
                WARN_ON(!i915_gem_obj_is_pinned(ctx_obj1));<br>
+               WARN_ON(!i915_gem_obj_is_pinned(ringbuf1->obj));<br>
<br>
-               execlists_ctx_write_tail(ctx_obj1, tail1);<br>
+               execlists_update_context(ctx_obj1, ringbuf1->obj, tail1);<br>
        }<br>
<br>
        execlists_elsp_write(ring, ctx_obj0, ctx_obj1);<br>
</div></div>@@ -524,6 +534,10 @@ static int execlists_context_queue(struct intel_engine_cs *ring,<br>
<span class="">                return -ENOMEM;<br>
        req->ctx = to;<br>
        i915_gem_context_reference(req->ctx);<br>
+<br>
+       if (to != ring->default_context)<br>
+               intel_lr_context_pin(ring, to);<br>
+<br>
        req->ring = ring;<br>
        req->tail = tail;<br>
<br>
</span>@@ -544,7 +558,7 @@ static int execlists_context_queue(struct intel_engine_cs *ring,<br>
<span class=""><br>
                if (to == tail_req->ctx) {<br>
                        WARN(tail_req->elsp_submitted != 0,<br>
-                            "More than 2 already-submitted reqs queued\n");<br>
+                               "More than 2 already-submitted reqs queued\n");<br>
                        list_del(&tail_req->execlist_link);<br>
                        list_add_tail(&tail_req->execlist_link,<br>
                                &ring->execlist_retired_req_list);<br>
</span>@@ -732,6 +746,12 @@ void intel_execlists_retire_requests(struct intel_engine_cs *ring)<br>
<span class="">        spin_unlock_irqrestore(&ring->execlist_lock, flags);<br>
<br>
        list_for_each_entry_safe(req, tmp, &retired_list, execlist_link) {<br>
+               struct intel_context *ctx = req->ctx;<br>
+               struct drm_i915_gem_object *ctx_obj =<br>
+                               ctx->engine[ring->id].state;<br>
+<br>
+               if (ctx_obj && (ctx != ring->default_context))<br>
+                       intel_lr_context_unpin(ring, ctx);<br>
                intel_runtime_pm_put(dev_priv);<br>
                i915_gem_context_unreference(req->ctx);<br>
                list_del(&req->execlist_link);<br>
</span>@@ -803,6 +823,7 @@ static int intel_lr_context_pin(struct intel_engine_cs *ring,<br>
<span class="">                struct intel_context *ctx)<br>
 {<br>
        struct drm_i915_gem_object *ctx_obj = ctx->engine[ring->id].state;<br>
+       struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf;<br>
        int ret = 0;<br>
<br>
</span>        WARN_ON(!mutex_is_locked(&ring->dev->struct_mutex));<br>
@@ -810,21 +831,35 @@ static int intel_lr_context_pin(struct intel_engine_cs *ring,<br>
<span class="">                ret = i915_gem_obj_ggtt_pin(ctx_obj,<br>
                                GEN8_LR_CONTEXT_ALIGN, 0);<br>
                if (ret)<br>
-                       ctx->engine[ring->id].unpin_count = 0;<br>
+                       goto reset_unpin_count;<br>
+<br>
+               ret = intel_pin_and_map_ringbuffer_obj(ring->dev, ringbuf);<br>
+               if (ret)<br>
+                       goto unpin_ctx_obj;<br>
        }<br>
<br>
</span><span class="">        return ret;<br>
+<br>
+unpin_ctx_obj:<br>
+       i915_gem_object_ggtt_unpin(ctx_obj);<br>
+reset_unpin_count:<br>
+       ctx->engine[ring->id].unpin_count = 0;<br>
+<br>
</span><span class="">+       return ret;<br>
 }<br>
<br>
 void intel_lr_context_unpin(struct intel_engine_cs *ring,<br>
                struct intel_context *ctx)<br>
 {<br>
        struct drm_i915_gem_object *ctx_obj = ctx->engine[ring->id].state;<br>
+       struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf;<br>
<br>
        if (ctx_obj) {<br>
</span>                WARN_ON(!mutex_is_locked(&ring->dev->struct_mutex));<br>
<span class="">-               if (--ctx->engine[ring->id].unpin_count == 0)<br>
+               if (--ctx->engine[ring->id].unpin_count == 0) {<br>
+                       intel_unpin_ringbuffer_obj(ringbuf);<br>
                        i915_gem_object_ggtt_unpin(ctx_obj);<br>
+               }<br>
        }<br>
 }<br>
<br>
</span>@@ -1541,7 +1576,6 @@ populate_lr_context(struct intel_context *ctx, struct drm_i915_gem_object *ctx_o<br>
<span class=""> {<br>
        struct drm_device *dev = ring->dev;<br>
        struct drm_i915_private *dev_priv = dev->dev_private;<br>
-       struct drm_i915_gem_object *ring_obj = ringbuf->obj;<br>
        struct i915_hw_ppgtt *ppgtt = ctx->ppgtt;<br>
        struct page *page;<br>
        uint32_t *reg_state;<br>
</span>@@ -1587,7 +1621,9 @@ populate_lr_context(struct intel_context *ctx, struct drm_i915_gem_object *ctx_o<br>
<span class="">        reg_state[CTX_RING_TAIL] = RING_TAIL(ring->mmio_base);<br>
        reg_state[CTX_RING_TAIL+1] = 0;<br>
        reg_state[CTX_RING_BUFFER_START] = RING_START(ring->mmio_base);<br>
-       reg_state[CTX_RING_BUFFER_START+1] = i915_gem_obj_ggtt_offset(ring_obj);<br>
+       /* Ring buffer start address is not known until the buffer is pinned.<br>
+        * It is written to the context image in execlists_update_context()<br>
+        */<br>
        reg_state[CTX_RING_BUFFER_CONTROL] = RING_CTL(ring->mmio_base);<br>
        reg_state[CTX_RING_BUFFER_CONTROL+1] =<br>
                        ((ringbuf->size - PAGE_SIZE) & RING_NR_PAGES) | RING_VALID;<br>
</span>@@ -1669,10 +1705,12 @@ void intel_lr_context_free(struct intel_context *ctx)<br>
<span class="">                                        ctx->engine[i].ringbuf;<br>
                        struct intel_engine_cs *ring = ringbuf->ring;<br>
<br>
+                       if (ctx == ring->default_context) {<br>
+                               intel_unpin_ringbuffer_obj(ringbuf);<br>
+                               i915_gem_object_ggtt_unpin(ctx_obj);<br>
+                       }<br>
                        intel_destroy_ringbuffer_obj(ringbuf);<br>
                        kfree(ringbuf);<br>
-                       if (ctx == ring->default_context)<br>
-                               i915_gem_object_ggtt_unpin(ctx_obj);<br>
                        drm_gem_object_unreference(&ctx_obj->base);<br>
                }<br>
        }<br>
</span>@@ -1770,11 +1808,8 @@ int intel_lr_context_deferred_create(struct intel_context *ctx,<br>
<span class="">        if (!ringbuf) {<br>
                DRM_DEBUG_DRIVER("Failed to allocate ringbuffer %s\n",<br>
                                ring->name);<br>
-               if (is_global_default_ctx)<br>
-                       i915_gem_object_ggtt_unpin(ctx_obj);<br>
-               drm_gem_object_unreference(&ctx_obj->base);<br>
                ret = -ENOMEM;<br>
-               return ret;<br>
+               goto error_unpin_ctx;<br>
        }<br>
<br>
        ringbuf->ring = ring;<br>
</span>@@ -1787,22 +1822,30 @@ int intel_lr_context_deferred_create(struct intel_context *ctx,<br>
<div><div class="h5">        ringbuf->space = ringbuf->size;<br>
        ringbuf->last_retired_head = -1;<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>
-        * creating many contexts, this will no longer work and we must switch<br>
-        * to a kmapish interface.<br>
-        */<br>
-       ret = intel_alloc_ringbuffer_obj(dev, ringbuf);<br>
-       if (ret) {<br>
-               DRM_DEBUG_DRIVER("Failed to allocate ringbuffer obj %s: %d\n",<br>
+       if (ringbuf->obj == NULL) {<br>
+               ret = intel_alloc_ringbuffer_obj(dev, ringbuf);<br>
+               if (ret) {<br>
+                       DRM_DEBUG_DRIVER(<br>
+                               "Failed to allocate ringbuffer obj %s: %d\n",<br>
                                ring->name, ret);<br>
-               goto error;<br>
+                       goto error_free_rbuf;<br>
+               }<br>
+<br>
+               if (is_global_default_ctx) {<br>
+                       ret = intel_pin_and_map_ringbuffer_obj(dev, ringbuf);<br>
+                       if (ret) {<br>
+                               DRM_ERROR(<br>
+                                       "Failed to pin and map ringbuffer %s: %d\n",<br>
+                                       ring->name, ret);<br>
+                               goto error_destroy_rbuf;<br>
+                       }<br>
+               }<br>
+<br>
        }<br>
<br>
        ret = populate_lr_context(ctx, ctx_obj, ring, ringbuf);<br>
        if (ret) {<br>
                DRM_DEBUG_DRIVER("Failed to populate LRC: %d\n", ret);<br>
-               intel_destroy_ringbuffer_obj(ringbuf);<br>
                goto error;<br>
        }<br>
<br>
</div></div>@@ -1823,7 +1866,6 @@ int intel_lr_context_deferred_create(struct intel_context *ctx,<br>
<span class="">                        DRM_ERROR("Init render state failed: %d\n", ret);<br>
                        ctx->engine[ring->id].ringbuf = NULL;<br>
                        ctx->engine[ring->id].state = NULL;<br>
-                       intel_destroy_ringbuffer_obj(ringbuf);<br>
                        goto error;<br>
                }<br>
                ctx->rcs_initialized = true;<br>
</span>@@ -1832,7 +1874,13 @@ int intel_lr_context_deferred_create(struct intel_context *ctx,<br>
<span class="im HOEnZb">        return 0;<br>
<br>
 error:<br>
+       if (is_global_default_ctx)<br>
+               intel_unpin_ringbuffer_obj(ringbuf);<br>
+error_destroy_rbuf:<br>
+       intel_destroy_ringbuffer_obj(ringbuf);<br>
+error_free_rbuf:<br>
        kfree(ringbuf);<br>
+error_unpin_ctx:<br>
        if (is_global_default_ctx)<br>
                i915_gem_object_ggtt_unpin(ctx_obj);<br>
        drm_gem_object_unreference(&ctx_obj->base);<br>
</span><div class="HOEnZb"><div class="h5">diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c<br>
index a8f72e8..0c4aab1 100644<br>
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c<br>
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c<br>
@@ -1721,13 +1721,42 @@ static int init_phys_status_page(struct intel_engine_cs *ring)<br>
        return 0;<br>
 }<br>
<br>
-void intel_destroy_ringbuffer_obj(struct intel_ringbuffer *ringbuf)<br>
+void intel_unpin_ringbuffer_obj(struct intel_ringbuffer *ringbuf)<br>
 {<br>
-       if (!ringbuf->obj)<br>
-               return;<br>
-<br>
        iounmap(ringbuf->virtual_start);<br>
+       ringbuf->virtual_start = NULL;<br>
        i915_gem_object_ggtt_unpin(ringbuf->obj);<br>
+}<br>
+<br>
+int intel_pin_and_map_ringbuffer_obj(struct drm_device *dev,<br>
+                                    struct intel_ringbuffer *ringbuf)<br>
+{<br>
+       struct drm_i915_private *dev_priv = to_i915(dev);<br>
+       struct drm_i915_gem_object *obj = ringbuf->obj;<br>
+       int ret;<br>
+<br>
+       ret = i915_gem_obj_ggtt_pin(obj, PAGE_SIZE, PIN_MAPPABLE);<br>
+       if (ret)<br>
+               return ret;<br>
+<br>
+       ret = i915_gem_object_set_to_gtt_domain(obj, true);<br>
+       if (ret) {<br>
+               i915_gem_object_ggtt_unpin(obj);<br>
+               return ret;<br>
+       }<br>
+<br>
+       ringbuf->virtual_start = ioremap_wc(dev_priv->gtt.mappable_base +<br>
+                       i915_gem_obj_ggtt_offset(obj), ringbuf->size);<br>
+       if (ringbuf->virtual_start == NULL) {<br>
+               i915_gem_object_ggtt_unpin(obj);<br>
+               return -EINVAL;<br>
+       }<br>
+<br>
+       return 0;<br>
+}<br>
+<br>
+void intel_destroy_ringbuffer_obj(struct intel_ringbuffer *ringbuf)<br>
+{<br>
        drm_gem_object_unreference(&ringbuf->obj->base);<br>
        ringbuf->obj = NULL;<br>
 }<br>
@@ -1735,12 +1764,7 @@ void intel_destroy_ringbuffer_obj(struct intel_ringbuffer *ringbuf)<br>
 int intel_alloc_ringbuffer_obj(struct drm_device *dev,<br>
                               struct intel_ringbuffer *ringbuf)<br>
 {<br>
-       struct drm_i915_private *dev_priv = to_i915(dev);<br>
        struct drm_i915_gem_object *obj;<br>
-       int ret;<br>
-<br>
-       if (ringbuf->obj)<br>
-               return 0;<br>
<br>
        obj = NULL;<br>
        if (!HAS_LLC(dev))<br>
@@ -1753,30 +1777,9 @@ int intel_alloc_ringbuffer_obj(struct drm_device *dev,<br>
        /* mark ring buffers as read-only from GPU side by default */<br>
        obj->gt_ro = 1;<br>
<br>
-       ret = i915_gem_obj_ggtt_pin(obj, PAGE_SIZE, PIN_MAPPABLE);<br>
-       if (ret)<br>
-               goto err_unref;<br>
-<br>
-       ret = i915_gem_object_set_to_gtt_domain(obj, true);<br>
-       if (ret)<br>
-               goto err_unpin;<br>
-<br>
-       ringbuf->virtual_start =<br>
-               ioremap_wc(dev_priv->gtt.mappable_base + i915_gem_obj_ggtt_offset(obj),<br>
-                               ringbuf->size);<br>
-       if (ringbuf->virtual_start == NULL) {<br>
-               ret = -EINVAL;<br>
-               goto err_unpin;<br>
-       }<br>
-<br>
        ringbuf->obj = obj;<br>
-       return 0;<br>
<br>
-err_unpin:<br>
-       i915_gem_object_ggtt_unpin(obj);<br>
-err_unref:<br>
-       drm_gem_object_unreference(&obj->base);<br>
-       return ret;<br>
+       return 0;<br>
 }<br>
<br>
 static int intel_init_ring_buffer(struct drm_device *dev,<br>
@@ -1813,10 +1816,21 @@ static int intel_init_ring_buffer(struct drm_device *dev,<br>
                        goto error;<br>
        }<br>
<br>
-       ret = intel_alloc_ringbuffer_obj(dev, ringbuf);<br>
-       if (ret) {<br>
-               DRM_ERROR("Failed to allocate ringbuffer %s: %d\n", ring->name, ret);<br>
-               goto error;<br>
+       if (ringbuf->obj == NULL) {<br>
+               ret = intel_alloc_ringbuffer_obj(dev, ringbuf);<br>
+               if (ret) {<br>
+                       DRM_ERROR("Failed to allocate ringbuffer %s: %d\n",<br>
+                                       ring->name, ret);<br>
+                       goto error;<br>
+               }<br>
+<br>
+               ret = intel_pin_and_map_ringbuffer_obj(dev, ringbuf);<br>
+               if (ret) {<br>
+                       DRM_ERROR("Failed to pin and map ringbuffer %s: %d\n",<br>
+                                       ring->name, ret);<br>
+                       intel_destroy_ringbuffer_obj(ringbuf);<br>
+                       goto error;<br>
+               }<br>
        }<br>
<br>
        /* Workaround an erratum on the i830 which causes a hang if<br>
@@ -1854,6 +1868,7 @@ void intel_cleanup_ring_buffer(struct intel_engine_cs *ring)<br>
        intel_stop_ring_buffer(ring);<br>
        WARN_ON(!IS_GEN2(ring->dev) && (I915_READ_MODE(ring) & MODE_IDLE) == 0);<br>
<br>
+       intel_unpin_ringbuffer_obj(ringbuf);<br>
        intel_destroy_ringbuffer_obj(ringbuf);<br>
        ring->preallocated_lazy_request = NULL;<br>
        ring->outstanding_lazy_seqno = 0;<br>
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h<br>
index 8c002d2..365854ad 100644<br>
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h<br>
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h<br>
@@ -382,6 +382,9 @@ intel_write_status_page(struct intel_engine_cs *ring,<br>
 #define I915_GEM_HWS_SCRATCH_INDEX     0x30<br>
 #define I915_GEM_HWS_SCRATCH_ADDR (I915_GEM_HWS_SCRATCH_INDEX << MI_STORE_DWORD_INDEX_SHIFT)<br>
<br>
+void intel_unpin_ringbuffer_obj(struct intel_ringbuffer *ringbuf);<br>
+int intel_pin_and_map_ringbuffer_obj(struct drm_device *dev,<br>
+                                    struct intel_ringbuffer *ringbuf);<br>
 void intel_destroy_ringbuffer_obj(struct intel_ringbuffer *ringbuf);<br>
 int intel_alloc_ringbuffer_obj(struct drm_device *dev,<br>
                               struct intel_ringbuffer *ringbuf);<br>
--<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>
</div></div></blockquote></div><br></div></div>