From: Michel Thierry <michel.thierry@xxxxxxxxx> Context switch (and execlist submission) should happen only when other contexts are not active, otherwise pre-emption occurs. To assure this, we place context switch requests in a queue and those request are later consumed when the right context switch interrupt is received. Signed-off-by: Michel Thierry <michel.thierry@xxxxxxxxx> v2: Use a spinlock, do not remove the requests on unqueue (wait for context switch completion). Signed-off-by: Thomas Daniel <thomas.daniel@xxxxxxxxx> v3: Several rebases and code changes. Use unique ID. v4: - Move the queue/lock init to the late ring initialization. - Damien's kmalloc review comments: check return, use sizeof(*req), do not cast. Signed-off-by: Oscar Mateo <oscar.mateo@xxxxxxxxx> --- drivers/gpu/drm/i915/i915_drv.h | 6 ++++ drivers/gpu/drm/i915/intel_lrc.c | 57 +++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_ringbuffer.c | 3 ++ drivers/gpu/drm/i915/intel_ringbuffer.h | 3 ++ 4 files changed, 69 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6b39fed..f2aae6a 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1745,6 +1745,9 @@ struct drm_i915_gem_request { struct drm_i915_file_private *file_priv; /** file_priv list entry for this request */ struct list_head client_list; + + /** execlist queue entry for this request */ + struct list_head execlist_link; }; struct drm_i915_file_private { @@ -2443,6 +2446,9 @@ static inline u32 intel_get_lr_contextid(struct drm_i915_gem_object *ctx_obj) * (which leaves one HwCtxId bit free) */ return lrca >> 13; } +int gen8_switch_context_queue(struct intel_engine *ring, + struct i915_hw_context *to, + u32 tail); /* i915_gem_evict.c */ int __must_check i915_gem_evict_something(struct drm_device *dev, diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index b06098e..6da7db9 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -199,6 +199,63 @@ static int gen8_switch_context(struct intel_engine *ring, return 0; } +static void gen8_switch_context_unqueue(struct intel_engine *ring) +{ + struct drm_i915_gem_request *req0 = NULL, *req1 = NULL; + struct drm_i915_gem_request *cursor = NULL, *tmp = NULL; + + if (list_empty(&ring->execlist_queue)) + return; + + /* Try to read in pairs */ + list_for_each_entry_safe(cursor, tmp, &ring->execlist_queue, execlist_link) { + if (!req0) + req0 = cursor; + else if (req0->ctx == cursor->ctx) { + /* Same ctx: ignore first request, as second request + * will update tail past first request's workload */ + list_del(&req0->execlist_link); + i915_gem_context_unreference(req0->ctx); + kfree(req0); + req0 = cursor; + } else { + req1 = cursor; + break; + } + } + + BUG_ON(gen8_switch_context(ring, req0->ctx, req0->tail, + req1? req1->ctx : NULL, req1? req1->tail : 0)); +} + +int gen8_switch_context_queue(struct intel_engine *ring, + struct i915_hw_context *to, + u32 tail) +{ + struct drm_i915_gem_request *req = NULL; + unsigned long flags; + bool was_empty; + + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (req == NULL) + return -ENOMEM; + req->ring = ring; + req->ctx = to; + i915_gem_context_reference(req->ctx); + req->tail = tail; + + spin_lock_irqsave(&ring->execlist_lock, flags); + + was_empty = list_empty(&ring->execlist_queue); + list_add_tail(&req->execlist_link, &ring->execlist_queue); + if (was_empty) + gen8_switch_context_unqueue(ring); + + spin_unlock_irqrestore(&ring->execlist_lock, flags); + + return 0; +} + struct i915_hw_context * gen8_gem_validate_context(struct drm_device *dev, struct drm_file *file, struct intel_engine *ring, const u32 ctx_id) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 847fec5..35ced7c 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1554,6 +1554,9 @@ static int intel_init_ring(struct drm_device *dev, init_waitqueue_head(&ring->irq_queue); + INIT_LIST_HEAD(&ring->execlist_queue); + spin_lock_init(&ring->execlist_lock); + if (dev_priv->lrc_enabled) { struct drm_i915_gem_object *obj; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 709b1f1..daf91de 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -176,6 +176,9 @@ struct intel_engine { wait_queue_head_t irq_queue; + spinlock_t execlist_lock; + struct list_head execlist_queue; + struct i915_hw_context *default_context; struct i915_hw_context *last_context; -- 1.9.0 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/intel-gfx