diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index b868084..19b463a 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -50,7 +50,8 @@
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
 #include <linux/oom.h>
-
+#include <linux/dma-buf.h>
+#include "../../../staging/android/sync.h"
 
 static int i915_getparam(struct drm_device *dev, void *data,
 			 struct drm_file *file_priv)
@@ -1247,6 +1248,132 @@ i915_gem_reject_pin_ioctl(struct drm_device *dev, void *data,
 	return -ENODEV;
 }
 
+int intel_exec_mm_ioctl(struct drm_device *dev, void *data,
+			struct drm_file *file)
+{
+ 	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_i915_exec_mm *exec_mm = data;
+	struct intel_ringbuffer *ringbuf;
+	struct intel_engine_cs *ring;
+	struct intel_context *ctx;
+	struct drm_i915_gem_request *request;
+	struct fence *fence;
+	struct sync_fence *sfence;
+	u32 ctx_id = exec_mm->ctx_id;
+	int fd = get_unused_fd_flags(O_CLOEXEC);
+	int ret = 0;
+
+	if (exec_mm->batch_ptr & 3) {
+		DRM_ERROR("misaligned batch ptr\n");
+		ret = -ENOEXEC;
+		goto out;
+	}
+
+	if (!dev_priv->svm.svm_available) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	ret = i915_mutex_lock_interruptible(dev);
+	if (ret) {
+		DRM_ERROR("mutex interrupted\n");
+		goto out;
+	}
+
+	if (file == NULL) {
+		ret = -EINVAL;
+		goto out_unlock;
+	}
+
+	ctx = i915_gem_validate_context(dev, file, &dev_priv->ring[RCS],
+					ctx_id);
+	if (ctx == NULL) {
+		ret = -ENOENT;
+		DRM_ERROR("couldn't get context\n");
+		goto out_unlock;
+	}
+
+	if (!ctx->is_svm) {
+		ret = -EINVAL;
+		DRM_ERROR("context is not SVM enabled\n");
+		goto out_unlock;
+	}
+
+	i915_gem_context_reference(ctx);
+
+	ringbuf = ctx->engine[RCS].ringbuf;
+	ring = ringbuf->ring;
+	if (!ring) {
+		DRM_ERROR("context has no last ring\n");
+		ret = -EIO;
+		goto out_unref;
+	}
+
+	if (!ctx->rcs_initialized) {
+		DRM_DEBUG("ring not ready\n");
+		ret = -EIO;
+		goto out_unref;
+	}
+
+	ret = i915_gem_request_alloc(ring, ctx, &request);
+	if (ret) {
+		DRM_ERROR("request alloc failed\n");
+		goto out_unref;
+	}
+
+	ret = i915_gem_request_add_to_client(request, file);
+	if (ret) {
+		DRM_ERROR("failed to add request to client\n");
+		goto out_free_req;
+	}
+
+	fence = i915_fence_create_ring(ring, ctx);
+	if (!fence) {
+		ret = -ENOMEM;
+		DRM_ERROR("fence creation failed\n");
+		goto out_free_req;
+	}
+
+	sfence = sync_fence_create_dma("svm-execbuf", fence);
+	if (!sfence) {
+		ret = -ENOMEM;
+		DRM_ERROR("sfence creation failed\n");
+		goto out_free_req;
+	}
+
+	exec_mm->fence = fd;
+	sync_fence_install(sfence, fd);
+
+	ret = ring->emit_flush(request, 0, I915_GEM_GPU_DOMAINS);
+	if (ret) {
+		DRM_ERROR("ring flush failed: %d\n", ret);
+		goto out_free_req;
+	}
+
+	ret = ring->emit_bb_start(request, exec_mm->batch_ptr, 0);
+	if (ret) {
+		DRM_ERROR("ring dispatch execbuf failed: %d\n", ret);
+		goto out_free_req;
+	}
+
+	i915_gem_context_unreference(ctx);
+	mutex_unlock(&dev->struct_mutex);
+
+	return 0;
+
+out_free_req:
+	i915_gem_request_cancel(request);
+
+out_unref:
+	i915_gem_context_unreference(ctx);
+out_unlock:
+	mutex_unlock(&dev->struct_mutex);
+	put_unused_fd(fd);
+
+out:
+	return ret;
+}
+
 const struct drm_ioctl_desc i915_ioctls[] = {
 	DRM_IOCTL_DEF_DRV(I915_INIT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
 	DRM_IOCTL_DEF_DRV(I915_FLUSH, drm_noop, DRM_AUTH),
@@ -1301,6 +1428,17 @@ const struct drm_ioctl_desc i915_ioctls[] = {
 	DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_GETPARAM, i915_gem_context_getparam_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
 	DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_SETPARAM, i915_gem_context_setparam_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
 	DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_CREATE2, i915_gem_context_create2_ioctl, DRM_UNLOCKED),
+	DRM_IOCTL_DEF_DRV(I915_EXEC_MM, intel_exec_mm_ioctl, DRM_UNLOCKED),
 };
 
 int i915_max_ioctl = ARRAY_SIZE(i915_ioctls);
+
+/*
+ * This is really ugly: Because old userspace abused the linux agp interface to
+ * manage the gtt, we need to claim that all intel devices are agp.  For
+ * otherwise the drm core refuses to initialize the agp support code.
+ */
+int i915_driver_device_is_agp(struct drm_device *dev)
+{
+	return 1;
+}
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 0c3047b..d89955c 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2860,6 +2860,8 @@ void i915_gem_vma_destroy(struct i915_vma *vma);
 #ifdef CONFIG_DRM_I915_SYNC
 int i915_sync_init(struct drm_i915_private *dev_priv);
 void i915_sync_fini(struct drm_i915_private *dev_priv);
+struct fence *i915_fence_create_ring(struct intel_engine_cs *ring,
+				     struct intel_context *ctx);
 int i915_sync_create_fence_ioctl(struct drm_device *dev, void *data,
 				 struct drm_file *file);
 #else
@@ -3178,6 +3180,9 @@ i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id);
 void i915_gem_context_free(struct kref *ctx_ref);
 struct drm_i915_gem_object *
 i915_gem_alloc_context_obj(struct drm_device *dev, size_t size);
