diff options
author | Jike Song <jike.song@intel.com> | 2016-12-08 11:00:35 +0800 |
---|---|---|
committer | Zhenyu Wang <zhenyuw@linux.intel.com> | 2016-12-16 16:55:26 +0800 |
commit | f440c8a572d7e0002d5c2c8dbd740130ad8ffa5b (patch) | |
tree | 9511b191afb97fab97f0fd0747b9c7cc214568ae | |
parent | c55b1de02d68e4343045391c0f4978c0bc5a9447 (diff) |
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>
-rw-r--r-- | drivers/gpu/drm/i915/gvt/kvmgt.c | 37 |
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, |