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