<div dir="ltr"><div>Reviewed the patch & it looks fine.</div><div>Reviewed-by: "Akash Goel <<a href="mailto:akash.goels@gmail.com">akash.goels@gmail.com</a>>"</div></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="">From: Oscar Mateo <<a href="mailto:oscar.mateo@intel.com">oscar.mateo@intel.com</a>><br>
<br>
Up until now, we have pinned every logical ring context backing object<br>
during creation, and left it pinned until destruction. This made my life<br>
easier, but it's a harmful thing to do, because we cause fragmentation<br>
of the GGTT (and, eventually, we would run out of space).<br>
<br>
This patch makes the pinning on-demand: the backing objects of the two<br>
contexts that are written to the ELSP are pinned right before submission<br>
and unpinned once the hardware is done with them. The only context that<br>
is still pinned regardless is the global default one, so that the HWS can<br>
still be accessed in the same way (ring->status_page).<br>
<br>
v2: In the early version of this patch, we were pinning the context as<br>
we put it into the ELSP: on the one hand, this is very efficient because<br>
only a maximum two contexts are pinned at any given time, but on the other<br>
hand, we cannot really pin in interrupt time :(<br>
<br>
v3: Use a mutex rather than atomic_t to protect pin count to avoid races.<br>
Do not unpin default context in free_request.<br>
<br>
v4: Break out pin and unpin into functions.  Fix style problems reported<br>
by checkpatch<br>
<br>
</span>v5: Remove unpin_lock as all pinning and unpinning is done with the struct<br>
mutex already locked.  Add WARN_ONs to make sure this is the case in future.<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>
 drivers/gpu/drm/i915/i915_debugfs.c |   12 +++++-<br>
</span> drivers/gpu/drm/i915/i915_drv.h     |    1 +<br>
 drivers/gpu/drm/i915/i915_gem.c     |   39 +++++++++++++-------<br>
 drivers/gpu/drm/i915/intel_lrc.c    |   69 +++++++++++++++++++++++++++++------<br>
 drivers/gpu/drm/i915/intel_lrc.h    |    4 ++<br>
 5 files changed, 98 insertions(+), 27 deletions(-)<br>
<div><div class="h5"><br>
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c<br>
index e60d5c2..6eaf813 100644<br>
--- a/drivers/gpu/drm/i915/i915_debugfs.c<br>
+++ b/drivers/gpu/drm/i915/i915_debugfs.c<br>
@@ -1799,10 +1799,16 @@ static int i915_dump_lrc(struct seq_file *m, void *unused)<br>
                                continue;<br>
<br>
                        if (ctx_obj) {<br>
-                               struct page *page = i915_gem_object_get_page(ctx_obj, 1);<br>
-                               uint32_t *reg_state = kmap_atomic(page);<br>
+                               struct page *page;<br>
+                               uint32_t *reg_state;<br>
                                int j;<br>
<br>
+                               i915_gem_obj_ggtt_pin(ctx_obj,<br>
+                                               GEN8_LR_CONTEXT_ALIGN, 0);<br>
+<br>
+                               page = i915_gem_object_get_page(ctx_obj, 1);<br>
+                               reg_state = kmap_atomic(page);<br>
+<br>
                                seq_printf(m, "CONTEXT: %s %u\n", ring->name,<br>
                                                intel_execlists_ctx_id(ctx_obj));<br>
<br>
@@ -1814,6 +1820,8 @@ static int i915_dump_lrc(struct seq_file *m, void *unused)<br>
                                }<br>
                                kunmap_atomic(reg_state);<br>
<br>
+                               i915_gem_object_ggtt_unpin(ctx_obj);<br>
+<br>
                                seq_putc(m, '\n');<br>
                        }<br>
                }<br>
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h<br>
</div></div>index 059330c..3c7299d 100644<br>
--- a/drivers/gpu/drm/i915/i915_drv.h<br>
+++ b/drivers/gpu/drm/i915/i915_drv.h<br>
@@ -655,6 +655,7 @@ struct intel_context {<br>
<span class="">        struct {<br>
                struct drm_i915_gem_object *state;<br>
                struct intel_ringbuffer *ringbuf;<br>
+               int unpin_count;<br>
</span><span class="">        } engine[I915_NUM_RINGS];<br>
<br>
        struct list_head link;<br>
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c<br>
</span>index 408afe7..2ee6996 100644<br>
<div><div class="h5">--- a/drivers/gpu/drm/i915/i915_gem.c<br>
+++ b/drivers/gpu/drm/i915/i915_gem.c<br>
@@ -2494,12 +2494,18 @@ static void i915_set_reset_status(struct drm_i915_private *dev_priv,<br>
<br>
 static void i915_gem_free_request(struct drm_i915_gem_request *request)<br>
 {<br>
+       struct intel_context *ctx = request->ctx;<br>
+<br>
        list_del(&request->list);<br>
        i915_gem_request_remove_from_client(request);<br>
<br>
-       if (request->ctx)<br>
-               i915_gem_context_unreference(request->ctx);<br>
+       if (i915.enable_execlists && ctx) {<br>
+               struct intel_engine_cs *ring = request->ring;<br>
<br>
+               if (ctx != ring->default_context)<br>
+                       intel_lr_context_unpin(ring, ctx);<br>
+               i915_gem_context_unreference(ctx);<br>
+       }<br>
        kfree(request);<br>
 }<br>
<br>
@@ -2554,6 +2560,23 @@ static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv,<br>
        }<br>
<br>
        /*<br>
+        * Clear the execlists queue up before freeing the requests, as those<br>
+        * are the ones that keep the context and ringbuffer backing objects<br>
+        * pinned in place.<br>
+        */<br>
+       while (!list_empty(&ring->execlist_queue)) {<br>
+               struct intel_ctx_submit_request *submit_req;<br>
+<br>
+               submit_req = list_first_entry(&ring->execlist_queue,<br>
+                               struct intel_ctx_submit_request,<br>
+                               execlist_link);<br>
+               list_del(&submit_req->execlist_link);<br>
+               intel_runtime_pm_put(dev_priv);<br>
+               i915_gem_context_unreference(submit_req->ctx);<br>
+               kfree(submit_req);<br>
+       }<br>
+<br>
+       /*<br>
         * We must free the requests after all the corresponding objects have<br>
         * been moved off active lists. Which is the same order as the normal<br>
         * retire_requests function does. This is important if object hold<br>
@@ -2570,18 +2593,6 @@ static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv,<br>
                i915_gem_free_request(request);<br>
        }<br>
<br>
-       while (!list_empty(&ring->execlist_queue)) {<br>
-               struct intel_ctx_submit_request *submit_req;<br>
-<br>
-               submit_req = list_first_entry(&ring->execlist_queue,<br>
-                               struct intel_ctx_submit_request,<br>
-                               execlist_link);<br>
-               list_del(&submit_req->execlist_link);<br>
-               intel_runtime_pm_put(dev_priv);<br>
-               i915_gem_context_unreference(submit_req->ctx);<br>
-               kfree(submit_req);<br>
-       }<br>
-<br>
        /* These may not have been flush before the reset, do so now */<br>
        kfree(ring->preallocated_lazy_request);<br>
        ring->preallocated_lazy_request = NULL;<br>
diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c<br>
</div></div>index 906b985..f7fa0f7 100644<br>
<span class="">--- a/drivers/gpu/drm/i915/intel_lrc.c<br>
+++ b/drivers/gpu/drm/i915/intel_lrc.c<br>
@@ -139,8 +139,6 @@<br>
 #define GEN8_LR_CONTEXT_RENDER_SIZE (20 * PAGE_SIZE)<br>
 #define GEN8_LR_CONTEXT_OTHER_SIZE (2 * PAGE_SIZE)<br>
<br>
-#define GEN8_LR_CONTEXT_ALIGN 4096<br>
-<br>
 #define RING_EXECLIST_QFULL            (1 << 0x2)<br>
 #define RING_EXECLIST1_VALID           (1 << 0x3)<br>
 #define RING_EXECLIST0_VALID           (1 << 0x4)<br>
</span>@@ -801,9 +799,40 @@ void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf)<br>
<span class="">        execlists_context_queue(ring, ctx, ringbuf->tail);<br>
 }<br>
