aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kvm
diff options
context:
space:
mode:
authorDavid Gibson <dwg@au1.ibm.com>2011-06-28 20:22:41 -0400
committerAvi Kivity <avi@redhat.com>2011-07-12 06:16:56 -0400
commit54738c097163c3f01e67ccc85462b78d4d4f495f (patch)
treecba8d389d50251856cbe967c16ba2193a30d6d12 /arch/powerpc/kvm
parenta8606e20e41a8149456bafdf76ad29d47672027c (diff)
KVM: PPC: Accelerate H_PUT_TCE by implementing it in real mode
This improves I/O performance for guests using the PAPR paravirtualization interface by making the H_PUT_TCE hcall faster, by implementing it in real mode. H_PUT_TCE is used for updating virtual IOMMU tables, and is used both for virtual I/O and for real I/O in the PAPR interface. Since this moves the IOMMU tables into the kernel, we define a new KVM_CREATE_SPAPR_TCE ioctl to allow qemu to create the tables. The ioctl returns a file descriptor which can be used to mmap the newly created table. The qemu driver models use them in the same way as userspace managed tables, but they can be updated directly by the guest with a real-mode H_PUT_TCE implementation, reducing the number of host/guest context switches during guest IO. There are certain circumstances where it is useful for userland qemu to write to the TCE table even if the kernel H_PUT_TCE path is used most of the time. Specifically, allowing this will avoid awkwardness when we need to reset the table. More importantly, we will in the future need to write the table in order to restore its state after a checkpoint resume or migration. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> Signed-off-by: Paul Mackerras <paulus@samba.org> Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'arch/powerpc/kvm')
-rw-r--r--arch/powerpc/kvm/Makefile3
-rw-r--r--arch/powerpc/kvm/book3s_64_vio_hv.c73
-rw-r--r--arch/powerpc/kvm/book3s_hv.c116
-rw-r--r--arch/powerpc/kvm/book3s_hv_rmhandlers.S2
-rw-r--r--arch/powerpc/kvm/powerpc.c18
5 files changed, 209 insertions, 3 deletions
diff --git a/arch/powerpc/kvm/Makefile b/arch/powerpc/kvm/Makefile
index 2ecffc0dc1bb..1de3d54901d4 100644
--- a/arch/powerpc/kvm/Makefile
+++ b/arch/powerpc/kvm/Makefile
@@ -55,7 +55,8 @@ kvm-book3s_64-objs-$(CONFIG_KVM_BOOK3S_64_HV) := \
55 book3s_hv_interrupts.o \ 55 book3s_hv_interrupts.o \
56 book3s_64_mmu_hv.o 56 book3s_64_mmu_hv.o
57kvm-book3s_64-builtin-objs-$(CONFIG_KVM_BOOK3S_64_HV) := \ 57kvm-book3s_64-builtin-objs-$(CONFIG_KVM_BOOK3S_64_HV) := \
58 book3s_hv_rm_mmu.o 58 book3s_hv_rm_mmu.o \
59 book3s_64_vio_hv.o
59 60
60kvm-book3s_64-module-objs := \ 61kvm-book3s_64-module-objs := \
61 ../../../virt/kvm/kvm_main.o \ 62 ../../../virt/kvm/kvm_main.o \
diff --git a/arch/powerpc/kvm/book3s_64_vio_hv.c b/arch/powerpc/kvm/book3s_64_vio_hv.c
new file mode 100644
index 000000000000..ea0f8c537c28
--- /dev/null
+++ b/arch/powerpc/kvm/book3s_64_vio_hv.c
@@ -0,0 +1,73 @@
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License, version 2, as
4 * published by the Free Software Foundation.
5 *
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
10 *
11 * You should have received a copy of the GNU General Public License
12 * along with this program; if not, write to the Free Software
13 * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
14 *
15 * Copyright 2010 Paul Mackerras, IBM Corp. <paulus@au1.ibm.com>
16 * Copyright 2011 David Gibson, IBM Corporation <dwg@au1.ibm.com>
17 */
18
19#include <linux/types.h>
20#include <linux/string.h>
21#include <linux/kvm.h>
22#include <linux/kvm_host.h>
23#include <linux/highmem.h>
24#include <linux/gfp.h>
25#include <linux/slab.h>
26#include <linux/hugetlb.h>
27#include <linux/list.h>
28
29#include <asm/tlbflush.h>
30#include <asm/kvm_ppc.h>
31#include <asm/kvm_book3s.h>
32#include <asm/mmu-hash64.h>
33#include <asm/hvcall.h>
34#include <asm/synch.h>
35#include <asm/ppc-opcode.h>
36#include <asm/kvm_host.h>
37#include <asm/udbg.h>
38
39#define TCES_PER_PAGE (PAGE_SIZE / sizeof(u64))
40
41long kvmppc_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn,
42 unsigned long ioba, unsigned long tce)
43{
44 struct kvm *kvm = vcpu->kvm;
45 struct kvmppc_spapr_tce_table *stt;
46
47 /* udbg_printf("H_PUT_TCE(): liobn=0x%lx ioba=0x%lx, tce=0x%lx\n", */
48 /* liobn, ioba, tce); */
49
50 list_for_each_entry(stt, &kvm->arch.spapr_tce_tables, list) {
51 if (stt->liobn == liobn) {
52 unsigned long idx = ioba >> SPAPR_TCE_SHIFT;
53 struct page *page;
54 u64 *tbl;
55
56 /* udbg_printf("H_PUT_TCE: liobn 0x%lx => stt=%p window_size=0x%x\n", */
57 /* liobn, stt, stt->window_size); */
58 if (ioba >= stt->window_size)
59 return H_PARAMETER;
60
61 page = stt->pages[idx / TCES_PER_PAGE];
62 tbl = (u64 *)page_address(page);
63
64 /* FIXME: Need to validate the TCE itself */
65 /* udbg_printf("tce @ %p\n", &tbl[idx % TCES_PER_PAGE]); */
66 tbl[idx % TCES_PER_PAGE] = tce;
67 return H_SUCCESS;
68 }
69 }
70
71 /* Didn't find the liobn, punt it to userspace */
72 return H_TOO_HARD;
73}
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index af862c30b70e..6fe469eabce8 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -538,6 +538,116 @@ int kvmppc_vcpu_run(struct kvm_run *run, struct kvm_vcpu *vcpu)
538 return r; 538 return r;
539} 539}
540 540
541static long kvmppc_stt_npages(unsigned long window_size)
542{
543 return ALIGN((window_size >> SPAPR_TCE_SHIFT)
544 * sizeof(u64), PAGE_SIZE) / PAGE_SIZE;
545}
546
547static void release_spapr_tce_table(struct kvmppc_spapr_tce_table *stt)
548{
549 struct kvm *kvm = stt->kvm;
550 int i;
551
552 mutex_lock(&kvm->lock);
553 list_del(&stt->list);
554 for (i = 0; i < kvmppc_stt_npages(stt->window_size); i++)
555 __free_page(stt->pages[i]);
556 kfree(stt);
557 mutex_unlock(&kvm->lock);
558
559 kvm_put_kvm(kvm);
560}
561
562static int kvm_spapr_tce_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
563{
564 struct kvmppc_spapr_tce_table *stt = vma->vm_file->private_data;
565 struct page *page;
566
567 if (vmf->pgoff >= kvmppc_stt_npages(stt->window_size))
568 return VM_FAULT_SIGBUS;
569
570 page = stt->pages[vmf->pgoff];
571 get_page(page);
572 vmf->page = page;
573 return 0;
574}
575
576static const struct vm_operations_struct kvm_spapr_tce_vm_ops = {
577 .fault = kvm_spapr_tce_fault,
578};
579
580static int kvm_spapr_tce_mmap(struct file *file, struct vm_area_struct *vma)
581{
582 vma->vm_ops = &kvm_spapr_tce_vm_ops;
583 return 0;
584}
585
586static int kvm_spapr_tce_release(struct inode *inode, struct file *filp)
587{
588 struct kvmppc_spapr_tce_table *stt = filp->private_data;
589
590 release_spapr_tce_table(stt);
591 return 0;
592}
593
594static struct file_operations kvm_spapr_tce_fops = {
595 .mmap = kvm_spapr_tce_mmap,
596 .release = kvm_spapr_tce_release,
597};
598
599long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm,
600 struct kvm_create_spapr_tce *args)
601{
602 struct kvmppc_spapr_tce_table *stt = NULL;
603 long npages;
604 int ret = -ENOMEM;
605 int i;
606
607 /* Check this LIOBN hasn't been previously allocated */
608 list_for_each_entry(stt, &kvm->arch.spapr_tce_tables, list) {
609 if (stt->liobn == args->liobn)
610 return -EBUSY;
611 }
612
613 npages = kvmppc_stt_npages(args->window_size);
614
615 stt = kzalloc(sizeof(*stt) + npages* sizeof(struct page *),
616 GFP_KERNEL);
617 if (!stt)
618 goto fail;
619
620 stt->liobn = args->liobn;
621 stt->window_size = args->window_size;
622 stt->kvm = kvm;
623
624 for (i = 0; i < npages; i++) {
625 stt->pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO);
626 if (!stt->pages[i])
627 goto fail;
628 }
629
630 kvm_get_kvm(kvm);
631
632 mutex_lock(&kvm->lock);
633 list_add(&stt->list, &kvm->arch.spapr_tce_tables);
634
635 mutex_unlock(&kvm->lock);
636
637 return anon_inode_getfd("kvm-spapr-tce", &kvm_spapr_tce_fops,
638 stt, O_RDWR);
639
640fail:
641 if (stt) {
642 for (i = 0; i < npages; i++)
643 if (stt->pages[i])
644 __free_page(stt->pages[i]);
645
646 kfree(stt);
647 }
648 return ret;
649}
650
541int kvmppc_core_prepare_memory_region(struct kvm *kvm, 651int kvmppc_core_prepare_memory_region(struct kvm *kvm,
542 struct kvm_userspace_memory_region *mem) 652 struct kvm_userspace_memory_region *mem)
543{ 653{
@@ -559,13 +669,17 @@ int kvmppc_core_init_vm(struct kvm *kvm)
559 669
560 /* Allocate hashed page table */ 670 /* Allocate hashed page table */
561 r = kvmppc_alloc_hpt(kvm); 671 r = kvmppc_alloc_hpt(kvm);
672 if (r)
673 return r;
562 674
563 return r; 675 INIT_LIST_HEAD(&kvm->arch.spapr_tce_tables);
676 return 0;
564} 677}
565 678
566void kvmppc_core_destroy_vm(struct kvm *kvm) 679void kvmppc_core_destroy_vm(struct kvm *kvm)
567{ 680{
568 kvmppc_free_hpt(kvm); 681 kvmppc_free_hpt(kvm);
682 WARN_ON(!list_empty(&kvm->arch.spapr_tce_tables));
569} 683}
570 684
571/* These are stubs for now */ 685/* These are stubs for now */
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
index 319ff63b1f31..e6adaadcdff2 100644
--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -754,7 +754,7 @@ hcall_real_table:
754 .long 0 /* 0x14 - H_CLEAR_REF */ 754 .long 0 /* 0x14 - H_CLEAR_REF */
755 .long .kvmppc_h_protect - hcall_real_table 755 .long .kvmppc_h_protect - hcall_real_table
756 .long 0 /* 0x1c - H_GET_TCE */ 756 .long 0 /* 0x1c - H_GET_TCE */
757 .long 0 /* 0x20 - H_SET_TCE */ 757 .long .kvmppc_h_put_tce - hcall_real_table
758 .long 0 /* 0x24 - H_SET_SPRG0 */ 758 .long 0 /* 0x24 - H_SET_SPRG0 */
759 .long .kvmppc_h_set_dabr - hcall_real_table 759 .long .kvmppc_h_set_dabr - hcall_real_table
760 .long 0 /* 0x2c */ 760 .long 0 /* 0x2c */
diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c
index 6fc9ee499b61..c78ceb9d5605 100644
--- a/arch/powerpc/kvm/powerpc.c
+++ b/arch/powerpc/kvm/powerpc.c
@@ -203,6 +203,11 @@ int kvm_dev_ioctl_check_extension(long ext)
203 r = KVM_COALESCED_MMIO_PAGE_OFFSET; 203 r = KVM_COALESCED_MMIO_PAGE_OFFSET;
204 break; 204 break;
205#endif 205#endif
206#ifdef CONFIG_KVM_BOOK3S_64_HV
207 case KVM_CAP_SPAPR_TCE:
208 r = 1;
209 break;
210#endif
206 default: 211 default:
207 r = 0; 212 r = 0;
208 break; 213 break;
@@ -653,6 +658,19 @@ long kvm_arch_vm_ioctl(struct file *filp,
653 658
654 break; 659 break;
655 } 660 }
661#ifdef CONFIG_KVM_BOOK3S_64_HV
662 case KVM_CREATE_SPAPR_TCE: {
663 struct kvm_create_spapr_tce create_tce;
664 struct kvm *kvm = filp->private_data;
665
666 r = -EFAULT;
667 if (copy_from_user(&create_tce, argp, sizeof(create_tce)))
668 goto out;
669 r = kvm_vm_ioctl_create_spapr_tce(kvm, &create_tce);
670 goto out;
671 }
672#endif /* CONFIG_KVM_BOOK3S_64_HV */
673
656 default: 674 default:
657 r = -ENOTTY; 675 r = -ENOTTY;
658 } 676 }