@@ -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,
@@ -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)
@@ -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;
@@ -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;