diff mbox

[RFC,6/8] drm/i915/context: context init implementation

Message ID 1298745018-5937-7-git-send-email-bwidawsk@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Ben Widawsky Feb. 26, 2011, 6:30 p.m. UTC
None
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/i915_context.c b/drivers/gpu/drm/i915/i915_context.c
index 45b5181..2e38fa8 100644
--- a/drivers/gpu/drm/i915/i915_context.c
+++ b/drivers/gpu/drm/i915/i915_context.c
@@ -99,13 +99,70 @@  static int context_init(struct drm_i915_gem_context *ctx,
 			bool wait_for_switch)
 {
 	struct drm_i915_private *dev_priv = ctx->dev->dev_private;
-	struct drm_i915_gem_context *last;
+	struct drm_i915_gem_context *last = NULL;
 	int ret;
 
 	if (ring->context_switch == NULL)
 		return 0;
 
-	return -ENOMEM;
+	drm_gem_object_reference(&ctx->obj->base);
+	ret = i915_gem_object_pin(ctx->obj, CONTEXT_ALIGN, false);
+	if (ret) {
+		drm_gem_object_unreference(&ctx->obj->base);
+		return ret;
+	}
+
+	if (ctx->is_default) {
+		/*
+		 * XXX default context is always first. The first context needs
+		 * to do an extra save because the first save (according to the
+		 * spec) doesn't actually do anything. So the outcome is
+		 * 1. Save without restore (no context saved)
+		 * 2. Save without restore (context is saved)
+		 * 3. Save with restore (loads the ctx from step 2)
+		 */
+		last = ring->context_switch(ring, ctx, 0,
+					    I915_CONTEXT_SAVE_ONLY);
+		if (!last) {
+			ret = EIO;
+			goto err_out;
+		}
+		last = ring->context_switch(ring, ctx, 0,
+					    I915_CONTEXT_SAVE_ONLY |
+					    I915_CONTEXT_FORCED_SWITCH);
+		if (!last) {
+			ret = EIO;
+			goto err_out;
+		}
+		last = ring->context_switch(ring, ctx, 0,
+					    I915_CONTEXT_NORMAL_SWITCH |
+					    I915_CONTEXT_FORCED_SWITCH);
+	} else {
+		last = ring->context_switch(ring, ctx, 0,
+					    I915_CONTEXT_SAVE_ONLY);
+	}
+
+	if (!last) {
+		ret = EIO;
+		goto err_out;
+	}
+
+	if (!last->is_default)
+		i915_release_context(last);
+
+	if (wait_for_switch) {
+		ret = wait_for_context_switch(ring);
+		if (ret)
+			goto err_out;
+	}
+
+	return 0;
+
+err_out:
+	WARN_ON(ctx->is_default);
+	i915_gem_object_unpin(ctx->obj);
+	drm_gem_object_unreference(&ctx->obj->base);
+	return ret;
 }
 
 /*
@@ -316,3 +373,9 @@  struct drm_i915_gem_context *i915_get_context(struct drm_file *file,
 {
 	return NULL;
 }
+
+void i915_release_context(struct drm_i915_gem_context *ctx)
+{
+	i915_gem_object_unpin(ctx->obj);
+	drm_gem_object_unreference(&ctx->obj->base);
+}
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 15f86fb..98ccbd9 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -914,6 +914,10 @@  struct drm_i915_gem_context {
 	int slot_count;
 };
 
+#define I915_CONTEXT_NORMAL_SWITCH	(1 << 0)
+#define I915_CONTEXT_SAVE_ONLY		(1 << 1)
+#define I915_CONTEXT_FORCED_SWITCH	(1 << 2)
+
 enum intel_chip_family {
 	CHIP_I8XX = 0x01,
 	CHIP_I9XX = 0x02,
@@ -1157,6 +1161,7 @@  extern void i915_context_open(struct drm_device *dev, struct drm_file *file);
 extern void i915_context_close(struct drm_device *dev, struct drm_file *file);
 extern struct drm_i915_gem_context *i915_get_context(struct drm_file *file,
 						     uint32_t id);
+extern void i915_release_context(struct drm_i915_gem_context *ctx);
 
 /**
  * Returns true if seq1 is later than seq2.