diff --git a/drivers/gpu/drm/i915/i915_context.c b/drivers/gpu/drm/i915/i915_context.c
index 3719a87..da4a0ff 100644
--- a/drivers/gpu/drm/i915/i915_context.c
+++ b/drivers/gpu/drm/i915/i915_context.c
@@ -33,6 +33,8 @@
 #define CONTEXT_SIZE dev_priv->context_size
 #define CONTEXT_ALIGN 4096
 
+static int context_idr_cleanup(int id, void *p, void *data);
+
 static int context_generate_id(struct drm_i915_gem_context *ctx)
 {
 	struct drm_i915_file_private *file_priv = ctx->file->driver_priv;
@@ -268,7 +270,50 @@ id_out:
 
 static void logical_context_fini(struct drm_i915_gem_context *ctx)
 {
+	struct drm_device *dev = ctx->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_i915_gem_context *last;
+	int i;
+	int ret = 0;
+
+	if (WARN_ON(!mutex_is_locked(&dev->struct_mutex)))
+		return;
+
+	if (ctx == dev_priv->default_context)
+		return;
+
+	for (i = 0; i < I915_NUM_RINGS; i++) {
+		struct intel_ring_buffer *ring = &dev_priv->ring[i];
+		if (!ring->context_switch)
+			continue;
+
+		if (!(ctx->ring_enable & (1 << i)))
+			continue;
+
+		if (ring->last_context != ctx)
+			continue;
 
+		/*
+		 * 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.
+		 */
+
+		DRM_DEBUG_DRIVER("Switching to default context\n");
+		last = ring->context_switch(ring, dev_priv->default_context,
+					    0, I915_CONTEXT_NORMAL_SWITCH);
+		if (!last) {
+			DRM_ERROR("Couldn't switch back to default context\n");
+			continue;
+		}
+
+		BUG_ON(last != ctx);
+		ret = wait_for_context_switch(ring);
+		if (ret)
+			DRM_ERROR("Wait for default context switch failed "
+				  "ring = %d (%d)", i, ret);
+		i915_release_context(last);
+	}
 }
 
 static int logical_context_free(struct drm_file *file, uint32_t id)
@@ -304,24 +349,40 @@ static int logical_context_free(struct drm_file *file, uint32_t id)
 }
 
 /**
- * i915_context_create_ioctl() - not yet supported
+ * i915_context_create_ioctl()
  */
 int i915_context_create_ioctl(struct drm_device *dev, void *data,
 			      struct drm_file *file)
 {
 	struct drm_i915_gem_context_create *args = data;
-	args->ctx_id = 0;
-	return -EIO;
+	struct drm_i915_gem_context *out_ctx = NULL;
+	int ret = 0;
+
+	mutex_lock(&dev->struct_mutex);
+	ret = logical_context_alloc(dev, file, args->ring_mask, &out_ctx);
+	mutex_unlock(&dev->struct_mutex);
+	if (ret == 0) {
+		args->ctx_id = out_ctx->id;
+		if (WARN_ON(args->ctx_id == DEFAULT_CONTEXT_ID))
+			return -ENXIO;
+		args->ring_enable = out_ctx->ring_enable;
+	}
+
+	return ret;
 }
 
 /**
- * i915_context_destroy_ioctl() - not yet supported
+ * i915_context_destroy_ioctl()
  */
 int i915_context_destroy_ioctl(struct drm_device *dev, void *data,
 			       struct drm_file *file)
 {
 	struct drm_i915_gem_context_destroy *args = data;
-	return -EINVAL;
+
+	if (args->ctx_id == DEFAULT_CONTEXT_ID)
+		return -EINVAL;
+
+	return logical_context_free(file, args->ctx_id);
 }
 
 /**
@@ -370,18 +431,55 @@ void i915_context_unload(struct drm_device *dev)
 
 void i915_context_open(struct drm_device *dev, struct drm_file *file)
 {
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_i915_file_private *file_priv = file->driver_priv;
+
+	if (dev_priv->contexts_disabled)
+		return;
 
+	idr_init(&file_priv->context_idr);
+	spin_lock_init(&file_priv->context_idr_lock);
 }
 
 void i915_context_close(struct drm_device *dev, struct drm_file *file)
 {
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_i915_file_private *file_priv = file->driver_priv;
+
+	if (dev_priv->contexts_disabled)
+		return;
 
+	idr_for_each(&file_priv->context_idr, context_idr_cleanup, file);
+	idr_destroy(&file_priv->context_idr);
+}
+
+static int context_idr_cleanup(int id, void *p, void *data)
+{
+	struct drm_file *file = (struct drm_file *) data;
+	logical_context_free(file, id);
+	return 0;
 }
 
 struct drm_i915_gem_context *i915_get_context(struct drm_file *file,
 					      uint32_t id)
 {
-	return NULL;
+	struct drm_i915_file_private *file_priv = file->driver_priv;
+	struct drm_i915_gem_context *ctx = NULL;
+	int ret;
+
+	spin_lock(&file_priv->context_idr_lock);
+	ctx = idr_find(&file_priv->context_idr, id);
+	if (ctx) {
+		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);
+			ctx = NULL;
+		}
+	}
+	spin_unlock(&file_priv->context_idr_lock);
+
+	return ctx;
 }
 
 void i915_release_context(struct drm_i915_gem_context *ctx)
