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 | ||
111 | void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu) | |
112 | { | |
113 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); | |
114 | ||
115 | kvmppc_booke_vcpu_load(vcpu, cpu); | |
116 | ||
117 | mtspr(SPRN_LPID, vcpu->kvm->arch.lpid); | |
118 | mtspr(SPRN_EPCR, vcpu->arch.shadow_epcr); | |
119 | mtspr(SPRN_GPIR, vcpu->vcpu_id); | |
120 | mtspr(SPRN_MSRP, vcpu->arch.shadow_msrp); | |
121 | mtspr(SPRN_EPLC, vcpu->arch.eplc); | |
122 | mtspr(SPRN_EPSC, vcpu->arch.epsc); | |
123 | ||
124 | mtspr(SPRN_GIVPR, vcpu->arch.ivpr); | |
125 | mtspr(SPRN_GIVOR2, vcpu->arch.ivor[BOOKE_IRQPRIO_DATA_STORAGE]); | |
126 | mtspr(SPRN_GIVOR8, vcpu->arch.ivor[BOOKE_IRQPRIO_SYSCALL]); | |
127 | mtspr(SPRN_GSPRG0, (unsigned long)vcpu->arch.shared->sprg0); | |
128 | mtspr(SPRN_GSPRG1, (unsigned long)vcpu->arch.shared->sprg1); | |
129 | mtspr(SPRN_GSPRG2, (unsigned long)vcpu->arch.shared->sprg2); | |
130 | mtspr(SPRN_GSPRG3, (unsigned long)vcpu->arch.shared->sprg3); | |
131 | ||
132 | mtspr(SPRN_GSRR0, vcpu->arch.shared->srr0); | |
133 | mtspr(SPRN_GSRR1, vcpu->arch.shared->srr1); | |
134 | ||
135 | mtspr(SPRN_GEPR, vcpu->arch.epr); | |
136 | mtspr(SPRN_GDEAR, vcpu->arch.shared->dar); | |
137 | mtspr(SPRN_GESR, vcpu->arch.shared->esr); | |
138 | ||
139 | if (vcpu->arch.oldpir != mfspr(SPRN_PIR)) | |
140 | kvmppc_e500_tlbil_all(vcpu_e500); | |
141 | ||
142 | kvmppc_load_guest_fp(vcpu); | |
143 | } | |
144 | ||
145 | void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu) | |
146 | { | |
147 | vcpu->arch.eplc = mfspr(SPRN_EPLC); | |
148 | vcpu->arch.epsc = mfspr(SPRN_EPSC); | |
149 | ||
150 | vcpu->arch.shared->sprg0 = mfspr(SPRN_GSPRG0); | |
151 | vcpu->arch.shared->sprg1 = mfspr(SPRN_GSPRG1); | |
152 | vcpu->arch.shared->sprg2 = mfspr(SPRN_GSPRG2); | |
153 | vcpu->arch.shared->sprg3 = mfspr(SPRN_GSPRG3); | |
154 | ||
155 | vcpu->arch.shared->srr0 = mfspr(SPRN_GSRR0); | |
156 | vcpu->arch.shared->srr1 = mfspr(SPRN_GSRR1); | |
157 | ||
158 | vcpu->arch.epr = mfspr(SPRN_GEPR); | |
159 | vcpu->arch.shared->dar = mfspr(SPRN_GDEAR); | |
160 | vcpu->arch.shared->esr = mfspr(SPRN_GESR); | |
161 | ||
162 | vcpu->arch.oldpir = mfspr(SPRN_PIR); | |
163 | ||
164 | kvmppc_booke_vcpu_put(vcpu); | |
165 | } | |
166 | ||
167 | int kvmppc_core_check_processor_compat(void) | |
168 | { | |
169 | int r; | |
170 | ||
171 | if (strcmp(cur_cpu_spec->cpu_name, "e500mc") == 0) | |
172 | r = 0; | |
173 | else if (strcmp(cur_cpu_spec->cpu_name, "e5500") == 0) | |
174 | r = 0; | |
175 | else | |
176 | r = -ENOTSUPP; | |
177 | ||
178 | return r; | |
179 | } | |
180 | ||
181 | int kvmppc_core_vcpu_setup(struct kvm_vcpu *vcpu) | |
182 | { | |
183 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); | |
184 | ||
185 | vcpu->arch.shadow_epcr = SPRN_EPCR_DSIGS | SPRN_EPCR_DGTMI | \ | |
186 | SPRN_EPCR_DUVD; | |
c7ba7771 MC |
187 | #ifdef CONFIG_64BIT |
188 | vcpu->arch.shadow_epcr |= SPRN_EPCR_ICM; | |
189 | #endif | |
73196cd3 SW |
190 | vcpu->arch.shadow_msrp = MSRP_UCLEP | MSRP_DEP | MSRP_PMMP; |
191 | vcpu->arch.eplc = EPC_EGS | (vcpu->kvm->arch.lpid << EPC_ELPID_SHIFT); | |
192 | vcpu->arch.epsc = vcpu->arch.eplc; | |
193 | ||
194 | vcpu->arch.pvr = mfspr(SPRN_PVR); | |
195 | vcpu_e500->svr = mfspr(SPRN_SVR); | |
196 | ||
197 | vcpu->arch.cpu_type = KVM_CPU_E500MC; | |
198 | ||
199 | return 0; | |
200 | } | |
201 | ||
202 | void kvmppc_core_get_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) | |
203 | { | |
204 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); | |
205 | ||
206 | sregs->u.e.features |= KVM_SREGS_E_ARCH206_MMU | KVM_SREGS_E_PM | | |
207 | KVM_SREGS_E_PC; | |
208 | sregs->u.e.impl_id = KVM_SREGS_E_IMPL_FSL; | |
209 | ||
210 | sregs->u.e.impl.fsl.features = 0; | |
211 | sregs->u.e.impl.fsl.svr = vcpu_e500->svr; | |
212 | sregs->u.e.impl.fsl.hid0 = vcpu_e500->hid0; | |
213 | sregs->u.e.impl.fsl.mcar = vcpu_e500->mcar; | |
214 | ||
215 | kvmppc_get_sregs_e500_tlb(vcpu, sregs); | |
216 | ||
217 | sregs->u.e.ivor_high[3] = | |
218 | vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR]; | |
219 | sregs->u.e.ivor_high[4] = vcpu->arch.ivor[BOOKE_IRQPRIO_DBELL]; | |
220 | sregs->u.e.ivor_high[5] = vcpu->arch.ivor[BOOKE_IRQPRIO_DBELL_CRIT]; | |
221 | ||
222 | kvmppc_get_sregs_ivor(vcpu, sregs); | |
223 | } | |
224 | ||
225 | int kvmppc_core_set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs) | |
226 | { | |
227 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); | |
228 | int ret; | |
229 | ||
230 | if (sregs->u.e.impl_id == KVM_SREGS_E_IMPL_FSL) { | |
231 | vcpu_e500->svr = sregs->u.e.impl.fsl.svr; | |
232 | vcpu_e500->hid0 = sregs->u.e.impl.fsl.hid0; | |
233 | vcpu_e500->mcar = sregs->u.e.impl.fsl.mcar; | |
234 | } | |
235 | ||
236 | ret = kvmppc_set_sregs_e500_tlb(vcpu, sregs); | |
237 | if (ret < 0) | |
238 | return ret; | |
239 | ||
240 | if (!(sregs->u.e.features & KVM_SREGS_E_IVOR)) | |
241 | return 0; | |
242 | ||
243 | if (sregs->u.e.features & KVM_SREGS_E_PM) { | |
244 | vcpu->arch.ivor[BOOKE_IRQPRIO_PERFORMANCE_MONITOR] = | |
245 | sregs->u.e.ivor_high[3]; | |
246 | } | |
247 | ||
248 | if (sregs->u.e.features & KVM_SREGS_E_PC) { | |
249 | vcpu->arch.ivor[BOOKE_IRQPRIO_DBELL] = | |
250 | sregs->u.e.ivor_high[4]; | |
251 | vcpu->arch.ivor[BOOKE_IRQPRIO_DBELL_CRIT] = | |
252 | sregs->u.e.ivor_high[5]; | |
253 | } | |
254 | ||
255 | return kvmppc_set_sregs_ivor(vcpu, sregs); | |
256 | } | |
257 | ||
258 | struct kvm_vcpu *kvmppc_core_vcpu_create(struct kvm *kvm, unsigned int id) | |
259 | { | |
260 | struct kvmppc_vcpu_e500 *vcpu_e500; | |
261 | struct kvm_vcpu *vcpu; | |
262 | int err; | |
263 | ||
264 | vcpu_e500 = kmem_cache_zalloc(kvm_vcpu_cache, GFP_KERNEL); | |
265 | if (!vcpu_e500) { | |
266 | err = -ENOMEM; | |
267 | goto out; | |
268 | } | |
269 | vcpu = &vcpu_e500->vcpu; | |
270 | ||
271 | /* Invalid PIR value -- this LPID dosn't have valid state on any cpu */ | |
272 | vcpu->arch.oldpir = 0xffffffff; | |
273 | ||
274 | err = kvm_vcpu_init(vcpu, kvm, id); | |
275 | if (err) | |
276 | goto free_vcpu; | |
277 | ||
278 | err = kvmppc_e500_tlb_init(vcpu_e500); | |
279 | if (err) | |
280 | goto uninit_vcpu; | |
281 | ||
282 | vcpu->arch.shared = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); | |
283 | if (!vcpu->arch.shared) | |
284 | goto uninit_tlb; | |
285 | ||
286 | return vcpu; | |
287 | ||
288 | uninit_tlb: | |
289 | kvmppc_e500_tlb_uninit(vcpu_e500); | |
290 | uninit_vcpu: | |
291 | kvm_vcpu_uninit(vcpu); | |
292 | ||
293 | free_vcpu: | |
294 | kmem_cache_free(kvm_vcpu_cache, vcpu_e500); | |
295 | out: | |
296 | return ERR_PTR(err); | |
297 | } | |
298 | ||
299 | void kvmppc_core_vcpu_free(struct kvm_vcpu *vcpu) | |
300 | { | |
301 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); | |
302 | ||
303 | free_page((unsigned long)vcpu->arch.shared); | |
304 | kvmppc_e500_tlb_uninit(vcpu_e500); | |
305 | kvm_vcpu_uninit(vcpu); | |
306 | kmem_cache_free(kvm_vcpu_cache, vcpu_e500); | |
307 | } | |
308 | ||
309 | int kvmppc_core_init_vm(struct kvm *kvm) | |
310 | { | |
311 | int lpid; | |
312 | ||
313 | lpid = kvmppc_alloc_lpid(); | |
314 | if (lpid < 0) | |
315 | return lpid; | |
316 | ||
317 | kvm->arch.lpid = lpid; | |
318 | return 0; | |
319 | } | |
320 | ||
321 | void kvmppc_core_destroy_vm(struct kvm *kvm) | |
322 | { | |
323 | kvmppc_free_lpid(kvm->arch.lpid); | |
324 | } | |
325 | ||
326 | static int __init kvmppc_e500mc_init(void) | |
327 | { | |
328 | int r; | |
329 | ||
330 | r = kvmppc_booke_init(); | |
331 | if (r) | |
332 | return r; | |
333 | ||
334 | kvmppc_init_lpid(64); | |
335 | kvmppc_claim_lpid(0); /* host */ | |
336 | ||
337 | return kvm_init(NULL, sizeof(struct kvmppc_vcpu_e500), 0, THIS_MODULE); | |
338 | } | |
339 | ||
340 | static void __exit kvmppc_e500mc_exit(void) | |
341 | { | |
342 | kvmppc_booke_exit(); | |
343 | } | |
344 | ||
345 | module_init(kvmppc_e500mc_init); | |
346 | module_exit(kvmppc_e500mc_exit); |