aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kvm
diff options
context:
space:
mode:
authorScott Wood <scottwood@freescale.com>2011-12-20 10:34:37 -0500
committerAvi Kivity <avi@redhat.com>2012-04-08 05:51:14 -0400
commit4f802fe98bd5bd4fe1dd86df3e5c58546e65ad09 (patch)
treedd13f1ed180c846523a84f54b7bdfe07dce5acd9 /arch/powerpc/kvm
parent8fdd21a26876ea6c486c38bfa75fdd18ba299351 (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.h5
-rw-r--r--arch/powerpc/kvm/e500_tlb.c72
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
29struct tlbe_ref { 31struct 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
306static 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
285static void clear_tlb_privs(struct kvmppc_vcpu_e500 *vcpu_e500) 316static 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 */
512static int kvmppc_e500_tlb1_map(struct kvmppc_vcpu_e500 *vcpu_e500, 543static 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:
1154void kvmppc_e500_tlb_uninit(struct kvmppc_vcpu_e500 *vcpu_e500) 1215void 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}