diff options
author | Scott Wood <scottwood@freescale.com> | 2011-12-20 10:34:37 -0500 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2012-04-08 05:51:14 -0400 |
commit | 4f802fe98bd5bd4fe1dd86df3e5c58546e65ad09 (patch) | |
tree | dd13f1ed180c846523a84f54b7bdfe07dce5acd9 /arch/powerpc/kvm | |
parent | 8fdd21a26876ea6c486c38bfa75fdd18ba299351 (diff) |
KVM: PPC: e500: Track TLB1 entries with a bitmap
Rather than invalidate everything when a TLB1 entry needs to be
taken down, keep track of which host TLB1 entries are used for
a given guest TLB1 entry, and invalidate just those entries.
Based on code from Ashish Kalra <Ashish.Kalra@freescale.com>
and Liu Yu <yu.liu@freescale.com>.
Signed-off-by: Scott Wood <scottwood@freescale.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch/powerpc/kvm')
-rw-r--r-- | arch/powerpc/kvm/e500.h | 5 | ||||
-rw-r--r-- | arch/powerpc/kvm/e500_tlb.c | 72 |
2 files changed, 72 insertions, 5 deletions
diff --git a/arch/powerpc/kvm/e500.h b/arch/powerpc/kvm/e500.h index 34cef08f1361..f4dee55ae6c7 100644 --- a/arch/powerpc/kvm/e500.h +++ b/arch/powerpc/kvm/e500.h | |||
@@ -2,6 +2,7 @@ | |||
2 | * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All rights reserved. | 2 | * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All rights reserved. |
3 | * | 3 | * |
4 | * Author: Yu Liu <yu.liu@freescale.com> | 4 | * Author: Yu Liu <yu.liu@freescale.com> |
5 | * Ashish Kalra <ashish.kalra@freescale.com> | ||
5 | * | 6 | * |
6 | * Description: | 7 | * Description: |
7 | * This file is based on arch/powerpc/kvm/44x_tlb.h and | 8 | * This file is based on arch/powerpc/kvm/44x_tlb.h and |
@@ -25,6 +26,7 @@ | |||
25 | 26 | ||
26 | #define E500_TLB_VALID 1 | 27 | #define E500_TLB_VALID 1 |
27 | #define E500_TLB_DIRTY 2 | 28 | #define E500_TLB_DIRTY 2 |
29 | #define E500_TLB_BITMAP 4 | ||
28 | 30 | ||
29 | struct tlbe_ref { | 31 | struct tlbe_ref { |
30 | pfn_t pfn; | 32 | pfn_t pfn; |
@@ -82,6 +84,9 @@ struct kvmppc_vcpu_e500 { | |||
82 | struct page **shared_tlb_pages; | 84 | struct page **shared_tlb_pages; |
83 | int num_shared_tlb_pages; | 85 | int num_shared_tlb_pages; |
84 | 86 | ||
87 | u64 *g2h_tlb1_map; | ||
88 | unsigned int *h2g_tlb1_rmap; | ||
89 | |||
85 | #ifdef CONFIG_KVM_E500 | 90 | #ifdef CONFIG_KVM_E500 |
86 | u32 pid[E500_PID_NUM]; | 91 | u32 pid[E500_PID_NUM]; |
87 | 92 | ||
diff --git a/arch/powerpc/kvm/e500_tlb.c b/arch/powerpc/kvm/e500_tlb.c index 9925fc6c9cfb..c8ce51d03a2f 100644 --- a/arch/powerpc/kvm/e500_tlb.c +++ b/arch/powerpc/kvm/e500_tlb.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All rights reserved. | 2 | * Copyright (C) 2008-2011 Freescale Semiconductor, Inc. All rights reserved. |
3 | * | 3 | * |
4 | * Author: Yu Liu, yu.liu@freescale.com | 4 | * Author: Yu Liu, yu.liu@freescale.com |
5 | * Ashish Kalra, ashish.kalra@freescale.com | ||
5 | * | 6 | * |
6 | * Description: | 7 | * Description: |
7 | * This file is based on arch/powerpc/kvm/44x_tlb.c, | 8 | * This file is based on arch/powerpc/kvm/44x_tlb.c, |
@@ -175,8 +176,28 @@ static void inval_gtlbe_on_host(struct kvmppc_vcpu_e500 *vcpu_e500, | |||
175 | struct kvm_book3e_206_tlb_entry *gtlbe = | 176 | struct kvm_book3e_206_tlb_entry *gtlbe = |
176 | get_entry(vcpu_e500, tlbsel, esel); | 177 | get_entry(vcpu_e500, tlbsel, esel); |
177 | 178 | ||
178 | if (tlbsel == 1) { | 179 | if (tlbsel == 1 && |
179 | kvmppc_e500_tlbil_all(vcpu_e500); | 180 | vcpu_e500->gtlb_priv[1][esel].ref.flags & E500_TLB_BITMAP) { |
181 | u64 tmp = vcpu_e500->g2h_tlb1_map[esel]; | ||
182 | int hw_tlb_indx; | ||
183 | unsigned long flags; | ||
184 | |||
185 | local_irq_save(flags); | ||
186 | while (tmp) { | ||
187 | hw_tlb_indx = __ilog2_u64(tmp & -tmp); | ||
188 | mtspr(SPRN_MAS0, | ||
189 | MAS0_TLBSEL(1) | | ||
190 | MAS0_ESEL(to_htlb1_esel(hw_tlb_indx))); | ||
191 | mtspr(SPRN_MAS1, 0); | ||
192 | asm volatile("tlbwe"); | ||
193 | vcpu_e500->h2g_tlb1_rmap[hw_tlb_indx] = 0; | ||
194 | tmp &= tmp - 1; | ||
195 | } | ||
196 | mb(); | ||
197 | vcpu_e500->g2h_tlb1_map[esel] = 0; | ||
198 | vcpu_e500->gtlb_priv[1][esel].ref.flags &= ~E500_TLB_BITMAP; | ||
199 | local_irq_restore(flags); | ||
200 | |||
180 | return; | 201 | return; |
181 | } | 202 | } |
182 | 203 | ||
@@ -282,6 +303,16 @@ static inline void kvmppc_e500_ref_release(struct tlbe_ref *ref) | |||
282 | } | 303 | } |
283 | } | 304 | } |
284 | 305 | ||
306 | static void clear_tlb1_bitmap(struct kvmppc_vcpu_e500 *vcpu_e500) | ||
307 | { | ||
308 | if (vcpu_e500->g2h_tlb1_map) | ||
309 | memset(vcpu_e500->g2h_tlb1_map, | ||
310 | sizeof(u64) * vcpu_e500->gtlb_params[1].entries, 0); | ||
311 | if (vcpu_e500->h2g_tlb1_rmap) | ||
312 | memset(vcpu_e500->h2g_tlb1_rmap, | ||
313 | sizeof(unsigned int) * host_tlb_params[1].entries, 0); | ||
314 | } | ||
315 | |||
285 | static void clear_tlb_privs(struct kvmppc_vcpu_e500 *vcpu_e500) | 316 | static void clear_tlb_privs(struct kvmppc_vcpu_e500 *vcpu_e500) |
286 | { | 317 | { |
287 | int tlbsel = 0; | 318 | int tlbsel = 0; |
@@ -511,7 +542,7 @@ static void kvmppc_e500_tlb0_map(struct kvmppc_vcpu_e500 *vcpu_e500, | |||
511 | /* XXX for both one-one and one-to-many , for now use TLB1 */ | 542 | /* XXX for both one-one and one-to-many , for now use TLB1 */ |
512 | static int kvmppc_e500_tlb1_map(struct kvmppc_vcpu_e500 *vcpu_e500, | 543 | static int kvmppc_e500_tlb1_map(struct kvmppc_vcpu_e500 *vcpu_e500, |
513 | u64 gvaddr, gfn_t gfn, struct kvm_book3e_206_tlb_entry *gtlbe, | 544 | u64 gvaddr, gfn_t gfn, struct kvm_book3e_206_tlb_entry *gtlbe, |
514 | struct kvm_book3e_206_tlb_entry *stlbe) | 545 | struct kvm_book3e_206_tlb_entry *stlbe, int esel) |
515 | { | 546 | { |
516 | struct tlbe_ref *ref; | 547 | struct tlbe_ref *ref; |
517 | unsigned int victim; | 548 | unsigned int victim; |
@@ -524,6 +555,14 @@ static int kvmppc_e500_tlb1_map(struct kvmppc_vcpu_e500 *vcpu_e500, | |||
524 | ref = &vcpu_e500->tlb_refs[1][victim]; | 555 | ref = &vcpu_e500->tlb_refs[1][victim]; |
525 | kvmppc_e500_shadow_map(vcpu_e500, gvaddr, gfn, gtlbe, 1, stlbe, ref); | 556 | kvmppc_e500_shadow_map(vcpu_e500, gvaddr, gfn, gtlbe, 1, stlbe, ref); |
526 | 557 | ||
558 | vcpu_e500->g2h_tlb1_map[esel] |= (u64)1 << victim; | ||
559 | vcpu_e500->gtlb_priv[1][esel].ref.flags |= E500_TLB_BITMAP; | ||
560 | if (vcpu_e500->h2g_tlb1_rmap[victim]) { | ||
561 | unsigned int idx = vcpu_e500->h2g_tlb1_rmap[victim]; | ||
562 | vcpu_e500->g2h_tlb1_map[idx] &= ~(1ULL << victim); | ||
563 | } | ||
564 | vcpu_e500->h2g_tlb1_rmap[victim] = esel; | ||
565 | |||
527 | return victim; | 566 | return victim; |
528 | } | 567 | } |
529 | 568 | ||
@@ -728,7 +767,7 @@ int kvmppc_e500_emul_tlbwe(struct kvm_vcpu *vcpu) | |||
728 | * are mapped on the fly. */ | 767 | * are mapped on the fly. */ |
729 | stlbsel = 1; | 768 | stlbsel = 1; |
730 | sesel = kvmppc_e500_tlb1_map(vcpu_e500, eaddr, | 769 | sesel = kvmppc_e500_tlb1_map(vcpu_e500, eaddr, |
731 | raddr >> PAGE_SHIFT, gtlbe, &stlbe); | 770 | raddr >> PAGE_SHIFT, gtlbe, &stlbe, esel); |
732 | break; | 771 | break; |
733 | 772 | ||
734 | default: | 773 | default: |
@@ -856,7 +895,7 @@ void kvmppc_mmu_map(struct kvm_vcpu *vcpu, u64 eaddr, gpa_t gpaddr, | |||
856 | 895 | ||
857 | stlbsel = 1; | 896 | stlbsel = 1; |
858 | sesel = kvmppc_e500_tlb1_map(vcpu_e500, eaddr, gfn, | 897 | sesel = kvmppc_e500_tlb1_map(vcpu_e500, eaddr, gfn, |
859 | gtlbe, &stlbe); | 898 | gtlbe, &stlbe, esel); |
860 | break; | 899 | break; |
861 | } | 900 | } |
862 | 901 | ||
@@ -872,6 +911,9 @@ static void free_gtlb(struct kvmppc_vcpu_e500 *vcpu_e500) | |||
872 | { | 911 | { |
873 | int i; | 912 | int i; |
874 | 913 | ||
914 | clear_tlb1_bitmap(vcpu_e500); | ||
915 | kfree(vcpu_e500->g2h_tlb1_map); | ||
916 | |||
875 | clear_tlb_refs(vcpu_e500); | 917 | clear_tlb_refs(vcpu_e500); |
876 | kfree(vcpu_e500->gtlb_priv[0]); | 918 | kfree(vcpu_e500->gtlb_priv[0]); |
877 | kfree(vcpu_e500->gtlb_priv[1]); | 919 | kfree(vcpu_e500->gtlb_priv[1]); |
@@ -932,6 +974,7 @@ int kvm_vcpu_ioctl_config_tlb(struct kvm_vcpu *vcpu, | |||
932 | char *virt; | 974 | char *virt; |
933 | struct page **pages; | 975 | struct page **pages; |
934 | struct tlbe_priv *privs[2] = {}; | 976 | struct tlbe_priv *privs[2] = {}; |
977 | u64 *g2h_bitmap = NULL; | ||
935 | size_t array_len; | 978 | size_t array_len; |
936 | u32 sets; | 979 | u32 sets; |
937 | int num_pages, ret, i; | 980 | int num_pages, ret, i; |
@@ -993,10 +1036,16 @@ int kvm_vcpu_ioctl_config_tlb(struct kvm_vcpu *vcpu, | |||
993 | if (!privs[0] || !privs[1]) | 1036 | if (!privs[0] || !privs[1]) |
994 | goto err_put_page; | 1037 | goto err_put_page; |
995 | 1038 | ||
1039 | g2h_bitmap = kzalloc(sizeof(u64) * params.tlb_sizes[1], | ||
1040 | GFP_KERNEL); | ||
1041 | if (!g2h_bitmap) | ||
1042 | goto err_put_page; | ||
1043 | |||
996 | free_gtlb(vcpu_e500); | 1044 | free_gtlb(vcpu_e500); |
997 | 1045 | ||
998 | vcpu_e500->gtlb_priv[0] = privs[0]; | 1046 | vcpu_e500->gtlb_priv[0] = privs[0]; |
999 | vcpu_e500->gtlb_priv[1] = privs[1]; | 1047 | vcpu_e500->gtlb_priv[1] = privs[1]; |
1048 | vcpu_e500->g2h_tlb1_map = g2h_bitmap; | ||
1000 | 1049 | ||
1001 | vcpu_e500->gtlb_arch = (struct kvm_book3e_206_tlb_entry *) | 1050 | vcpu_e500->gtlb_arch = (struct kvm_book3e_206_tlb_entry *) |
1002 | (virt + (cfg->array & (PAGE_SIZE - 1))); | 1051 | (virt + (cfg->array & (PAGE_SIZE - 1))); |
@@ -1129,6 +1178,18 @@ int kvmppc_e500_tlb_init(struct kvmppc_vcpu_e500 *vcpu_e500) | |||
1129 | if (!vcpu_e500->gtlb_priv[1]) | 1178 | if (!vcpu_e500->gtlb_priv[1]) |
1130 | goto err; | 1179 | goto err; |
1131 | 1180 | ||
1181 | vcpu_e500->g2h_tlb1_map = kzalloc(sizeof(unsigned int) * | ||
1182 | vcpu_e500->gtlb_params[1].entries, | ||
1183 | GFP_KERNEL); | ||
1184 | if (!vcpu_e500->g2h_tlb1_map) | ||
1185 | goto err; | ||
1186 | |||
1187 | vcpu_e500->h2g_tlb1_rmap = kzalloc(sizeof(unsigned int) * | ||
1188 | host_tlb_params[1].entries, | ||
1189 | GFP_KERNEL); | ||
1190 | if (!vcpu_e500->h2g_tlb1_rmap) | ||
1191 | goto err; | ||
1192 | |||
1132 | /* Init TLB configuration register */ | 1193 | /* Init TLB configuration register */ |
1133 | vcpu->arch.tlbcfg[0] = mfspr(SPRN_TLB0CFG) & | 1194 | vcpu->arch.tlbcfg[0] = mfspr(SPRN_TLB0CFG) & |
1134 | ~(TLBnCFG_N_ENTRY | TLBnCFG_ASSOC); | 1195 | ~(TLBnCFG_N_ENTRY | TLBnCFG_ASSOC); |
@@ -1154,6 +1215,7 @@ err: | |||
1154 | void kvmppc_e500_tlb_uninit(struct kvmppc_vcpu_e500 *vcpu_e500) | 1215 | void kvmppc_e500_tlb_uninit(struct kvmppc_vcpu_e500 *vcpu_e500) |
1155 | { | 1216 | { |
1156 | free_gtlb(vcpu_e500); | 1217 | free_gtlb(vcpu_e500); |
1218 | kfree(vcpu_e500->h2g_tlb1_rmap); | ||
1157 | kfree(vcpu_e500->tlb_refs[0]); | 1219 | kfree(vcpu_e500->tlb_refs[0]); |
1158 | kfree(vcpu_e500->tlb_refs[1]); | 1220 | kfree(vcpu_e500->tlb_refs[1]); |
1159 | } | 1221 | } |