diff options
Diffstat (limited to 'arch/powerpc/kvm/book3s_hv_builtin.c')
-rw-r--r-- | arch/powerpc/kvm/book3s_hv_builtin.c | 209 |
1 files changed, 141 insertions, 68 deletions
diff --git a/arch/powerpc/kvm/book3s_hv_builtin.c b/arch/powerpc/kvm/book3s_hv_builtin.c index a795a13f4a70..bed1279aa6a8 100644 --- a/arch/powerpc/kvm/book3s_hv_builtin.c +++ b/arch/powerpc/kvm/book3s_hv_builtin.c | |||
@@ -18,6 +18,15 @@ | |||
18 | #include <asm/kvm_ppc.h> | 18 | #include <asm/kvm_ppc.h> |
19 | #include <asm/kvm_book3s.h> | 19 | #include <asm/kvm_book3s.h> |
20 | 20 | ||
21 | #define KVM_LINEAR_RMA 0 | ||
22 | #define KVM_LINEAR_HPT 1 | ||
23 | |||
24 | static void __init kvm_linear_init_one(ulong size, int count, int type); | ||
25 | static struct kvmppc_linear_info *kvm_alloc_linear(int type); | ||
26 | static void kvm_release_linear(struct kvmppc_linear_info *ri); | ||
27 | |||
28 | /*************** RMA *************/ | ||
29 | |||
21 | /* | 30 | /* |
22 | * This maintains a list of RMAs (real mode areas) for KVM guests to use. | 31 | * This maintains a list of RMAs (real mode areas) for KVM guests to use. |
23 | * Each RMA has to be physically contiguous and of a size that the | 32 | * Each RMA has to be physically contiguous and of a size that the |
@@ -29,32 +38,6 @@ | |||
29 | static unsigned long kvm_rma_size = 64 << 20; /* 64MB */ | 38 | static unsigned long kvm_rma_size = 64 << 20; /* 64MB */ |
30 | static unsigned long kvm_rma_count; | 39 | static unsigned long kvm_rma_count; |
31 | 40 | ||
32 | static int __init early_parse_rma_size(char *p) | ||
33 | { | ||
34 | if (!p) | ||
35 | return 1; | ||
36 | |||
37 | kvm_rma_size = memparse(p, &p); | ||
38 | |||
39 | return 0; | ||
40 | } | ||
41 | early_param("kvm_rma_size", early_parse_rma_size); | ||
42 | |||
43 | static int __init early_parse_rma_count(char *p) | ||
44 | { | ||
45 | if (!p) | ||
46 | return 1; | ||
47 | |||
48 | kvm_rma_count = simple_strtoul(p, NULL, 0); | ||
49 | |||
50 | return 0; | ||
51 | } | ||
52 | early_param("kvm_rma_count", early_parse_rma_count); | ||
53 | |||
54 | static struct kvmppc_rma_info *rma_info; | ||
55 | static LIST_HEAD(free_rmas); | ||
56 | static DEFINE_SPINLOCK(rma_lock); | ||
57 | |||
58 | /* Work out RMLS (real mode limit selector) field value for a given RMA size. | 41 | /* Work out RMLS (real mode limit selector) field value for a given RMA size. |
59 | Assumes POWER7 or PPC970. */ | 42 | Assumes POWER7 or PPC970. */ |
60 | static inline int lpcr_rmls(unsigned long rma_size) | 43 | static inline int lpcr_rmls(unsigned long rma_size) |
@@ -81,45 +64,106 @@ static inline int lpcr_rmls(unsigned long rma_size) | |||
81 | } | 64 | } |
82 | } | 65 | } |
83 | 66 | ||
67 | static int __init early_parse_rma_size(char *p) | ||
68 | { | ||
69 | if (!p) | ||
70 | return 1; | ||
71 | |||
72 | kvm_rma_size = memparse(p, &p); | ||
73 | |||
74 | return 0; | ||
75 | } | ||
76 | early_param("kvm_rma_size", early_parse_rma_size); | ||
77 | |||
78 | static int __init early_parse_rma_count(char *p) | ||
79 | { | ||
80 | if (!p) | ||
81 | return 1; | ||
82 | |||
83 | kvm_rma_count = simple_strtoul(p, NULL, 0); | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | early_param("kvm_rma_count", early_parse_rma_count); | ||
88 | |||
89 | struct kvmppc_linear_info *kvm_alloc_rma(void) | ||
90 | { | ||
91 | return kvm_alloc_linear(KVM_LINEAR_RMA); | ||
92 | } | ||
93 | EXPORT_SYMBOL_GPL(kvm_alloc_rma); | ||
94 | |||
95 | void kvm_release_rma(struct kvmppc_linear_info *ri) | ||
96 | { | ||
97 | kvm_release_linear(ri); | ||
98 | } | ||
99 | EXPORT_SYMBOL_GPL(kvm_release_rma); | ||
100 | |||
101 | /*************** HPT *************/ | ||
102 | |||
84 | /* | 103 | /* |
85 | * Called at boot time while the bootmem allocator is active, | 104 | * This maintains a list of big linear HPT tables that contain the GVA->HPA |
86 | * to allocate contiguous physical memory for the real memory | 105 | * memory mappings. If we don't reserve those early on, we might not be able |
87 | * areas for guests. | 106 | * to get a big (usually 16MB) linear memory region from the kernel anymore. |
88 | */ | 107 | */ |
89 | void __init kvm_rma_init(void) | 108 | |
109 | static unsigned long kvm_hpt_count; | ||
110 | |||
111 | static int __init early_parse_hpt_count(char *p) | ||
112 | { | ||
113 | if (!p) | ||
114 | return 1; | ||
115 | |||
116 | kvm_hpt_count = simple_strtoul(p, NULL, 0); | ||
117 | |||
118 | return 0; | ||
119 | } | ||
120 | early_param("kvm_hpt_count", early_parse_hpt_count); | ||
121 | |||
122 | struct kvmppc_linear_info *kvm_alloc_hpt(void) | ||
123 | { | ||
124 | return kvm_alloc_linear(KVM_LINEAR_HPT); | ||
125 | } | ||
126 | EXPORT_SYMBOL_GPL(kvm_alloc_hpt); | ||
127 | |||
128 | void kvm_release_hpt(struct kvmppc_linear_info *li) | ||
129 | { | ||
130 | kvm_release_linear(li); | ||
131 | } | ||
132 | EXPORT_SYMBOL_GPL(kvm_release_hpt); | ||
133 | |||
134 | /*************** generic *************/ | ||
135 | |||
136 | static LIST_HEAD(free_linears); | ||
137 | static DEFINE_SPINLOCK(linear_lock); | ||
138 | |||
139 | static void __init kvm_linear_init_one(ulong size, int count, int type) | ||
90 | { | 140 | { |
91 | unsigned long i; | 141 | unsigned long i; |
92 | unsigned long j, npages; | 142 | unsigned long j, npages; |
93 | void *rma; | 143 | void *linear; |
94 | struct page *pg; | 144 | struct page *pg; |
145 | const char *typestr; | ||
146 | struct kvmppc_linear_info *linear_info; | ||
95 | 147 | ||
96 | /* Only do this on PPC970 in HV mode */ | 148 | if (!count) |
97 | if (!cpu_has_feature(CPU_FTR_HVMODE) || | ||
98 | !cpu_has_feature(CPU_FTR_ARCH_201)) | ||
99 | return; | ||
100 | |||
101 | if (!kvm_rma_size || !kvm_rma_count) | ||
102 | return; | 149 | return; |
103 | 150 | ||
104 | /* Check that the requested size is one supported in hardware */ | 151 | typestr = (type == KVM_LINEAR_RMA) ? "RMA" : "HPT"; |
105 | if (lpcr_rmls(kvm_rma_size) < 0) { | 152 | |
106 | pr_err("RMA size of 0x%lx not supported\n", kvm_rma_size); | 153 | npages = size >> PAGE_SHIFT; |
107 | return; | 154 | linear_info = alloc_bootmem(count * sizeof(struct kvmppc_linear_info)); |
108 | } | 155 | for (i = 0; i < count; ++i) { |
109 | 156 | linear = alloc_bootmem_align(size, size); | |
110 | npages = kvm_rma_size >> PAGE_SHIFT; | 157 | pr_info("Allocated KVM %s at %p (%ld MB)\n", typestr, linear, |
111 | rma_info = alloc_bootmem(kvm_rma_count * sizeof(struct kvmppc_rma_info)); | 158 | size >> 20); |
112 | for (i = 0; i < kvm_rma_count; ++i) { | 159 | linear_info[i].base_virt = linear; |
113 | rma = alloc_bootmem_align(kvm_rma_size, kvm_rma_size); | 160 | linear_info[i].base_pfn = __pa(linear) >> PAGE_SHIFT; |
114 | pr_info("Allocated KVM RMA at %p (%ld MB)\n", rma, | 161 | linear_info[i].npages = npages; |
115 | kvm_rma_size >> 20); | 162 | linear_info[i].type = type; |
116 | rma_info[i].base_virt = rma; | 163 | list_add_tail(&linear_info[i].list, &free_linears); |
117 | rma_info[i].base_pfn = __pa(rma) >> PAGE_SHIFT; | 164 | atomic_set(&linear_info[i].use_count, 0); |
118 | rma_info[i].npages = npages; | 165 | |
119 | list_add_tail(&rma_info[i].list, &free_rmas); | 166 | pg = pfn_to_page(linear_info[i].base_pfn); |
120 | atomic_set(&rma_info[i].use_count, 0); | ||
121 | |||
122 | pg = pfn_to_page(rma_info[i].base_pfn); | ||
123 | for (j = 0; j < npages; ++j) { | 167 | for (j = 0; j < npages; ++j) { |
124 | atomic_inc(&pg->_count); | 168 | atomic_inc(&pg->_count); |
125 | ++pg; | 169 | ++pg; |
@@ -127,30 +171,59 @@ void __init kvm_rma_init(void) | |||
127 | } | 171 | } |
128 | } | 172 | } |
129 | 173 | ||
130 | struct kvmppc_rma_info *kvm_alloc_rma(void) | 174 | static struct kvmppc_linear_info *kvm_alloc_linear(int type) |
131 | { | 175 | { |
132 | struct kvmppc_rma_info *ri; | 176 | struct kvmppc_linear_info *ri; |
133 | 177 | ||
134 | ri = NULL; | 178 | ri = NULL; |
135 | spin_lock(&rma_lock); | 179 | spin_lock(&linear_lock); |
136 | if (!list_empty(&free_rmas)) { | 180 | list_for_each_entry(ri, &free_linears, list) { |
137 | ri = list_first_entry(&free_rmas, struct kvmppc_rma_info, list); | 181 | if (ri->type != type) |
182 | continue; | ||
183 | |||
138 | list_del(&ri->list); | 184 | list_del(&ri->list); |
139 | atomic_inc(&ri->use_count); | 185 | atomic_inc(&ri->use_count); |
186 | break; | ||
140 | } | 187 | } |
141 | spin_unlock(&rma_lock); | 188 | spin_unlock(&linear_lock); |
189 | memset(ri->base_virt, 0, ri->npages << PAGE_SHIFT); | ||
142 | return ri; | 190 | return ri; |
143 | } | 191 | } |
144 | EXPORT_SYMBOL_GPL(kvm_alloc_rma); | ||
145 | 192 | ||
146 | void kvm_release_rma(struct kvmppc_rma_info *ri) | 193 | static void kvm_release_linear(struct kvmppc_linear_info *ri) |
147 | { | 194 | { |
148 | if (atomic_dec_and_test(&ri->use_count)) { | 195 | if (atomic_dec_and_test(&ri->use_count)) { |
149 | spin_lock(&rma_lock); | 196 | spin_lock(&linear_lock); |
150 | list_add_tail(&ri->list, &free_rmas); | 197 | list_add_tail(&ri->list, &free_linears); |
151 | spin_unlock(&rma_lock); | 198 | spin_unlock(&linear_lock); |
152 | 199 | ||
153 | } | 200 | } |
154 | } | 201 | } |
155 | EXPORT_SYMBOL_GPL(kvm_release_rma); | ||
156 | 202 | ||
203 | /* | ||
204 | * Called at boot time while the bootmem allocator is active, | ||
205 | * to allocate contiguous physical memory for the hash page | ||
206 | * tables for guests. | ||
207 | */ | ||
208 | void __init kvm_linear_init(void) | ||
209 | { | ||
210 | /* HPT */ | ||
211 | kvm_linear_init_one(1 << HPT_ORDER, kvm_hpt_count, KVM_LINEAR_HPT); | ||
212 | |||
213 | /* RMA */ | ||
214 | /* Only do this on PPC970 in HV mode */ | ||
215 | if (!cpu_has_feature(CPU_FTR_HVMODE) || | ||
216 | !cpu_has_feature(CPU_FTR_ARCH_201)) | ||
217 | return; | ||
218 | |||
219 | if (!kvm_rma_size || !kvm_rma_count) | ||
220 | return; | ||
221 | |||
222 | /* Check that the requested size is one supported in hardware */ | ||
223 | if (lpcr_rmls(kvm_rma_size) < 0) { | ||
224 | pr_err("RMA size of 0x%lx not supported\n", kvm_rma_size); | ||
225 | return; | ||
226 | } | ||
227 | |||
228 | kvm_linear_init_one(kvm_rma_size, kvm_rma_count, KVM_LINEAR_RMA); | ||
229 | } | ||