aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kvm/book3s_64_vio.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2012-03-15 17:58:34 -0400
committerAlexander Graf <agraf@suse.de>2012-05-06 10:19:11 -0400
commitf31e65e1170edba4a86bd8cba0318e251d3746d0 (patch)
tree511cd618867f7335e451d416cb7fc8e6944606ff /arch/powerpc/kvm/book3s_64_vio.c
parent4444aa5f78eff73a353c8c4784cda2de74dea54b (diff)
kvm/book3s: Make kernel emulated H_PUT_TCE available for "PR" KVM
There is nothing in the code for emulating TCE tables in the kernel that prevents it from working on "PR" KVM... other than ifdef's and location of the code. This and moves the bulk of the code there to a new file called book3s_64_vio.c. This speeds things up a bit on my G5. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> [agraf: fix for hv kvm, 32bit, whitespace] Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'arch/powerpc/kvm/book3s_64_vio.c')
-rw-r--r--arch/powerpc/kvm/book3s_64_vio.c150
1 files changed, 150 insertions, 0 deletions
diff --git a/arch/powerpc/kvm/book3s_64_vio.c b/arch/powerpc/kvm/book3s_64_vio.c
new file mode 100644
index 000000000000..72ffc899c082
--- /dev/null
+++ b/arch/powerpc/kvm/book3s_64_vio.c
@@ -0,0 +1,150 @@
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#include <linux/anon_inodes.h>
29
30#include <asm/tlbflush.h>
31#include <asm/kvm_ppc.h>
32#include <asm/kvm_book3s.h>
33#include <asm/mmu-hash64.h>
34#include <asm/hvcall.h>
35#include <asm/synch.h>
36#include <asm/ppc-opcode.h>
37#include <asm/kvm_host.h>
38#include <asm/udbg.h>
39
40#define TCES_PER_PAGE (PAGE_SIZE / sizeof(u64))
41
42static long kvmppc_stt_npages(unsigned long window_size)
43{
44 return ALIGN((window_size >> SPAPR_TCE_SHIFT)
45 * sizeof(u64), PAGE_SIZE) / PAGE_SIZE;
46}
47
48static void release_spapr_tce_table(struct kvmppc_spapr_tce_table *stt)
49{
50 struct kvm *kvm = stt->kvm;
51 int i;
52
53 mutex_lock(&kvm->lock);
54 list_del(&stt->list);
55 for (i = 0; i < kvmppc_stt_npages(stt->window_size); i++)
56 __free_page(stt->pages[i]);
57 kfree(stt);
58 mutex_unlock(&kvm->lock);
59
60 kvm_put_kvm(kvm);
61}
62
63static int kvm_spapr_tce_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
64{
65 struct kvmppc_spapr_tce_table *stt = vma->vm_file->private_data;
66 struct page *page;
67
68 if (vmf->pgoff >= kvmppc_stt_npages(stt->window_size))
69 return VM_FAULT_SIGBUS;
70
71 page = stt->pages[vmf->pgoff];
72 get_page(page);
73 vmf->page = page;
74 return 0;
75}
76
77static const struct vm_operations_struct kvm_spapr_tce_vm_ops = {
78 .fault = kvm_spapr_tce_fault,
79};
80
81static int kvm_spapr_tce_mmap(struct file *file, struct vm_area_struct *vma)
82{
83 vma->vm_ops = &kvm_spapr_tce_vm_ops;
84 return 0;
85}
86
87static int kvm_spapr_tce_release(struct inode *inode, struct file *filp)
88{
89 struct kvmppc_spapr_tce_table *stt = filp->private_data;
90
91 release_spapr_tce_table(stt);
92 return 0;
93}
94
95static struct file_operations kvm_spapr_tce_fops = {
96 .mmap = kvm_spapr_tce_mmap,
97 .release = kvm_spapr_tce_release,
98};
99
100long kvm_vm_ioctl_create_spapr_tce(struct kvm *kvm,
101 struct kvm_create_spapr_tce *args)
102{
103 struct kvmppc_spapr_tce_table *stt = NULL;
104 long npages;
105 int ret = -ENOMEM;
106 int i;
107
108 /* Check this LIOBN hasn't been previously allocated */
109 list_for_each_entry(stt, &kvm->arch.spapr_tce_tables, list) {
110 if (stt->liobn == args->liobn)
111 return -EBUSY;
112 }
113
114 npages = kvmppc_stt_npages(args->window_size);
115
116 stt = kzalloc(sizeof(*stt) + npages * sizeof(struct page *),
117 GFP_KERNEL);
118 if (!stt)
119 goto fail;
120
121 stt->liobn = args->liobn;
122 stt->window_size = args->window_size;
123 stt->kvm = kvm;
124
125 for (i = 0; i < npages; i++) {
126 stt->pages[i] = alloc_page(GFP_KERNEL | __GFP_ZERO);
127 if (!stt->pages[i])
128 goto fail;
129 }
130
131 kvm_get_kvm(kvm);
132
133 mutex_lock(&kvm->lock);
134 list_add(&stt->list, &kvm->arch.spapr_tce_tables);
135
136 mutex_unlock(&kvm->lock);
137
138 return anon_inode_getfd("kvm-spapr-tce", &kvm_spapr_tce_fops,
139 stt, O_RDWR);
140
141fail:
142 if (stt) {
143 for (i = 0; i < npages; i++)
144 if (stt->pages[i])
145 __free_page(stt->pages[i]);
146
147 kfree(stt);
148 }
149 return ret;
150}