]>
Commit | Line | Data |
---|---|---|
73196cd3 | 1 | /* |
c7ba7771 | 2 | * Copyright (C) 2010,2012 Freescale Semiconductor, Inc. All rights reserved. |
73196cd3 SW |
3 | * |
4 | * Author: Varun Sethi, <varun.sethi@freescale.com> | |
5 | * | |
6 | * Description: | |
7 | * This file is derived from arch/powerpc/kvm/e500.c, | |
8 | * by Yu Liu <yu.liu@freescale.com>. | |
9 | * | |
10 | * This program is free software; you can redistribute it and/or modify | |
11 | * it under the terms of the GNU General Public License, version 2, as | |
12 | * published by the Free Software Foundation. | |
13 | */ | |
14 | ||
15 | #include <linux/kvm_host.h> | |
16 | #include <linux/slab.h> | |
17 | #include <linux/err.h> | |
18 | #include <linux/export.h> | |
19 | ||
20 | #include <asm/reg.h> | |
21 | #include <asm/cputable.h> | |
22 | #include <asm/tlbflush.h> | |
23 | #include <asm/kvm_ppc.h> | |
24 | #include <asm/dbell.h> | |
25 | ||
26 | #include "booke.h" | |
27 | #include "e500.h" | |
28 | ||
29 | void kvmppc_set_pending_interrupt(struct kvm_vcpu *vcpu, enum int_class type) | |
30 | { | |
31 | enum ppc_dbell dbell_type; | |
32 | unsigned long tag; | |
33 | ||
34 | switch (type) { | |
35 | case INT_CLASS_NONCRIT: | |
36 | dbell_type = PPC_G_DBELL; | |
37 | break; | |
38 | case INT_CLASS_CRIT: | |
39 | dbell_type = PPC_G_DBELL_CRIT; | |
40 | break; | |
41 | case INT_CLASS_MC: | |
42 | dbell_type = PPC_G_DBELL_MC; | |
43 | break; | |
44 | default: | |
45 | WARN_ONCE(1, "%s: unknown int type %d\n", __func__, type); | |
46 | return; | |
47 | } | |
48 | ||
49 | ||
50 | tag = PPC_DBELL_LPID(vcpu->kvm->arch.lpid) | vcpu->vcpu_id; | |
51 | mb(); | |
52 | ppc_msgsnd(dbell_type, 0, tag); | |
53 | } | |
54 | ||
55 | /* gtlbe must not be mapped by more than one host tlb entry */ | |
56 | void kvmppc_e500_tlbil_one(struct kvmppc_vcpu_e500 *vcpu_e500, | |
57 | struct kvm_book3e_206_tlb_entry *gtlbe) | |
58 | { | |
59 | unsigned int tid, ts; | |
66c9897d MC |
60 | gva_t eaddr; |
61 | u32 val, lpid; | |
73196cd3 SW |
62 | unsigned long flags; |
63 | ||
64 | ts = get_tlb_ts(gtlbe); | |
65 | tid = get_tlb_tid(gtlbe); | |
66 | lpid = vcpu_e500->vcpu.kvm->arch.lpid; | |
67 | ||
68 | /* We search the host TLB to invalidate its shadow TLB entry */ | |
69 | val = (tid << 16) | ts; | |
70 | eaddr = get_tlb_eaddr(gtlbe); | |
71 | ||
72 | local_irq_save(flags); | |
73 | ||
74 | mtspr(SPRN_MAS6, val); | |
75 | mtspr(SPRN_MAS5, MAS5_SGS | lpid); | |
76 | ||
77 | asm volatile("tlbsx 0, %[eaddr]\n" : : [eaddr] "r" (eaddr)); | |
78 | val = mfspr(SPRN_MAS1); | |
79 | if (val & MAS1_VALID) { | |
80 | mtspr(SPRN_MAS1, val & ~MAS1_VALID); | |
81 | asm volatile("tlbwe"); | |
82 | } | |
83 | mtspr(SPRN_MAS5, 0); | |
84 | /* NOTE: tlbsx also updates mas8, so clear it for host tlbwe */ | |
85 | mtspr(SPRN_MAS8, 0); | |
86 | isync(); | |
87 | ||
88 | local_irq_restore(flags); | |
89 | } | |
90 | ||
91 | void kvmppc_e500_tlbil_all(struct kvmppc_vcpu_e500 *vcpu_e500) | |
92 | { | |
93 | unsigned long flags; | |
94 | ||
95 | local_irq_save(flags); | |
96 | mtspr(SPRN_MAS5, MAS5_SGS | vcpu_e500->vcpu.kvm->arch.lpid); | |
97 | asm volatile("tlbilxlpid"); | |
98 | mtspr(SPRN_MAS5, 0); | |
99 | local_irq_restore(flags); | |
100 | } | |
101 | ||
102 | void kvmppc_set_pid(struct kvm_vcpu *vcpu, u32 pid) | |
103 | { | |
104 | vcpu->arch.pid = pid; | |
105 | } | |
106 | ||
107 | void kvmppc_mmu_msr_notify(struct kvm_vcpu *vcpu, u32 old_msr) | |
108 | { | |
109 | } | |
110 | ||
c5e6cb05 SW |
111 | static DEFINE_PER_CPU(struct kvm_vcpu *, last_vcpu_on_cpu); |
112 | ||
3a167bea | 113 | static void kvmppc_core_vcpu_load_e500mc(struct kvm_vcpu *vcpu, int cpu) |
73196cd3 SW |
114 | { |
115 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); | |
116 | ||
117 | kvmppc_booke_vcpu_load(vcpu, cpu); | |
118 | ||
119 | mtspr(SPRN_LPID, vcpu->kvm->arch.lpid); | |
120 | mtspr(SPRN_EPCR, vcpu->arch.shadow_epcr); | |
121 | mtspr(SPRN_GPIR, vcpu->vcpu_id); | |
122 | mtspr(SPRN_MSRP, vcpu->arch.shadow_msrp); | |
123 | mtspr(SPRN_EPLC, vcpu->arch.eplc); | |
124 | mtspr(SPRN_EPSC, vcpu->arch.epsc); | |
125 | ||
126 | mtspr(SPRN_GIVPR, vcpu->arch.ivpr); | |
127 | mtspr(SPRN_GIVOR2, vcpu->arch.ivor[BOOKE_IRQPRIO_DATA_STORAGE]); | |
128 | mtspr(SPRN_GIVOR8, vcpu->arch.ivor[BOOKE_IRQPRIO_SYSCALL]); | |
129 | mtspr(SPRN_GSPRG0, (unsigned long)vcpu->arch.shared->sprg0); | |
130 | mtspr(SPRN_GSPRG1, (unsigned long)vcpu->arch.shared->sprg1); | |
131 | mtspr(SPRN_GSPRG2, (unsigned long)vcpu->arch.shared->sprg2); | |
132 | mtspr(SPRN_GSPRG3, (unsigned long)vcpu->arch.shared->sprg3); | |
133 | ||
134 | mtspr(SPRN_GSRR0, vcpu->arch.shared->srr0); | |
135 | mtspr(SPRN_GSRR1, vcpu->arch.shared->srr1); | |
136 | ||
137 | mtspr(SPRN_GEPR, vcpu->arch.epr); | |
138 | mtspr(SPRN_GDEAR, vcpu->arch.shared->dar); | |
139 | mtspr(SPRN_GESR, vcpu->arch.shared->esr); | |
140 | ||
c5e6cb05 SW |
141 | if (vcpu->arch.oldpir != mfspr(SPRN_PIR) || |
142 | __get_cpu_var(last_vcpu_on_cpu) != vcpu) { | |
73196cd3 | 143 | kvmppc_e500_tlbil_all(vcpu_e500); |
c5e6cb05 SW |
144 | __get_cpu_var(last_vcpu_on_cpu) = vcpu; |
145 | } | |
73196cd3 SW |
146 | |
147 | kvmppc_load_guest_fp(vcpu); | |
148 | } | |
149 | ||
3a167bea | 150 | static void kvmppc_core_vcpu_put_e500mc(struct kvm_vcpu *vcpu) |
73196cd3 SW |
151 | { |
152 | vcpu->arch.eplc = mfspr(SPRN_EPLC); | |
153 | vcpu->arch.epsc = mfspr(SPRN_EPSC); | |
154 | ||
155 | vcpu->arch.shared->sprg0 = mfspr(SPRN_GSPRG0); | |
156 | vcpu->arch.shared->sprg1 = mfspr(SPRN_GSPRG1); | |
157 | vcpu->arch.shared->sprg2 = mfspr(SPRN_GSPRG2); | |
158 | vcpu->arch.shared->sprg3 = mfspr(SPRN_GSPRG3); | |
159 | ||
160 | vcpu->arch.shared->srr0 = mfspr(SPRN_GSRR0); | |
161 | vcpu->arch.shared->srr1 = mfspr(SPRN_GSRR1); | |
162 | ||
163 | vcpu->arch.epr = mfspr(SPRN_GEPR); | |
164 | vcpu->arch.shared->dar = mfspr(SPRN_GDEAR); | |
165 | vcpu->arch.shared->esr = mfspr(SPRN_GESR); | |
166 | ||
167 | vcpu->arch.oldpir = mfspr(SPRN_PIR); | |
168 | ||
169 | kvmppc_booke_vcpu_put(vcpu); | |
170 | } | |
171 | ||
172 | int kvmppc_core_check_processor_compat(void) | |
173 | { | |
174 | int r; | |
175 | ||
176 | if (strcmp(cur_cpu_spec->cpu_name, "e500mc") == 0) | |
177 | r = 0; | |
178 | else if (strcmp(cur_cpu_spec->cpu_name, "e5500") == 0) | |
179 | r = 0; | |
180 | else | |
181 | r = -ENOTSUPP; | |
182 | ||
183 | return r; | |
184 | } | |
185 | ||
186 | int kvmppc_core_vcpu_setup(struct kvm_vcpu *vcpu) | |
187 | { | |
188 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); | |
189 | ||
190 | vcpu->arch.shadow_epcr = SPRN_EPCR_DSIGS | SPRN_EPCR_DGTMI | \ | |
191 | SPRN_EPCR_DUVD; | |
c7ba7771 MC |
192 | #ifdef CONFIG_64BIT |
193 | vcpu->arch.shadow_epcr |= SPRN_EPCR_ICM; | |
194 | #endif | |
73196cd3 SW |
195 | vcpu->arch.shadow_msrp = MSRP_UCLEP | MSRP_DEP | MSRP_PMMP; |
196 | vcpu->arch.eplc = EPC_EGS | (vcpu->kvm->arch.lpid << EPC_ELPID_SHIFT); | |
197 | vcpu->arch.epsc = vcpu->arch.eplc; | |
198 | ||
199 | vcpu->arch.pvr = mfspr(SPRN_PVR); | |
200 | vcpu_e500->svr = mfspr(SPRN_SVR); | |
201 | ||
202 | vcpu->arch.cpu_type = KVM_CPU_E500MC; | |
203 | ||
204 | return 0; | |
205 | } | |
206 | ||
3a167bea AK |
207 | static int kvmppc_core_get_sregs_e500mc(struct kvm_vcpu *vcpu, |
208 | struct kvm_sregs *sregs) | |
73196cd3 SW |
209 | { |
210 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); | |
211 | ||
212 | sregs->u.e.features |= KVM_SREGS_E_ARCH206_MMU | KVM_SREGS_E_PM | | |
213 | KVM_SREGS_E_PC; | |
214 | sregs->u.e.impl_id = KVM_SREGS_E_IMPL_FSL; | |
215 | ||
216 | sregs->u.e.impl.fsl.features = 0; | |
217 | sregs->u.e.impl.fsl.svr = vcpu_e500->svr; | |
218 | sregs->u.e.impl.fsl.hid0 = vcpu_e500->hid0; | |
219 | sregs->u.e.impl.fsl.mcar = vcpu_e500->mcar; | |
220 | ||
221 | kvmppc_get_sregs_e500_tlb(vcpu, sregs); | |
222 | ||
223 | sregs->u.e.ivor_high[3] = | |
224 | vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR]; | |
225 | sregs->u.e.ivor_high[4] = vcpu->arch.ivor[BOOKE_IRQPRIO_DBELL]; | |
226 | sregs->u.e.ivor_high[5] = vcpu->arch.ivor[BOOKE_IRQPRIO_DBELL_CRIT]; | |
227 | ||
3a167bea | 228 | return kvmppc_get_sregs_ivor(vcpu, sregs); |
73196cd3 SW |
229 | } |
230 | ||
3a167bea AK |
231 | static int kvmppc_core_set_sregs_e500mc(struct kvm_vcpu *vcpu, |
232 | struct kvm_sregs *sregs) | |
73196cd3 SW |
233 | { |
234 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); | |
235 | int ret; | |
236 | ||
237 | if (sregs->u.e.impl_id == KVM_SREGS_E_IMPL_FSL) { | |
238 | vcpu_e500->svr = sregs->u.e.impl.fsl.svr; | |
239 | vcpu_e500->hid0 = sregs->u.e.impl.fsl.hid0; | |
240 | vcpu_e500->mcar = sregs->u.e.impl.fsl.mcar; | |
241 | } | |
242 | ||
243 | ret = kvmppc_set_sregs_e500_tlb(vcpu, sregs); | |
244 | if (ret < 0) | |
245 | return ret; | |
246 | ||
247 | if (!(sregs->u.e.features & KVM_SREGS_E_IVOR)) | |
248 | return 0; | |
249 | ||
250 | if (sregs->u.e.features & KVM_SREGS_E_PM) { | |
251 | vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR] = | |
252 | sregs->u.e.ivor_high[3]; | |
253 | } | |
254 | ||
255 | if (sregs->u.e.features & KVM_SREGS_E_PC) { | |
256 | vcpu->arch.ivor[BOOKE_IRQPRIO_DBELL] = | |
257 | sregs->u.e.ivor_high[4]; | |
258 | vcpu->arch.ivor[BOOKE_IRQPRIO_DBELL_CRIT] = | |
259 | sregs->u.e.ivor_high[5]; | |
260 | } | |
261 | ||
262 | return kvmppc_set_sregs_ivor(vcpu, sregs); | |
263 | } | |
264 | ||
3a167bea AK |
265 | static int kvmppc_get_one_reg_e500mc(struct kvm_vcpu *vcpu, u64 id, |
266 | union kvmppc_one_reg *val) | |
35b299e2 | 267 | { |
a85d2aa2 MC |
268 | int r = kvmppc_get_one_reg_e500_tlb(vcpu, id, val); |
269 | return r; | |
35b299e2 MC |
270 | } |
271 | ||
3a167bea AK |
272 | static int kvmppc_set_one_reg_e500mc(struct kvm_vcpu *vcpu, u64 id, |
273 | union kvmppc_one_reg *val) | |
35b299e2 | 274 | { |
a85d2aa2 MC |
275 | int r = kvmppc_set_one_reg_e500_tlb(vcpu, id, val); |
276 | return r; | |
35b299e2 MC |
277 | } |
278 | ||
3a167bea AK |
279 | static struct kvm_vcpu *kvmppc_core_vcpu_create_e500mc(struct kvm *kvm, |
280 | unsigned int id) | |
73196cd3 SW |
281 | { |
282 | struct kvmppc_vcpu_e500 *vcpu_e500; | |
283 | struct kvm_vcpu *vcpu; | |
284 | int err; | |
285 | ||
286 | vcpu_e500 = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL); | |
287 | if (!vcpu_e500) { | |
288 | err = -ENOMEM; | |
289 | goto out; | |
290 | } | |
291 | vcpu = &vcpu_e500->vcpu; | |
292 | ||
293 | /* Invalid PIR value -- this LPID dosn't have valid state on any cpu */ | |
294 | vcpu->arch.oldpir = 0xffffffff; | |
295 | ||
296 | err = kvm_vcpu_init(vcpu, kvm, id); | |
297 | if (err) | |
298 | goto free_vcpu; | |
299 | ||
300 | err = kvmppc_e500_tlb_init(vcpu_e500); | |
301 | if (err) | |
302 | goto uninit_vcpu; | |
303 | ||
304 | vcpu->arch.shared = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); | |
305 | if (!vcpu->arch.shared) | |
306 | goto uninit_tlb; | |
307 | ||
308 | return vcpu; | |
309 | ||
310 | uninit_tlb: | |
311 | kvmppc_e500_tlb_uninit(vcpu_e500); | |
312 | uninit_vcpu: | |
313 | kvm_vcpu_uninit(vcpu); | |
314 | ||
315 | free_vcpu: | |
316 | kmem_cache_free(kvm_vcpu_cache, vcpu_e500); | |
317 | out: | |
318 | return ERR_PTR(err); | |
319 | } | |
320 | ||
3a167bea | 321 | static void kvmppc_core_vcpu_free_e500mc(struct kvm_vcpu *vcpu) |
73196cd3 SW |
322 | { |
323 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); | |
324 | ||
325 | free_page((unsigned long)vcpu->arch.shared); | |
326 | kvmppc_e500_tlb_uninit(vcpu_e500); | |
327 | kvm_vcpu_uninit(vcpu); | |
328 | kmem_cache_free(kvm_vcpu_cache, vcpu_e500); | |
329 | } | |
330 | ||
3a167bea | 331 | static int kvmppc_core_init_vm_e500mc(struct kvm *kvm) |
73196cd3 SW |
332 | { |
333 | int lpid; | |
334 | ||
335 | lpid = kvmppc_alloc_lpid(); | |
336 | if (lpid < 0) | |
337 | return lpid; | |
338 | ||
339 | kvm->arch.lpid = lpid; | |
340 | return 0; | |
341 | } | |
342 | ||
3a167bea | 343 | static void kvmppc_core_destroy_vm_e500mc(struct kvm *kvm) |
73196cd3 SW |
344 | { |
345 | kvmppc_free_lpid(kvm->arch.lpid); | |
346 | } | |
347 | ||
3a167bea AK |
348 | static struct kvmppc_ops kvm_ops_e500mc = { |
349 | .get_sregs = kvmppc_core_get_sregs_e500mc, | |
350 | .set_sregs = kvmppc_core_set_sregs_e500mc, | |
351 | .get_one_reg = kvmppc_get_one_reg_e500mc, | |
352 | .set_one_reg = kvmppc_set_one_reg_e500mc, | |
353 | .vcpu_load = kvmppc_core_vcpu_load_e500mc, | |
354 | .vcpu_put = kvmppc_core_vcpu_put_e500mc, | |
355 | .vcpu_create = kvmppc_core_vcpu_create_e500mc, | |
356 | .vcpu_free = kvmppc_core_vcpu_free_e500mc, | |
357 | .mmu_destroy = kvmppc_mmu_destroy_e500, | |
358 | .init_vm = kvmppc_core_init_vm_e500mc, | |
359 | .destroy_vm = kvmppc_core_destroy_vm_e500mc, | |
360 | .emulate_op = kvmppc_core_emulate_op_e500, | |
361 | .emulate_mtspr = kvmppc_core_emulate_mtspr_e500, | |
362 | .emulate_mfspr = kvmppc_core_emulate_mfspr_e500, | |
363 | }; | |
364 | ||
73196cd3 SW |
365 | static int __init kvmppc_e500mc_init(void) |
366 | { | |
367 | int r; | |
368 | ||
369 | r = kvmppc_booke_init(); | |
370 | if (r) | |
3a167bea | 371 | goto err_out; |
73196cd3 SW |
372 | |
373 | kvmppc_init_lpid(64); | |
374 | kvmppc_claim_lpid(0); /* host */ | |
375 | ||
3a167bea AK |
376 | r = kvm_init(&kvm_ops_e500mc, sizeof(struct kvmppc_vcpu_e500), 0, THIS_MODULE); |
377 | if (r) | |
378 | goto err_out; | |
379 | err_out: | |
380 | return r; | |
73196cd3 SW |
381 | } |
382 | ||
383 | static void __exit kvmppc_e500mc_exit(void) | |
384 | { | |
385 | kvmppc_booke_exit(); | |
386 | } | |
387 | ||
388 | module_init(kvmppc_e500mc_init); | |
389 | module_exit(kvmppc_e500mc_exit); |