<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>