+struct intel_context *
+i915_gem_validate_context(struct drm_device *dev, struct drm_file *file,
+			  struct intel_engine_cs *ring, const u32 ctx_id);
 static inline void i915_gem_context_reference(struct intel_context *ctx)
 {
 	kref_get(&ctx->ref);
@@ -3402,6 +3407,8 @@ int i915_get_reset_stats_ioctl(struct drm_device *dev, void *data,
 extern struct intel_mm_struct *intel_bind_mm(struct drm_device *dev,
 					     struct intel_context *ctx);
 extern void intel_unbind_mm(struct intel_context *ctx);
+extern int intel_exec_mm_ioctl(struct drm_device *dev, void *data,
+			       struct drm_file *file);
 extern int intel_alloc_pasid(struct drm_device *dev,
 			     struct intel_context *ctx);
 extern void intel_free_pasid(struct drm_device *dev,
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index a953d49..b1f8819 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -988,7 +988,7 @@ validate_exec_list(struct drm_device *dev,
 	return 0;
 }
 
-static struct intel_context *
+struct intel_context *
 i915_gem_validate_context(struct drm_device *dev, struct drm_file *file,
 			  struct intel_engine_cs *ring, const u32 ctx_id)
 {
diff --git a/drivers/gpu/drm/i915/i915_svm.c b/drivers/gpu/drm/i915/i915_svm.c
index 1d05318..fdb45d6 100644
--- a/drivers/gpu/drm/i915/i915_svm.c
+++ b/drivers/gpu/drm/i915/i915_svm.c
@@ -757,16 +757,6 @@ void intel_unbind_mm(struct intel_context *ctx)
 	return;
 }
 
-int intel_exec_mm_ioctl(struct drm_device *dev, void *data,
-			struct drm_file *file)
-{
-//	struct drm_i915_exec_mm *exec_mm = data;
-//	struct drm_i915_private *dev_priv = dev->dev_private;
-
-	/* Load new context into context reg */
-	return 0;
-}
-
 /*
  * The PASID table has 32 entries in the current config, rotate through
  * them as needed.
diff --git a/drivers/gpu/drm/i915/i915_sync.c b/drivers/gpu/drm/i915/i915_sync.c
index 46cea44..085f1f9 100644
--- a/drivers/gpu/drm/i915/i915_sync.c
+++ b/drivers/gpu/drm/i915/i915_sync.c
@@ -187,8 +187,8 @@ static struct fence_ops i915_fence_ring_ops = {
 	.timeline_value_str =	i915_fence_ring_timeline_value_str,
 };
 
-static struct fence *i915_fence_create_ring(struct intel_engine_cs *ring,
-					    struct intel_context *ctx)
+struct fence *i915_fence_create_ring(struct intel_engine_cs *ring,
+				     struct intel_context *ctx)
 {
 	struct drm_i915_private *dev_priv = ring->dev->dev_private;
 	struct drm_i915_gem_request *request;
diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h
index bac2fb2..9683e8c 100644
--- a/include/uapi/drm/i915_drm.h
+++ b/include/uapi/drm/i915_drm.h
@@ -231,6 +231,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_I915_GEM_CONTEXT_GETPARAM	0x34
 #define DRM_I915_GEM_CONTEXT_SETPARAM	0x35
 #define DRM_I915_GEM_CONTEXT_CREATE2	0x36
+#define DRM_I915_EXEC_MM		0x37
 
 #define DRM_IOCTL_I915_INIT		DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
 #define DRM_IOCTL_I915_FLUSH		DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH)
@@ -285,6 +286,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_IOCTL_I915_GEM_CONTEXT_GETPARAM	DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_GETPARAM, struct drm_i915_gem_context_param)
 #define DRM_IOCTL_I915_GEM_CONTEXT_SETPARAM	DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_SETPARAM, struct drm_i915_gem_context_param)
 #define DRM_IOCTL_I915_GEM_CONTEXT_CREATE2	DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_CREATE2, struct drm_i915_gem_context_create2)
+#define DRM_IOCTL_I915_EXEC_MM			DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_EXEC_MM, struct drm_i915_exec_mm)
 
 /* Allow drivers to submit batchbuffers directly to hardware, relying
  * on the security mechanisms provided by hardware.
@@ -1147,4 +1149,26 @@ struct drm_i915_gem_context_param {
 	__u64 value;
 };
 
+/**
+ * drm_i915_exec_mm - shared address space execbuf
+ * @batch_ptr: address of batch buffer (in context's CPU address space)
+ * @ctx_id: context to use for execution
+ * @flags: see flags
+ * @fence: returned fence handle
+ * @pad: unused
+ *
+ * This simlified execbuf just executes an MI_BATCH_BUFFER_START at
+ * @batch_ptr using @ctx_id as the context.  The context will indicate
+ * which address space the @batch_ptr will use.
+ *
+ * Note @batch_ptr must be dword aligned.
+ */
+struct drm_i915_exec_mm {
+	__u64 batch_ptr;
+	__u32 ctx_id;
+	__u32 flags;
+	__u32 fence;
+	__u32 pad;
+};
+
 #endif /* _UAPI_I915_DRM_H_ */
