[PATCH 06/11] drm/i915/context: ringbuffer context switch code

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is the HW dependent context switch code.

Signed-off-by: Ben Widawsky <ben at bwidawsk.net>
---
 drivers/gpu/drm/i915/i915_drv.h         |    3 +
 drivers/gpu/drm/i915/intel_ringbuffer.c |  117 +++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_ringbuffer.h |    6 ++-
 3 files changed, 125 insertions(+), 1 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 34e6f4f..4175929 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -965,6 +965,9 @@ struct drm_i915_gem_context {
 	bool is_initialized;
 };
 
+#define I915_CONTEXT_NORMAL_SWITCH	(1 << 0)
+#define I915_CONTEXT_SAVE_ONLY		(1 << 1)
+#define I915_CONTEXT_FORCED_SWITCH	(1 << 2)
 #define INTEL_INFO(dev)	(((struct drm_i915_private *) (dev)->dev_private)->info)
 
 #define IS_I830(dev)		((dev)->pci_device == 0x3577)
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index e71e7fc..dcdc80e 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -942,6 +942,122 @@ render_ring_dispatch_execbuffer(struct intel_ring_buffer *ring,
 	return 0;
 }
 
+static int do_ring_switch(struct intel_ring_buffer *ring,
+			  struct drm_i915_gem_context *new_context,
+			  u32 hw_flags)
+{
+	struct drm_device *dev = ring->dev;
+	int ret = 0;
+
+	if (!new_context->is_initialized) {
+		ret = ring->flush(ring, 0, 0);
+		if (ret)
+			return ret;
+
+		ret = intel_ring_begin(ring, 2);
+		if (ret)
+			return ret;
+
+		intel_ring_emit(ring, MI_NOOP | (1 << 22) | new_context->id);
+		intel_ring_emit(ring, MI_NOOP);
+		intel_ring_advance(ring);
+	}
+
+	if (IS_GEN6(dev) && new_context->is_initialized &&
+	    ring->itlb_before_ctx_switch) {
+		/* w/a: If Flush TLB Invalidation Mode is enabled, driver must
+		 * do a TLB invalidation prior to MI_SET_CONTEXT
+		 */
+		gen6_render_ring_flush(ring, 0, 0);
+	}
+
+	ret = intel_ring_begin(ring, 6);
+	if (ret)
+		return ret;
+
+	intel_ring_emit(ring, MI_NOOP);
+
+	switch (INTEL_INFO(dev)->gen) {
+	case 5:
+		intel_ring_emit(ring, MI_SUSPEND_FLUSH | MI_SUSPEND_FLUSH_EN);
+		break;
+	case 6:
+		intel_ring_emit(ring, MI_NOOP);
+		break;
+	case 7:
+		intel_ring_emit(ring, MI_ARB_ON_OFF | MI_ARB_DISABLE);
+		break;
+	case 4:
+	default:
+		BUG();
+	}
+
+	DRM_DEBUG_DRIVER("Context switch %d-%d -> %d-%d\n",
+			 (ring->last_context && ring->last_context->file) ?
+				ring->last_context->file->pid : 0,
+			 ring->last_context ? ring->last_context->id : -1,
+			 new_context->file ? new_context->file->pid : 0,
+			 new_context->id);
+
+
+	intel_ring_emit(ring, MI_SET_CONTEXT);
+	intel_ring_emit(ring, new_context->obj->gtt_offset |
+			MI_MM_SPACE_GTT |
+			MI_SAVE_EXT_STATE_EN |
+			MI_RESTORE_EXT_STATE_EN |
+			hw_flags);
+
+	/* w/a: MI_SET_CONTEXT must always be followed by MI_NOOP */
+	intel_ring_emit(ring, MI_NOOP);
+
+	if (IS_GEN5(dev))
+		intel_ring_emit(ring, MI_SUSPEND_FLUSH);
+	else if (IS_GEN7(dev))
+		intel_ring_emit(ring, MI_ARB_ON_OFF | MI_ARB_ENABLE);
+	else
+		intel_ring_emit(ring, MI_NOOP);
+
+
+	intel_ring_advance(ring);
+
+	return ret;
+
+}
+
+static struct drm_i915_gem_context *
+render_ring_context_switch(struct intel_ring_buffer *ring,
+			   struct drm_i915_gem_context *new_context,
+			   u32 flags)
+{
+	struct drm_device *dev = ring->dev;
+	bool force = (flags & I915_CONTEXT_FORCED_SWITCH) ? true : false;
+	struct drm_i915_gem_context *last = NULL;
+	uint32_t hw_flags = 0;
+
+	/* last_context is only protected by struct_mutex */
+	WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+
+	BUG_ON(new_context->obj == NULL || new_context->obj->gtt_offset == 0);
+
+	if (!force && (ring->last_context == new_context))
+		return new_context;
+
+	if (flags & I915_CONTEXT_SAVE_ONLY)
+		hw_flags = MI_RESTORE_INHIBIT;
+
+	if (do_ring_switch(ring, new_context, hw_flags))
+		return NULL;
+
+	last = ring->last_context;
+	ring->last_context = new_context;
+
+	/* The first context switch with default context is special */
+	if (last == NULL && new_context->is_default)
+		return new_context;
+
+	return last;
+}
+
 static void cleanup_status_page(struct intel_ring_buffer *ring)
 {
 	drm_i915_private_t *dev_priv = ring->dev->dev_private;
@@ -1232,6 +1348,7 @@ static const struct intel_ring_buffer render_ring = {
 				   MI_SEMAPHORE_SYNC_RV,
 				   MI_SEMAPHORE_SYNC_RB},
 	.signal_mbox		= {GEN6_VRSYNC, GEN6_BRSYNC},
+	.context_switch		= render_ring_context_switch,
 };
 
 /* ring buffer for bit-stream decoder */
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index fad4251..1988728 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -69,10 +69,14 @@ struct  intel_ring_buffer {
 	int		(*dispatch_execbuffer)(struct intel_ring_buffer *ring,
 					       u32 offset, u32 length);
 	void		(*cleanup)(struct intel_ring_buffer *ring);
+	struct		drm_i915_gem_context *last_context;
+	struct		drm_i915_gem_context *(*context_switch) (
+					     struct intel_ring_buffer *ring,
+					     struct drm_i915_gem_context *ctx,
+					     u32 flags);
 	int		(*sync_to)(struct intel_ring_buffer *ring,
 				   struct intel_ring_buffer *to,
 				   u32 seqno);
-
 	u32		semaphore_register[3]; /*our mbox written by others */
 	u32		signal_mbox[2]; /* mboxes this ring signals to */
 	/**
-- 
1.7.9



[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]
  Powered by Linux