summary refs log tree commit diff
path: root/drivers/gpu
diff options
context:
space:
mode:
authorJike Song <jike.song@intel.com>2016-12-08 11:00:35 +0800
committerZhenyu Wang <zhenyuw@linux.intel.com>2016-12-16 16:55:26 +0800
commitf440c8a572d7e0002d5c2c8dbd740130ad8ffa5b (patch)
tree9511b191afb97fab97f0fd0747b9c7cc214568ae /drivers/gpu
parentc55b1de02d68e4343045391c0f4978c0bc5a9447 (diff)
downloadlinux-f440c8a572d7e0002d5c2c8dbd740130ad8ffa5b.tar.gz
drm/i915/gvt/kvmgt: read/write GPA via KVM API
Previously to read/write a GPA, we at first try to pin the GFN it belongs
to, then translate the pinned PFN to a kernel HVA, then read/write it.
This is however not necessary. A GFN should be pinned IFF it would be
accessed by peripheral devices (DMA), not by CPU. This patch changes
the read/write method to KVM API, which will leverage userspace HVA
and copy_{from|to}_usr instead.

Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/drm/i915/gvt/kvmgt.c37
1 files changed, 16 insertions, 21 deletions
diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c
index aecb657d8b99..24496ad6a942 100644
--- a/drivers/gpu/drm/i915/gvt/kvmgt.c
+++ b/drivers/gpu/drm/i915/gvt/kvmgt.c
@@ -31,6 +31,7 @@
 #include <linux/init.h>
 #include <linux/device.h>
 #include <linux/mm.h>
+#include <linux/mmu_context.h>
 #include <linux/types.h>
 #include <linux/list.h>
 #include <linux/rbtree.h>
@@ -519,33 +520,27 @@ static unsigned long kvmgt_gfn_to_pfn(unsigned long handle, unsigned long gfn)
 	return pfn;
 }
 
-static void *kvmgt_gpa_to_hva(unsigned long handle, unsigned long gpa)
-{
-	unsigned long pfn;
-	gfn_t gfn = gpa_to_gfn(gpa);
-
-	pfn = kvmgt_gfn_to_pfn(handle, gfn);
-	if (!pfn)
-		return NULL;
-
-	return (char *)pfn_to_kaddr(pfn) + offset_in_page(gpa);
-}
-
 static int kvmgt_rw_gpa(unsigned long handle, unsigned long gpa,
 			void *buf, unsigned long len, bool write)
 {
-	void *hva = NULL;
+	struct kvmgt_guest_info *info;
+	struct kvm *kvm;
+	int ret;
+	bool kthread = current->mm == NULL;
 
-	hva = kvmgt_gpa_to_hva(handle, gpa);
-	if (!hva)
-		return -EFAULT;
+	info = (struct kvmgt_guest_info *)handle;
+	kvm = info->kvm;
 
-	if (write)
-		memcpy(hva, buf, len);
-	else
-		memcpy(buf, hva, len);
+	if (kthread)
+		use_mm(kvm->mm);
 
-	return 0;
+	ret = write ? kvm_write_guest(kvm, gpa, buf, len) :
+		      kvm_read_guest(kvm, gpa, buf, len);
+
+	if (kthread)
+		unuse_mm(kvm->mm);
+
+	return ret;
 }
 
 static int kvmgt_read_gpa(unsigned long handle, unsigned long gpa,