diff mbox

[39/50] drm/i915/bdw: Get prepared for a two-stage execlist submit process

Message ID 1399637360-4277-40-git-send-email-oscar.mateo@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

oscar.mateo@intel.com May 9, 2014, 12:09 p.m. UTC
From: Michel Thierry <michel.thierry@intel.com>

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@intel.com>

v2: Use a spinlock, do not remove the requests on unqueue (wait for
context switch completion).

Signed-off-by: Thomas Daniel <thomas.daniel@intel.com>

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@intel.com>
---
 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 mbox

Patch

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;