diff options
author | Jike Song <jike.song@intel.com> | 2016-12-07 22:00:35 -0500 |
---|---|---|
committer | Zhenyu Wang <zhenyuw@linux.intel.com> | 2016-12-16 03:55:26 -0500 |
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 @@ | |||
31 | #include <linux/init.h> | 31 | #include <linux/init.h> |
32 | #include <linux/device.h> | 32 | #include <linux/device.h> |
33 | #include <linux/mm.h> | 33 | #include <linux/mm.h> |
34 | #include <linux/mmu_context.h> | ||
34 | #include <linux/types.h> | 35 | #include <linux/types.h> |
35 | #include <linux/list.h> | 36 | #include <linux/list.h> |
36 | #include <linux/rbtree.h> | 37 | #include <linux/rbtree.h> |
@@ -519,33 +520,27 @@ static unsigned long kvmgt_gfn_to_pfn(unsigned long handle, unsigned long gfn) | |||
519 | return pfn; | 520 | return pfn; |
520 | } | 521 | } |
521 | 522 | ||
522 | static void *kvmgt_gpa_to_hva(unsigned long handle, unsigned long gpa) | ||
523 | { | ||
524 | unsigned long pfn; | ||
525 | gfn_t gfn = gpa_to_gfn(gpa); | ||
526 | |||
527 | pfn = kvmgt_gfn_to_pfn(handle, gfn); | ||
528 | if (!pfn) | ||
529 | return NULL; | ||
530 | |||
531 | return (char *)pfn_to_kaddr(pfn) + offset_in_page(gpa); | ||
532 | } | ||
533 | |||
534 | static int kvmgt_rw_gpa(unsigned long handle, unsigned long gpa, | 523 | static int kvmgt_rw_gpa(unsigned long handle, unsigned long gpa, |
535 | void *buf, unsigned long len, bool write) | 524 | void *buf, unsigned long len, bool write) |
536 | { | 525 | { |
537 | void *hva = NULL; | 526 | struct kvmgt_guest_info *info; |
527 | struct kvm *kvm; | ||
528 | int ret; | ||
529 | bool kthread = current->mm == NULL; | ||
538 | 530 | ||
539 | hva = kvmgt_gpa_to_hva(handle, gpa); | 531 | info = (struct kvmgt_guest_info *)handle; |
540 | if (!hva) | 532 | kvm = info->kvm; |
541 | return -EFAULT; | ||
542 | 533 | ||
543 | if (write) | 534 | if (kthread) |
544 | memcpy(hva, buf, len); | 535 | use_mm(kvm->mm); |
545 | else | ||
546 | memcpy(buf, hva, len); | ||
547 | 536 | ||
548 | return 0; | 537 | ret = write ? kvm_write_guest(kvm, gpa, buf, len) : |
538 | kvm_read_guest(kvm, gpa, buf, len); | ||
539 | |||
540 | if (kthread) | ||
541 | unuse_mm(kvm->mm); | ||
542 | |||
543 | return ret; | ||
549 | } | 544 | } |
550 | 545 | ||
551 | static int kvmgt_read_gpa(unsigned long handle, unsigned long gpa, | 546 | static int kvmgt_read_gpa(unsigned long handle, unsigned long gpa, |