diff options
author | Scott Wood <scottwood@freescale.com> | 2013-03-06 11:02:49 -0500 |
---|---|---|
committer | Alexander Graf <agraf@suse.de> | 2013-04-11 09:53:43 -0400 |
commit | 4d2be6f7c75e814ee28b007dbf0c26dfcbbe20a1 (patch) | |
tree | 59bbb188fed8951f6aa7e0ff4d326755aaaa8f1b /arch/powerpc | |
parent | 66a5fecdccd4f32a22d2d110cf4f002755b520d8 (diff) |
kvm/ppc/e500: eliminate tlb_refs
Commit 523f0e5421c12610527c620b983b443f329e3a32 ("KVM: PPC: E500:
Explicitly mark shadow maps invalid") began using E500_TLB_VALID
for guest TLB1 entries, and skipping invalidations if it's not set.
However, when E500_TLB_VALID was set for such entries, it was on a
fake local ref, and so the invalidations never happen. gtlb_privs
is documented as being only for guest TLB0, though we already violate
that with E500_TLB_BITMAP.
Now that we have MMU notifiers, and thus don't need to actually
retain a reference to the mapped pages, get rid of tlb_refs, and
use gtlb_privs for E500_TLB_VALID in TLB1.
Since we can have more than one host TLB entry for a given tlbe_ref,
be careful not to clear existing flags that are relevant to other
host TLB entries when preparing a new host TLB entry.
Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/kvm/e500.h | 24 | ||||
-rw-r--r-- | arch/powerpc/kvm/e500_mmu_host.c | 75 |
2 files changed, 30 insertions, 69 deletions
diff --git a/arch/powerpc/kvm/e500.h b/arch/powerpc/kvm/e500.h index 41cefd43655f..33db48a8ce24 100644 --- a/arch/powerpc/kvm/e500.h +++ b/arch/powerpc/kvm/e500.h | |||
@@ -26,17 +26,20 @@ | |||
26 | #define E500_PID_NUM 3 | 26 | #define E500_PID_NUM 3 |
27 | #define E500_TLB_NUM 2 | 27 | #define E500_TLB_NUM 2 |
28 | 28 | ||
29 | #define E500_TLB_VALID 1 | 29 | /* entry is mapped somewhere in host TLB */ |
30 | #define E500_TLB_BITMAP 2 | 30 | #define E500_TLB_VALID (1 << 0) |
31 | /* TLB1 entry is mapped by host TLB1, tracked by bitmaps */ | ||
32 | #define E500_TLB_BITMAP (1 << 1) | ||
33 | /* TLB1 entry is mapped by host TLB0 */ | ||
31 | #define E500_TLB_TLB0 (1 << 2) | 34 | #define E500_TLB_TLB0 (1 << 2) |
32 | 35 | ||
33 | struct tlbe_ref { | 36 | struct tlbe_ref { |
34 | pfn_t pfn; | 37 | pfn_t pfn; /* valid only for TLB0, except briefly */ |
35 | unsigned int flags; /* E500_TLB_* */ | 38 | unsigned int flags; /* E500_TLB_* */ |
36 | }; | 39 | }; |
37 | 40 | ||
38 | struct tlbe_priv { | 41 | struct tlbe_priv { |
39 | struct tlbe_ref ref; /* TLB0 only -- TLB1 uses tlb_refs */ | 42 | struct tlbe_ref ref; |
40 | }; | 43 | }; |
41 | 44 | ||
42 | #ifdef CONFIG_KVM_E500V2 | 45 | #ifdef CONFIG_KVM_E500V2 |
@@ -63,17 +66,6 @@ struct kvmppc_vcpu_e500 { | |||
63 | 66 | ||
64 | unsigned int gtlb_nv[E500_TLB_NUM]; | 67 | unsigned int gtlb_nv[E500_TLB_NUM]; |
65 | 68 | ||
66 | /* | ||
67 | * information associated with each host TLB entry -- | ||
68 | * TLB1 only for now. If/when guest TLB1 entries can be | ||
69 | * mapped with host TLB0, this will be used for that too. | ||
70 | * | ||
71 | * We don't want to use this for guest TLB0 because then we'd | ||
72 | * have the overhead of doing the translation again even if | ||
73 | * the entry is still in the guest TLB (e.g. we swapped out | ||
74 | * and back, and our host TLB entries got evicted). | ||
75 | */ | ||
76 | struct tlbe_ref *tlb_refs[E500_TLB_NUM]; | ||
77 | unsigned int host_tlb1_nv; | 69 | unsigned int host_tlb1_nv; |
78 | 70 | ||
79 | u32 svr; | 71 | u32 svr; |
diff --git a/arch/powerpc/kvm/e500_mmu_host.c b/arch/powerpc/kvm/e500_mmu_host.c index 8e72b2124f63..1c6a9d729df4 100644 --- a/arch/powerpc/kvm/e500_mmu_host.c +++ b/arch/powerpc/kvm/e500_mmu_host.c | |||
@@ -193,8 +193,11 @@ void inval_gtlbe_on_host(struct kvmppc_vcpu_e500 *vcpu_e500, int tlbsel, | |||
193 | struct tlbe_ref *ref = &vcpu_e500->gtlb_priv[tlbsel][esel].ref; | 193 | struct tlbe_ref *ref = &vcpu_e500->gtlb_priv[tlbsel][esel].ref; |
194 | 194 | ||
195 | /* Don't bother with unmapped entries */ | 195 | /* Don't bother with unmapped entries */ |
196 | if (!(ref->flags & E500_TLB_VALID)) | 196 | if (!(ref->flags & E500_TLB_VALID)) { |
197 | return; | 197 | WARN(ref->flags & (E500_TLB_BITMAP | E500_TLB_TLB0), |
198 | "%s: flags %x\n", __func__, ref->flags); | ||
199 | WARN_ON(tlbsel == 1 && vcpu_e500->g2h_tlb1_map[esel]); | ||
200 | } | ||
198 | 201 | ||
199 | if (tlbsel == 1 && ref->flags & E500_TLB_BITMAP) { | 202 | if (tlbsel == 1 && ref->flags & E500_TLB_BITMAP) { |
200 | u64 tmp = vcpu_e500->g2h_tlb1_map[esel]; | 203 | u64 tmp = vcpu_e500->g2h_tlb1_map[esel]; |
@@ -248,7 +251,7 @@ static inline void kvmppc_e500_ref_setup(struct tlbe_ref *ref, | |||
248 | pfn_t pfn) | 251 | pfn_t pfn) |
249 | { | 252 | { |
250 | ref->pfn = pfn; | 253 | ref->pfn = pfn; |
251 | ref->flags = E500_TLB_VALID; | 254 | ref->flags |= E500_TLB_VALID; |
252 | 255 | ||
253 | if (tlbe_is_writable(gtlbe)) | 256 | if (tlbe_is_writable(gtlbe)) |
254 | kvm_set_pfn_dirty(pfn); | 257 | kvm_set_pfn_dirty(pfn); |
@@ -257,6 +260,7 @@ static inline void kvmppc_e500_ref_setup(struct tlbe_ref *ref, | |||
257 | static inline void kvmppc_e500_ref_release(struct tlbe_ref *ref) | 260 | static inline void kvmppc_e500_ref_release(struct tlbe_ref *ref) |
258 | { | 261 | { |
259 | if (ref->flags & E500_TLB_VALID) { | 262 | if (ref->flags & E500_TLB_VALID) { |
263 | /* FIXME: don't log bogus pfn for TLB1 */ | ||
260 | trace_kvm_booke206_ref_release(ref->pfn, ref->flags); | 264 | trace_kvm_booke206_ref_release(ref->pfn, ref->flags); |
261 | ref->flags = 0; | 265 | ref->flags = 0; |
262 | } | 266 | } |
@@ -274,36 +278,23 @@ static void clear_tlb1_bitmap(struct kvmppc_vcpu_e500 *vcpu_e500) | |||
274 | 278 | ||
275 | static void clear_tlb_privs(struct kvmppc_vcpu_e500 *vcpu_e500) | 279 | static void clear_tlb_privs(struct kvmppc_vcpu_e500 *vcpu_e500) |
276 | { | 280 | { |
277 | int tlbsel = 0; | 281 | int tlbsel; |
278 | int i; | ||
279 | |||
280 | for (i = 0; i < vcpu_e500->gtlb_params[tlbsel].entries; i++) { | ||
281 | struct tlbe_ref *ref = | ||
282 | &vcpu_e500->gtlb_priv[tlbsel][i].ref; | ||
283 | kvmppc_e500_ref_release(ref); | ||
284 | } | ||
285 | } | ||
286 | |||
287 | static void clear_tlb_refs(struct kvmppc_vcpu_e500 *vcpu_e500) | ||
288 | { | ||
289 | int stlbsel = 1; | ||
290 | int i; | 282 | int i; |
291 | 283 | ||
292 | kvmppc_e500_tlbil_all(vcpu_e500); | 284 | for (tlbsel = 0; tlbsel <= 1; tlbsel++) { |
293 | 285 | for (i = 0; i < vcpu_e500->gtlb_params[tlbsel].entries; i++) { | |
294 | for (i = 0; i < host_tlb_params[stlbsel].entries; i++) { | 286 | struct tlbe_ref *ref = |
295 | struct tlbe_ref *ref = | 287 | &vcpu_e500->gtlb_priv[tlbsel][i].ref; |
296 | &vcpu_e500->tlb_refs[stlbsel][i]; | 288 | kvmppc_e500_ref_release(ref); |
297 | kvmppc_e500_ref_release(ref); | 289 | } |
298 | } | 290 | } |
299 | |||
300 | clear_tlb_privs(vcpu_e500); | ||
301 | } | 291 | } |
302 | 292 | ||
303 | void kvmppc_core_flush_tlb(struct kvm_vcpu *vcpu) | 293 | void kvmppc_core_flush_tlb(struct kvm_vcpu *vcpu) |
304 | { | 294 | { |
305 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); | 295 | struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu); |
306 | clear_tlb_refs(vcpu_e500); | 296 | kvmppc_e500_tlbil_all(vcpu_e500); |
297 | clear_tlb_privs(vcpu_e500); | ||
307 | clear_tlb1_bitmap(vcpu_e500); | 298 | clear_tlb1_bitmap(vcpu_e500); |
308 | } | 299 | } |
309 | 300 | ||
@@ -458,8 +449,6 @@ static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500, | |||
458 | gvaddr &= ~((tsize_pages << PAGE_SHIFT) - 1); | 449 | gvaddr &= ~((tsize_pages << PAGE_SHIFT) - 1); |
459 | } | 450 | } |
460 | 451 | ||
461 | /* Drop old ref and setup new one. */ | ||
462 | kvmppc_e500_ref_release(ref); | ||
463 | kvmppc_e500_ref_setup(ref, gtlbe, pfn); | 452 | kvmppc_e500_ref_setup(ref, gtlbe, pfn); |
464 | 453 | ||
465 | kvmppc_e500_setup_stlbe(&vcpu_e500->vcpu, gtlbe, tsize, | 454 | kvmppc_e500_setup_stlbe(&vcpu_e500->vcpu, gtlbe, tsize, |
@@ -512,10 +501,10 @@ static int kvmppc_e500_tlb1_map_tlb1(struct kvmppc_vcpu_e500 *vcpu_e500, | |||
512 | vcpu_e500->g2h_tlb1_map[idx] &= ~(1ULL << sesel); | 501 | vcpu_e500->g2h_tlb1_map[idx] &= ~(1ULL << sesel); |
513 | } | 502 | } |
514 | 503 | ||
515 | vcpu_e500->tlb_refs[1][sesel] = *ref; | ||
516 | vcpu_e500->gtlb_priv[1][esel].ref.flags |= E500_TLB_BITMAP; | 504 | vcpu_e500->gtlb_priv[1][esel].ref.flags |= E500_TLB_BITMAP; |
517 | vcpu_e500->g2h_tlb1_map[esel] |= (u64)1 << sesel; | 505 | vcpu_e500->g2h_tlb1_map[esel] |= (u64)1 << sesel; |
518 | vcpu_e500->h2g_tlb1_rmap[sesel] = esel + 1; | 506 | vcpu_e500->h2g_tlb1_rmap[sesel] = esel + 1; |
507 | WARN_ON(!(ref->flags & E500_TLB_VALID)); | ||
519 | 508 | ||
520 | return sesel; | 509 | return sesel; |
521 | } | 510 | } |
@@ -527,13 +516,12 @@ static int kvmppc_e500_tlb1_map(struct kvmppc_vcpu_e500 *vcpu_e500, | |||
527 | u64 gvaddr, gfn_t gfn, struct kvm_book3e_206_tlb_entry *gtlbe, | 516 | u64 gvaddr, gfn_t gfn, struct kvm_book3e_206_tlb_entry *gtlbe, |
528 | struct kvm_book3e_206_tlb_entry *stlbe, int esel) | 517 | struct kvm_book3e_206_tlb_entry *stlbe, int esel) |
529 | { | 518 | { |
530 | struct tlbe_ref ref; | 519 | struct tlbe_ref *ref = &vcpu_e500->gtlb_priv[1][esel].ref; |
531 | int sesel; | 520 | int sesel; |
532 | int r; | 521 | int r; |
533 | 522 | ||
534 | ref.flags = 0; | ||
535 | r = kvmppc_e500_shadow_map(vcpu_e500, gvaddr, gfn, gtlbe, 1, stlbe, | 523 | r = kvmppc_e500_shadow_map(vcpu_e500, gvaddr, gfn, gtlbe, 1, stlbe, |
536 | &ref); | 524 | ref); |
537 | if (r) | 525 | if (r) |
538 | return r; | 526 | return r; |
539 | 527 | ||
@@ -545,7 +533,7 @@ static int kvmppc_e500_tlb1_map(struct kvmppc_vcpu_e500 *vcpu_e500, | |||
545 | } | 533 | } |
546 | 534 | ||
547 | /* Otherwise map into TLB1 */ | 535 | /* Otherwise map into TLB1 */ |
548 | sesel = kvmppc_e500_tlb1_map_tlb1(vcpu_e500, &ref, esel); | 536 | sesel = kvmppc_e500_tlb1_map_tlb1(vcpu_e500, ref, esel); |
549 | write_stlbe(vcpu_e500, gtlbe, stlbe, 1, sesel); | 537 | write_stlbe(vcpu_e500, gtlbe, stlbe, 1, sesel); |
550 | 538 | ||
551 | return 0; | 539 | return 0; |
@@ -566,7 +554,7 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 eaddr, gpa_t gpaddr, | |||
566 | case 0: | 554 | case 0: |
567 | priv = &vcpu_e500->gtlb_priv[tlbsel][esel]; | 555 | priv = &vcpu_e500->gtlb_priv[tlbsel][esel]; |
568 | 556 | ||
569 | /* Triggers after clear_tlb_refs or on initial mapping */ | 557 | /* Triggers after clear_tlb_privs or on initial mapping */ |
570 | if (!(priv->ref.flags & E500_TLB_VALID)) { | 558 | if (!(priv->ref.flags & E500_TLB_VALID)) { |
571 | kvmppc_e500_tlb0_map(vcpu_e500, esel, &stlbe); | 559 | kvmppc_e500_tlb0_map(vcpu_e500, esel, &stlbe); |
572 | } else { | 560 | } else { |
@@ -666,35 +654,16 @@ int e500_mmu_host_init(struct kvmppc_vcpu_e500 *vcpu_e500) | |||
666 | host_tlb_params[0].entries / host_tlb_params[0].ways; | 654 | host_tlb_params[0].entries / host_tlb_params[0].ways; |
667 | host_tlb_params[1].sets = 1; | 655 | host_tlb_params[1].sets = 1; |
668 | 656 | ||
669 | vcpu_e500->tlb_refs[0] = | ||
670 | kzalloc(sizeof(struct tlbe_ref) * host_tlb_params[0].entries, | ||
671 | GFP_KERNEL); | ||
672 | if (!vcpu_e500->tlb_refs[0]) | ||
673 | goto err; | ||
674 | |||
675 | vcpu_e500->tlb_refs[1] = | ||
676 | kzalloc(sizeof(struct tlbe_ref) * host_tlb_params[1].entries, | ||
677 | GFP_KERNEL); | ||
678 | if (!vcpu_e500->tlb_refs[1]) | ||
679 | goto err; | ||
680 | |||
681 | vcpu_e500->h2g_tlb1_rmap = kzalloc(sizeof(unsigned int) * | 657 | vcpu_e500->h2g_tlb1_rmap = kzalloc(sizeof(unsigned int) * |
682 | host_tlb_params[1].entries, | 658 | host_tlb_params[1].entries, |
683 | GFP_KERNEL); | 659 | GFP_KERNEL); |
684 | if (!vcpu_e500->h2g_tlb1_rmap) | 660 | if (!vcpu_e500->h2g_tlb1_rmap) |
685 | goto err; | 661 | return -EINVAL; |
686 | 662 | ||
687 | return 0; | 663 | return 0; |
688 | |||
689 | err: | ||
690 | kfree(vcpu_e500->tlb_refs[0]); | ||
691 | kfree(vcpu_e500->tlb_refs[1]); | ||
692 | return -EINVAL; | ||
693 | } | 664 | } |
694 | 665 | ||
695 | void e500_mmu_host_uninit(struct kvmppc_vcpu_e500 *vcpu_e500) | 666 | void e500_mmu_host_uninit(struct kvmppc_vcpu_e500 *vcpu_e500) |
696 | { | 667 | { |
697 | kfree(vcpu_e500->h2g_tlb1_rmap); | 668 | kfree(vcpu_e500->h2g_tlb1_rmap); |
698 | kfree(vcpu_e500->tlb_refs[0]); | ||
699 | kfree(vcpu_e500->tlb_refs[1]); | ||
700 | } | 669 | } |