diff options
| -rw-r--r-- | arch/powerpc/kvm/e500_tlb.c | 69 |
1 files changed, 41 insertions, 28 deletions
diff --git a/arch/powerpc/kvm/e500_tlb.c b/arch/powerpc/kvm/e500_tlb.c index 8efb2acee2bf..3777167e5f31 100644 --- a/arch/powerpc/kvm/e500_tlb.c +++ b/arch/powerpc/kvm/e500_tlb.c | |||
| @@ -432,7 +432,7 @@ static inline void kvmppc_e500_setup_stlbe( | |||
| 432 | #endif | 432 | #endif |
| 433 | } | 433 | } |
| 434 | 434 | ||
| 435 | static inline void kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500, | 435 | static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500, |
| 436 | u64 gvaddr, gfn_t gfn, struct kvm_book3e_206_tlb_entry *gtlbe, | 436 | u64 gvaddr, gfn_t gfn, struct kvm_book3e_206_tlb_entry *gtlbe, |
| 437 | int tlbsel, struct kvm_book3e_206_tlb_entry *stlbe, | 437 | int tlbsel, struct kvm_book3e_206_tlb_entry *stlbe, |
| 438 | struct tlbe_ref *ref) | 438 | struct tlbe_ref *ref) |
| @@ -551,7 +551,7 @@ static inline void kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500, | |||
| 551 | if (is_error_noslot_pfn(pfn)) { | 551 | if (is_error_noslot_pfn(pfn)) { |
| 552 | printk(KERN_ERR "Couldn't get real page for gfn %lx!\n", | 552 | printk(KERN_ERR "Couldn't get real page for gfn %lx!\n", |
| 553 | (long)gfn); | 553 | (long)gfn); |
| 554 | return; | 554 | return -EINVAL; |
| 555 | } | 555 | } |
| 556 | 556 | ||
| 557 | /* Align guest and physical address to page map boundaries */ | 557 | /* Align guest and physical address to page map boundaries */ |
| @@ -571,22 +571,33 @@ static inline void kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500, | |||
| 571 | 571 | ||
| 572 | /* Drop refcount on page, so that mmu notifiers can clear it */ | 572 | /* Drop refcount on page, so that mmu notifiers can clear it */ |
| 573 | kvm_release_pfn_clean(pfn); | 573 | kvm_release_pfn_clean(pfn); |
| 574 | |||
| 575 | return 0; | ||
| 574 | } | 576 | } |
| 575 | 577 | ||
| 576 | /* XXX only map the one-one case, for now use TLB0 */ | 578 | /* XXX only map the one-one case, for now use TLB0 */ |
| 577 | static void kvmppc_e500_tlb0_map(struct kvmppc_vcpu_e500 *vcpu_e500, | 579 | static int kvmppc_e500_tlb0_map(struct kvmppc_vcpu_e500 *vcpu_e500, |
| 578 | int esel, | 580 | int esel, |
| 579 | struct kvm_book3e_206_tlb_entry *stlbe) | 581 | struct kvm_book3e_206_tlb_entry *stlbe) |
| 580 | { | 582 | { |
| 581 | struct kvm_book3e_206_tlb_entry *gtlbe; | 583 | struct kvm_book3e_206_tlb_entry *gtlbe; |
| 582 | struct tlbe_ref *ref; | 584 | struct tlbe_ref *ref; |
| 585 | int stlbsel = 0; | ||
| 586 | int sesel = 0; | ||
| 587 | int r; | ||
| 583 | 588 | ||
| 584 | gtlbe = get_entry(vcpu_e500, 0, esel); | 589 | gtlbe = get_entry(vcpu_e500, 0, esel); |
| 585 | ref = &vcpu_e500->gtlb_priv[0][esel].ref; | 590 | ref = &vcpu_e500->gtlb_priv[0][esel].ref; |
| 586 | 591 | ||
| 587 | kvmppc_e500_shadow_map(vcpu_e500, get_tlb_eaddr(gtlbe), | 592 | r = kvmppc_e500_shadow_map(vcpu_e500, get_tlb_eaddr(gtlbe), |
| 588 | get_tlb_raddr(gtlbe) >> PAGE_SHIFT, | 593 | get_tlb_raddr(gtlbe) >> PAGE_SHIFT, |
| 589 | gtlbe, 0, stlbe, ref); | 594 | gtlbe, 0, stlbe, ref); |
| 595 | if (r) | ||
| 596 | return r; | ||
| 597 | |||
| 598 | write_stlbe(vcpu_e500, gtlbe, stlbe, stlbsel, sesel); | ||
| 599 | |||
| 600 | return 0; | ||
| 590 | } | 601 | } |
| 591 | 602 | ||
| 592 | /* Caller must ensure that the specified guest TLB entry is safe to insert into | 603 | /* Caller must ensure that the specified guest TLB entry is safe to insert into |
| @@ -597,25 +608,32 @@ static int kvmppc_e500_tlb1_map(struct kvmppc_vcpu_e500 *vcpu_e500, | |||
| 597 | struct kvm_book3e_206_tlb_entry *stlbe, int esel) | 608 | struct kvm_book3e_206_tlb_entry *stlbe, int esel) |
| 598 | { | 609 | { |
| 599 | struct tlbe_ref *ref; | 610 | struct tlbe_ref *ref; |
| 600 | unsigned int victim; | 611 | unsigned int sesel; |
| 612 | int r; | ||
| 613 | int stlbsel = 1; | ||
| 601 | 614 | ||
| 602 | victim = vcpu_e500->host_tlb1_nv++; | 615 | sesel = vcpu_e500->host_tlb1_nv++; |
| 603 | 616 | ||
| 604 | if (unlikely(vcpu_e500->host_tlb1_nv >= tlb1_max_shadow_size())) | 617 | if (unlikely(vcpu_e500->host_tlb1_nv >= tlb1_max_shadow_size())) |
| 605 | vcpu_e500->host_tlb1_nv = 0; | 618 | vcpu_e500->host_tlb1_nv = 0; |
| 606 | 619 | ||
| 607 | ref = &vcpu_e500->tlb_refs[1][victim]; | 620 | ref = &vcpu_e500->tlb_refs[1][sesel]; |
| 608 | kvmppc_e500_shadow_map(vcpu_e500, gvaddr, gfn, gtlbe, 1, stlbe, ref); | 621 | r = kvmppc_e500_shadow_map(vcpu_e500, gvaddr, gfn, gtlbe, 1, stlbe, |
| 622 | ref); | ||
| 623 | if (r) | ||
| 624 | return r; | ||
| 609 | 625 | ||
| 610 | vcpu_e500->g2h_tlb1_map[esel] |= (u64)1 << victim; | 626 | vcpu_e500->g2h_tlb1_map[esel] |= (u64)1 << sesel; |
| 611 | vcpu_e500->gtlb_priv[1][esel].ref.flags |= E500_TLB_BITMAP; | 627 | vcpu_e500->gtlb_priv[1][esel].ref.flags |= E500_TLB_BITMAP; |
| 612 | if (vcpu_e500->h2g_tlb1_rmap[victim]) { | 628 | if (vcpu_e500->h2g_tlb1_rmap[sesel]) { |
| 613 | unsigned int idx = vcpu_e500->h2g_tlb1_rmap[victim]; | 629 | unsigned int idx = vcpu_e500->h2g_tlb1_rmap[sesel]; |
| 614 | vcpu_e500->g2h_tlb1_map[idx] &= ~(1ULL << victim); | 630 | vcpu_e500->g2h_tlb1_map[idx] &= ~(1ULL << sesel); |
| 615 | } | 631 | } |
| 616 | vcpu_e500->h2g_tlb1_rmap[victim] = esel; | 632 | vcpu_e500->h2g_tlb1_rmap[sesel] = esel; |
| 617 | 633 | ||
| 618 | return victim; | 634 | write_stlbe(vcpu_e500, gtlbe, stlbe, stlbsel, sesel); |
| 635 | |||
| 636 | return 0; | ||
| 619 | } | 637 | } |
| 620 | 638 | ||
| 621 | static void kvmppc_recalc_tlb1map_range(struct kvmppc_vcpu_e500 *vcpu_e500) | 639 | static void kvmppc_recalc_tlb1map_range(struct kvmppc_vcpu_e500 *vcpu_e500) |
| @@ -1034,30 +1052,27 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 eaddr, gpa_t gpaddr, | |||
| 1034 | struct kvm_book3e_206_tlb_entry *gtlbe, stlbe; | 1052 | struct kvm_book3e_206_tlb_entry *gtlbe, stlbe; |
| 1035 | int tlbsel = tlbsel_of(index); | 1053 | int tlbsel = tlbsel_of(index); |
| 1036 | int esel = esel_of(index); | 1054 | int esel = esel_of(index); |
| 1037 | int stlbsel, sesel; | ||
| 1038 | 1055 | ||
| 1039 | gtlbe = get_entry(vcpu_e500, tlbsel, esel); | 1056 | gtlbe = get_entry(vcpu_e500, tlbsel, esel); |
| 1040 | 1057 | ||
| 1041 | switch (tlbsel) { | 1058 | switch (tlbsel) { |
| 1042 | case 0: | 1059 | case 0: |
| 1043 | stlbsel = 0; | ||
| 1044 | sesel = 0; /* unused */ | ||
| 1045 | priv = &vcpu_e500->gtlb_priv[tlbsel][esel]; | 1060 | priv = &vcpu_e500->gtlb_priv[tlbsel][esel]; |
| 1046 | 1061 | ||
| 1047 | /* Only triggers after clear_tlb_refs */ | 1062 | /* Triggers after clear_tlb_refs or on initial mapping */ |
| 1048 | if (unlikely(!(priv->ref.flags & E500_TLB_VALID))) | 1063 | if (!(priv->ref.flags & E500_TLB_VALID)) { |
| 1049 | kvmppc_e500_tlb0_map(vcpu_e500, esel, &stlbe); | 1064 | kvmppc_e500_tlb0_map(vcpu_e500, esel, &stlbe); |
| 1050 | else | 1065 | } else { |
| 1051 | kvmppc_e500_setup_stlbe(vcpu, gtlbe, BOOK3E_PAGESZ_4K, | 1066 | kvmppc_e500_setup_stlbe(vcpu, gtlbe, BOOK3E_PAGESZ_4K, |
| 1052 | &priv->ref, eaddr, &stlbe); | 1067 | &priv->ref, eaddr, &stlbe); |
| 1068 | write_stlbe(vcpu_e500, gtlbe, &stlbe, 0, 0); | ||
| 1069 | } | ||
| 1053 | break; | 1070 | break; |
| 1054 | 1071 | ||
| 1055 | case 1: { | 1072 | case 1: { |
| 1056 | gfn_t gfn = gpaddr >> PAGE_SHIFT; | 1073 | gfn_t gfn = gpaddr >> PAGE_SHIFT; |
| 1057 | 1074 | kvmppc_e500_tlb1_map(vcpu_e500, eaddr, gfn, gtlbe, &stlbe, | |
| 1058 | stlbsel = 1; | 1075 | esel); |
| 1059 | sesel = kvmppc_e500_tlb1_map(vcpu_e500, eaddr, gfn, | ||
| 1060 | gtlbe, &stlbe, esel); | ||
| 1061 | break; | 1076 | break; |
| 1062 | } | 1077 | } |
| 1063 | 1078 | ||
| @@ -1065,8 +1080,6 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 eaddr, gpa_t gpaddr, | |||
| 1065 | BUG(); | 1080 | BUG(); |
| 1066 | break; | 1081 | break; |
| 1067 | } | 1082 | } |
| 1068 | |||
| 1069 | write_stlbe(vcpu_e500, gtlbe, &stlbe, stlbsel, sesel); | ||
| 1070 | } | 1083 | } |
| 1071 | 1084 | ||
| 1072 | /************* MMU Notifiers *************/ | 1085 | /************* MMU Notifiers *************/ |