<br>
+static int intel_lr_context_pin(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>
+       int ret = 0;<br>
+<br>
</span>+       WARN_ON(!mutex_is_locked(&ring->dev->struct_mutex));<br>
<span class="">+       if (ctx->engine[ring->id].unpin_count++ == 0) {<br>
+               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>
+       }<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>
+<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>
+                       i915_gem_object_ggtt_unpin(ctx_obj);<br>
+       }<br>
</span><span class="">+}<br>
+<br>
 static int logical_ring_alloc_seqno(struct intel_engine_cs *ring,<br>
                                    struct intel_context *ctx)<br>
 {<br>
+       int ret;<br>
+<br>
        if (ring->outstanding_lazy_seqno)<br>
                return 0;<br>
<br>
</span>@@ -814,6 +843,14 @@ static int logical_ring_alloc_seqno(struct intel_engine_cs *ring,<br>
<span class="">                if (request == NULL)<br>
                        return -ENOMEM;<br>
<br>
+               if (ctx != ring->default_context) {<br>
+                       ret = intel_lr_context_pin(ring, ctx);<br>
+                       if (ret) {<br>
+                               kfree(request);<br>
+                               return ret;<br>
+                       }<br>
+               }<br>
+<br>
                /* Hold a reference to the context this request belongs to<br>
                 * (we will need it when the time comes to emit/retire the<br>
                 * request).<br>
</span>@@ -1626,12 +1663,16 @@ void intel_lr_context_free(struct intel_context *ctx)<br>
<span class=""><br>
        for (i = 0; i < I915_NUM_RINGS; i++) {<br>
                struct drm_i915_gem_object *ctx_obj = ctx->engine[i].state;<br>
-               struct intel_ringbuffer *ringbuf = ctx->engine[i].ringbuf;<br>
<br>
                if (ctx_obj) {<br>
+                       struct intel_ringbuffer *ringbuf =<br>
+                                       ctx->engine[i].ringbuf;<br>
+                       struct intel_engine_cs *ring = ringbuf->ring;<br>
+<br>
                        intel_destroy_ringbuffer_obj(ringbuf);<br>
                        kfree(ringbuf);<br>
-                       i915_gem_object_ggtt_unpin(ctx_obj);<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>@@ -1695,6 +1736,7 @@ static int lrc_setup_hardware_status_page(struct intel_engine_cs *ring,<br>
<span class=""> int intel_lr_context_deferred_create(struct intel_context *ctx,<br>
                                     struct intel_engine_cs *ring)<br>
 {<br>
+       const bool is_global_default_ctx = (ctx == ring->default_context);<br>
        struct drm_device *dev = ring->dev;<br>
        struct drm_i915_gem_object *ctx_obj;<br>
        uint32_t context_size;<br>
</span>@@ -1714,18 +1756,22 @@ int intel_lr_context_deferred_create(struct intel_context *ctx,<br>
<span class="">                return ret;<br>
        }<br>
<br>
-       ret = i915_gem_obj_ggtt_pin(ctx_obj, GEN8_LR_CONTEXT_ALIGN, 0);<br>
-       if (ret) {<br>
-               DRM_DEBUG_DRIVER("Pin LRC backing obj failed: %d\n", ret);<br>
-               drm_gem_object_unreference(&ctx_obj->base);<br>
-               return ret;<br>
+       if (is_global_default_ctx) {<br>
+               ret = i915_gem_obj_ggtt_pin(ctx_obj, GEN8_LR_CONTEXT_ALIGN, 0);<br>
+               if (ret) {<br>
+                       DRM_DEBUG_DRIVER("Pin LRC backing obj failed: %d\n",<br>
+                                       ret);<br>
+                       drm_gem_object_unreference(&ctx_obj->base);<br>
+                       return ret;<br>
+               }<br>
        }<br>
<br>
        ringbuf = kzalloc(sizeof(*ringbuf), GFP_KERNEL);<br>
        if (!ringbuf) {<br>
                DRM_DEBUG_DRIVER("Failed to allocate ringbuffer %s\n",<br>
                                ring->name);<br>
-               i915_gem_object_ggtt_unpin(ctx_obj);<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>
</span>@@ -1787,7 +1833,8 @@ int intel_lr_context_deferred_create(struct intel_context *ctx,<br>
<div class="HOEnZb"><div class="h5"><br>
 error:<br>
        kfree(ringbuf);<br>
-       i915_gem_object_ggtt_unpin(ctx_obj);<br>
+       if (is_global_default_ctx)<br>
+               i915_gem_object_ggtt_unpin(ctx_obj);<br>
        drm_gem_object_unreference(&ctx_obj->base);<br>
        return ret;<br>
 }<br>
diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h<br>
index 84bbf19..14b216b 100644<br>
--- a/drivers/gpu/drm/i915/intel_lrc.h<br>
+++ b/drivers/gpu/drm/i915/intel_lrc.h<br>
@@ -24,6 +24,8 @@<br>
 #ifndef _INTEL_LRC_H_<br>
 #define _INTEL_LRC_H_<br>
<br>
+#define GEN8_LR_CONTEXT_ALIGN 4096<br>
+<br>
 /* Execlists regs */<br>
 #define RING_ELSP(ring)                        ((ring)->mmio_base+0x230)<br>
 #define RING_EXECLIST_STATUS(ring)     ((ring)->mmio_base+0x234)<br>
@@ -67,6 +69,8 @@ int intel_lr_context_render_state_init(struct intel_engine_cs *ring,<br>
 void intel_lr_context_free(struct intel_context *ctx);<br>
 int intel_lr_context_deferred_create(struct intel_context *ctx,<br>
                                     struct intel_engine_cs *ring);<br>
+void intel_lr_context_unpin(struct intel_engine_cs *ring,<br>
+               struct intel_context *ctx);<br>
<br>
 /* Execlists */<br>
 int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists);<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>