diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig
index ba9595960bbe..c2e48710eec8 100644
--- a/drivers/gpu/drm/i915/Kconfig
+++ b/drivers/gpu/drm/i915/Kconfig
@@ -137,6 +137,17 @@ config DRM_I915_GVT_KVMGT
 	  Choose this option if you want to enable KVMGT support for
 	  Intel GVT-g.
 
+config DRM_I915_SVM
+	bool "Enable Shared Virtual Memory support in i915"
+	depends on STAGING
+	depends on DRM_I915
+	default n
+	help
+	  Choose this option if you want Shared Virtual Memory (SVM)
+	  support in i915. With SVM support, one can share the virtual
+	  address space between a process and the GPU. SVM is supported
+	  on both integrated and discrete Intel GPUs.
+
 menu "drm/i915 Debugging"
 depends on DRM_I915
 depends on EXPERT
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index b8c5f8934dbd..dbdbe85790f6 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -156,6 +156,9 @@ i915-y += \
 	  intel_region_lmem.o \
 	  intel_wopcm.o
 
+# SVM code
+i915-$(CONFIG_DRM_I915_SVM) += gem/i915_gem_svm.o
+
 # general-purpose microcontroller (GuC) support
 i915-y += gt/uc/intel_uc.o \
 	  gt/uc/intel_uc_fw.o \
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_svm.c b/drivers/gpu/drm/i915/gem/i915_gem_svm.c
new file mode 100644
index 000000000000..f26567ea0e3a
--- /dev/null
+++ b/drivers/gpu/drm/i915/gem/i915_gem_svm.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2019 Intel Corporation
+ */
+
+#include "i915_drv.h"
+#include "i915_gem_gtt.h"
+#include "i915_gem_lmem.h"
+
+static struct i915_vma *
+i915_gem_vm_lookup_svm_vma(struct i915_address_space *vm,
+			   struct drm_i915_gem_object *obj,
+			   struct drm_i915_gem_vm_bind_va *va)
+{
+	struct i915_vma *vma, *tmp;
+
+	/* FIXME: Optimize lookup (use hashtable or tree) */
+	mutex_lock(&vm->svm_mutex);
+	list_for_each_entry_safe(vma, tmp, &vm->svm_list, svm_link) {
+		if (vma->obj != obj ||
+		    vma->node.start != va->start ||
+		    vma->node.size != va->length)
+			continue;
+
+		list_del_init(&vma->svm_link);
+		mutex_unlock(&vm->svm_mutex);
+		return vma;
+	}
+	mutex_unlock(&vm->svm_mutex);
+	return NULL;
+}
+
+int i915_gem_vm_bind_svm_obj(struct i915_address_space *vm,
+			     struct drm_i915_gem_vm_bind_va *va,
+			     struct drm_file *file)
+{
+	struct drm_i915_gem_object *obj;
+	struct i915_vma *vma;
+	int ret = 0;
+
+	obj = i915_gem_object_lookup(file, va->handle);
+	if (!obj)
+		return -ENOENT;
+
+	/* For dgfx, ensure the obj is in device local memory only */
+	if (IS_DGFX(vm->i915) && !i915_gem_object_is_lmem(obj))
+		return -EINVAL;
+
+	if (!(va->flags & I915_GEM_VM_BIND_UNBIND)) {
+		struct i915_ggtt_view view;
+
+		view.type = I915_GGTT_VIEW_PARTIAL;
+		view.partial.offset = va->offset >> PAGE_SHIFT;
+		view.partial.size = va->length >> PAGE_SHIFT;
+		vma = i915_vma_instance(obj, vm, &view);
+		if (IS_ERR(vma)) {
+			ret = PTR_ERR(vma);
+			goto put_obj;
+		}
+		vma->va_start = va->start;
+		/* Disable eviction for now */
+		__i915_vma_pin(vma);
+
+		/*
+		 * FIXME: Reserve VA here and bind only if the vm is active.
+		 * This ensures any overlapping binding is rejected here itself.
+		 * and we don't need to store va_start.
+		 */
+		mutex_lock(&vm->svm_mutex);
+		list_add(&vma->svm_link, &vm->svm_list);
+		mutex_unlock(&vm->svm_mutex);
+	} else {
+		vma = i915_gem_vm_lookup_svm_vma(vm, obj, va);
+		if (vma) {
+			__i915_vma_unpin(vma);
+			__i915_vma_put(vma);
+		}
+	}
+put_obj:
+	i915_gem_object_put(obj);
+	return ret;
+}
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_svm.h b/drivers/gpu/drm/i915/gem/i915_gem_svm.h
new file mode 100644
index 000000000000..e1ad125e86cc
--- /dev/null
+++ b/drivers/gpu/drm/i915/gem/i915_gem_svm.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2019 Intel Corporation
+ */
+
+#ifndef __I915_GEM_SVM_H
+#define __I915_GEM_SVM_H
+
+#include "i915_drv.h"
+
+#if defined(CONFIG_DRM_I915_SVM)
+int i915_gem_vm_bind_svm_obj(struct i915_address_space *vm,
+			     struct drm_i915_gem_vm_bind_va *va,
+			     struct drm_file *file);
+#else
+static inline int i915_gem_vm_bind_svm_obj(struct i915_address_space *vm,
+					   struct drm_i915_gem_vm_bind_va *va,
+					   struct drm_file *file)
+{ return -ENOTSUPP; }
+#endif
+
+#endif /* __I915_GEM_SVM_H */
diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.c b/drivers/gpu/drm/i915/gt/intel_gtt.c
index ad5bf7fc851a..897aad1f7c08 100644
--- a/drivers/gpu/drm/i915/gt/intel_gtt.c
+++ b/drivers/gpu/drm/i915/gt/intel_gtt.c
@@ -276,6 +276,7 @@ void i915_address_space_init(struct i915_address_space *vm, int subclass)
 
 	INIT_LIST_HEAD(&vm->bound_list);
 
