@@ -81,7 +81,7 @@ i915_context_validate(struct drm_device *dev, struct drm_file *file,
struct drm_gem_object *obj;
struct drm_i915_gem_object *obj_priv;
struct drm_i915_gem_context *ctx;
- int i, ret = 0;
+ int i;
ctx = i915_context_lookup_id(dev, ctx_id);
if (ctx == NULL) {
@@ -265,17 +265,28 @@ static int i915_context_hw_fini(struct drm_device *dev,
struct drm_i915_gem_context *ctx,
struct intel_ring_buffer *ring)
{
+ int ret;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
/* XXX We can prevent restoring contexts, but not saving them
* so if we're going to take away our backing context object
* of the last context, we have to switch now.
*/
- struct drm_i915_private *dev_priv = dev->dev_private;
+ mutex_lock(&dev->struct_mutex);
if (ring->last_context == ctx && ctx != dev_priv->default_context) {
- mutex_lock(&dev->struct_mutex);
- ring->context_switch(ring, dev_priv->default_context,
- I915_CONTEXT_NORMAL_SWITCH);
- mutex_unlock(&dev->struct_mutex);
+ DRM_DEBUG_DRIVER("Switching to default context\n");
+ ret = ring->context_switch(ring, dev_priv->default_context,
+ I915_CONTEXT_NORMAL_SWITCH);
+ if (ret) {
+ DRM_ERROR("Couldn't switch back to default context\n");
+ goto out;
+ }
+ ring->last_context = dev_priv->default_context;
}
+
+out:
+ mutex_unlock(&dev->struct_mutex);
+ return ret;
}
static int
@@ -428,7 +439,8 @@ void i915_context_init(struct drm_device *dev)
dev_priv->ctx_disable = 1;
idr_destroy(&dev_priv->i915_ctx_idr);
} else {
- DRM_DEBUG_DRIVER("Context support enabled\n", ret);
+ DRM_DEBUG_DRIVER("Default context = %p\n",
+ to_intel_bo(dev_priv->default_context->ctx_obj)->gtt_offset);
}
}
@@ -990,7 +990,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
struct drm_i915_gem_object *batch_obj;
struct drm_clip_rect *cliprects = NULL;
struct intel_ring_buffer *ring;
- struct drm_i915_gem_context *ctx;
+ struct drm_i915_gem_context *ctx = NULL;
u32 exec_start, exec_len;
u32 seqno;
u32 ctx_id;
@@ -1013,7 +1013,9 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
DRM_DEBUG_DRIVER("Context resubmission required\n");
return -EIO;
}
- }
+ } else
+ ctx = dev_priv->default_context;
+
#if WATCH_EXEC
DRM_INFO("buffers_ptr %d buffer_count %d len %08x\n",
(int) args->buffers_ptr, args->buffer_count, args->batch_len);
@@ -1203,8 +1205,11 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
}
}
- if (!dev_priv->ctx_disable)
- ring->context_switch(ring, ctx, I915_CONTEXT_NORMAL_SWITCH);
+ if (!dev_priv->ctx_disable) {
+ ret = ring->context_switch(ring, ctx, I915_CONTEXT_NORMAL_SWITCH);
+ if (ret)
+ goto err;
+ }
exec_start = batch_obj->gtt_offset + args->batch_start_offset;
exec_len = args->batch_len;
@@ -750,15 +750,55 @@ render_ring_dispatch_execbuffer(struct intel_ring_buffer *ring,
return 0;
}
-static void
+static int
render_ring_ctx_switch(struct intel_ring_buffer *ring,
struct drm_i915_gem_context *ctx,
- uint32_t flags)
+ u32 flags)
{
+ struct drm_device *dev = ring->dev;
+ struct drm_gem_object *obj;
+ uint32_t ctx_switch_flags;
+ int ret = 0;
+
if (ring->last_context == ctx)
- return;
+ return 0;
+
+ DRM_DEBUG_DRIVER("Context switch to %d\n",
+ ctx->ctx_id);
ring->last_context = ctx;
+ obj = ctx->ctx_obj;
+
+ if (flags == I915_CONTEXT_SAVE_ONLY)
+ ctx_switch_flags = MI_RESTORE_INHIBIT;
+ else
+ ctx_switch_flags = 0;
+
+ ret = intel_ring_begin(ring, 4);
+ if (ret)
+ return ret;
+
+ if (IS_IRONLAKE_D(dev) || IS_IRONLAKE_M(dev))
+ intel_ring_emit(ring, MI_SUSPEND_FLUSH | MI_SUSPEND_FLUSH_EN);
+ else
+ intel_ring_emit(ring, MI_NOOP);
+
+ intel_ring_emit(ring, MI_SET_CONTEXT);
+ intel_ring_emit(ring, to_intel_bo(obj)->gtt_offset |
+ MI_MM_SPACE_GTT |
+ MI_SAVE_EXT_STATE_EN |
+ MI_RESTORE_EXT_STATE_EN |
+ ctx_switch_flags);
+
+ if (IS_IRONLAKE_D(dev) || IS_IRONLAKE_M(dev))
+ intel_ring_emit(ring, MI_SUSPEND_FLUSH);
+ /* TODO: we may need a NOOP here */
+ else
+ intel_ring_emit(ring, MI_NOOP);
+
+ intel_ring_advance(ring);
+
+ return 0;
}
static void cleanup_status_page(struct intel_ring_buffer *ring)
@@ -80,7 +80,7 @@ struct intel_ring_buffer {
u32 offset, u32 length);
void (*cleanup)(struct intel_ring_buffer *ring);
struct drm_i915_gem_context *last_context;
- void (*context_switch)(struct intel_ring_buffer *ring,
+ int (*context_switch)(struct intel_ring_buffer *ring,
struct drm_i915_gem_context *ctx,
u32 flags);