This is the HW dependent context switch code.

Signed-off-by: Ben Widawsky <b...@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

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to