+	INIT_LIST_HEAD(&vm->svm_list);
 	mutex_init(&vm->svm_mutex);
 	i915_active_init(&vm->active, __i915_vm_active, __i915_vm_retire);
 }
diff --git a/drivers/gpu/drm/i915/gt/intel_gtt.h b/drivers/gpu/drm/i915/gt/intel_gtt.h
index f3e5469c4dc6..800c062a4b0e 100644
--- a/drivers/gpu/drm/i915/gt/intel_gtt.h
+++ b/drivers/gpu/drm/i915/gt/intel_gtt.h
@@ -263,6 +263,10 @@ struct i915_address_space {
 	 */
 	struct list_head bound_list;
 
+	/**
+	 * List of SVM bind objects.
+	 */
+	struct list_head svm_list;
 	struct mutex svm_mutex; /* protects svm operations */
 
 	struct pagestash free_pages;
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 64ba02c55282..5631fa82bfed 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -62,6 +62,7 @@
 #include "gem/i915_gem_context.h"
 #include "gem/i915_gem_ioctls.h"
 #include "gem/i915_gem_mman.h"
+#include "gem/i915_gem_svm.h"
 #include "gt/intel_gt.h"
 #include "gt/intel_gt_pm.h"
 #include "gt/intel_rc6.h"
@@ -2718,6 +2719,9 @@ static int i915_gem_vm_bind_ioctl(struct drm_device *dev, void *data,
 		}
 
 		switch (va.type) {
+		case I915_GEM_VM_BIND_SVM_OBJ:
+			ret = i915_gem_vm_bind_svm_obj(vm, &va, file);
+			break;
 		default:
 			ret = -EINVAL;
 		}
diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c
index 48af37355371..3e16b291f806 100644
--- a/drivers/gpu/drm/i915/i915_vma.c
+++ b/drivers/gpu/drm/i915/i915_vma.c
@@ -223,6 +223,7 @@ vma_create(struct drm_i915_gem_object *obj,
 
 	spin_unlock(&obj->vma.lock);
 
+	INIT_LIST_HEAD(&vma->svm_link);
 	return vma;
 
 err_vma:
@@ -1047,6 +1048,10 @@ void i915_vma_release(struct kref *ref)
 		list_del(&vma->obj_link);
 		rb_erase(&vma->obj_node, &obj->vma.tree);
 		spin_unlock(&obj->vma.lock);
+
+		mutex_lock(&vma->vm->svm_mutex);
+		list_del_init(&vma->svm_link);
+		mutex_unlock(&vma->vm->svm_mutex);
 	}
 
 	__i915_vma_remove_closed(vma);
diff --git a/drivers/gpu/drm/i915/i915_vma_types.h b/drivers/gpu/drm/i915/i915_vma_types.h
index e0942efd5236..d5a4fb4e43a4 100644
--- a/drivers/gpu/drm/i915/i915_vma_types.h
+++ b/drivers/gpu/drm/i915/i915_vma_types.h
@@ -269,6 +269,9 @@ struct i915_vma {
 	/** This object's place on the active/inactive lists */
 	struct list_head vm_link;
 
+	u64 va_start;
+	struct list_head svm_link; /* Link in persistent VMA list */
+
 	struct list_head obj_link; /* Link in the object's VMA list */
 	struct rb_node obj_node;
 	struct hlist_node obj_hash;
