aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kvm/book3s_mmu_hpte.c
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
committerGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
commitc71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch)
treeecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /arch/powerpc/kvm/book3s_mmu_hpte.c
parentea53c912f8a86a8567697115b6a0d8152beee5c8 (diff)
parent6a00f206debf8a5c8899055726ad127dbeeed098 (diff)
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts: litmus/sched_cedf.c
Diffstat (limited to 'arch/powerpc/kvm/book3s_mmu_hpte.c')
-rw-r--r--arch/powerpc/kvm/book3s_mmu_hpte.c140
1 files changed, 101 insertions, 39 deletions
diff --git a/arch/powerpc/kvm/book3s_mmu_hpte.c b/arch/powerpc/kvm/book3s_mmu_hpte.c
index 4868d4a7ebc5..79751d8dd131 100644
--- a/arch/powerpc/kvm/book3s_mmu_hpte.c
+++ b/arch/powerpc/kvm/book3s_mmu_hpte.c
@@ -21,6 +21,7 @@
21#include <linux/kvm_host.h> 21#include <linux/kvm_host.h>
22#include <linux/hash.h> 22#include <linux/hash.h>
23#include <linux/slab.h> 23#include <linux/slab.h>
24#include "trace.h"
24 25
25#include <asm/kvm_ppc.h> 26#include <asm/kvm_ppc.h>
26#include <asm/kvm_book3s.h> 27#include <asm/kvm_book3s.h>
@@ -30,14 +31,6 @@
30 31
31#define PTE_SIZE 12 32#define PTE_SIZE 12
32 33
33/* #define DEBUG_MMU */
34
35#ifdef DEBUG_MMU
36#define dprintk_mmu(a, ...) printk(KERN_INFO a, __VA_ARGS__)
37#else
38#define dprintk_mmu(a, ...) do { } while(0)
39#endif
40
41static struct kmem_cache *hpte_cache; 34static struct kmem_cache *hpte_cache;
42 35
43static inline u64 kvmppc_mmu_hash_pte(u64 eaddr) 36static inline u64 kvmppc_mmu_hash_pte(u64 eaddr)
@@ -45,6 +38,12 @@ static inline u64 kvmppc_mmu_hash_pte(u64 eaddr)
45 return hash_64(eaddr >> PTE_SIZE, HPTEG_HASH_BITS_PTE); 38 return hash_64(eaddr >> PTE_SIZE, HPTEG_HASH_BITS_PTE);
46} 39}
47 40
41static inline u64 kvmppc_mmu_hash_pte_long(u64 eaddr)
42{
43 return hash_64((eaddr & 0x0ffff000) >> PTE_SIZE,
44 HPTEG_HASH_BITS_PTE_LONG);
45}
46
48static inline u64 kvmppc_mmu_hash_vpte(u64 vpage) 47static inline u64 kvmppc_mmu_hash_vpte(u64 vpage)
49{ 48{
50 return hash_64(vpage & 0xfffffffffULL, HPTEG_HASH_BITS_VPTE); 49 return hash_64(vpage & 0xfffffffffULL, HPTEG_HASH_BITS_VPTE);
@@ -60,77 +59,128 @@ void kvmppc_mmu_hpte_cache_map(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
60{ 59{
61 u64 index; 60 u64 index;
62 61
62 trace_kvm_book3s_mmu_map(pte);
63
64 spin_lock(&vcpu->arch.mmu_lock);
65
63 /* Add to ePTE list */ 66 /* Add to ePTE list */
64 index = kvmppc_mmu_hash_pte(pte->pte.eaddr); 67 index = kvmppc_mmu_hash_pte(pte->pte.eaddr);
65 hlist_add_head(&pte->list_pte, &vcpu->arch.hpte_hash_pte[index]); 68 hlist_add_head_rcu(&pte->list_pte, &vcpu->arch.hpte_hash_pte[index]);
69
70 /* Add to ePTE_long list */
71 index = kvmppc_mmu_hash_pte_long(pte->pte.eaddr);
72 hlist_add_head_rcu(&pte->list_pte_long,
73 &vcpu->arch.hpte_hash_pte_long[index]);
66 74
67 /* Add to vPTE list */ 75 /* Add to vPTE list */
68 index = kvmppc_mmu_hash_vpte(pte->pte.vpage); 76 index = kvmppc_mmu_hash_vpte(pte->pte.vpage);
69 hlist_add_head(&pte->list_vpte, &vcpu->arch.hpte_hash_vpte[index]); 77 hlist_add_head_rcu(&pte->list_vpte, &vcpu->arch.hpte_hash_vpte[index]);
70 78
71 /* Add to vPTE_long list */ 79 /* Add to vPTE_long list */
72 index = kvmppc_mmu_hash_vpte_long(pte->pte.vpage); 80 index = kvmppc_mmu_hash_vpte_long(pte->pte.vpage);
73 hlist_add_head(&pte->list_vpte_long, 81 hlist_add_head_rcu(&pte->list_vpte_long,
74 &vcpu->arch.hpte_hash_vpte_long[index]); 82 &vcpu->arch.hpte_hash_vpte_long[index]);
83
84 spin_unlock(&vcpu->arch.mmu_lock);
85}
86
87static void free_pte_rcu(struct rcu_head *head)
88{
89 struct hpte_cache *pte = container_of(head, struct hpte_cache, rcu_head);
90 kmem_cache_free(hpte_cache, pte);
75} 91}
76 92
77static void invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte) 93static void invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte)
78{ 94{
79 dprintk_mmu("KVM: Flushing SPT: 0x%lx (0x%llx) -> 0x%llx\n", 95 trace_kvm_book3s_mmu_invalidate(pte);
80 pte->pte.eaddr, pte->pte.vpage, pte->host_va);
81 96
82 /* Different for 32 and 64 bit */ 97 /* Different for 32 and 64 bit */
83 kvmppc_mmu_invalidate_pte(vcpu, pte); 98 kvmppc_mmu_invalidate_pte(vcpu, pte);
84 99
100 spin_lock(&vcpu->arch.mmu_lock);
101
102 /* pte already invalidated in between? */
103 if (hlist_unhashed(&pte->list_pte)) {
104 spin_unlock(&vcpu->arch.mmu_lock);
105 return;
106 }
107
108 hlist_del_init_rcu(&pte->list_pte);
109 hlist_del_init_rcu(&pte->list_pte_long);
110 hlist_del_init_rcu(&pte->list_vpte);
111 hlist_del_init_rcu(&pte->list_vpte_long);
112
85 if (pte->pte.may_write) 113 if (pte->pte.may_write)
86 kvm_release_pfn_dirty(pte->pfn); 114 kvm_release_pfn_dirty(pte->pfn);
87 else 115 else
88 kvm_release_pfn_clean(pte->pfn); 116 kvm_release_pfn_clean(pte->pfn);
89 117
90 hlist_del(&pte->list_pte); 118 spin_unlock(&vcpu->arch.mmu_lock);
91 hlist_del(&pte->list_vpte);
92 hlist_del(&pte->list_vpte_long);
93 119
94 vcpu->arch.hpte_cache_count--; 120 vcpu->arch.hpte_cache_count--;
95 kmem_cache_free(hpte_cache, pte); 121 call_rcu(&pte->rcu_head, free_pte_rcu);
96} 122}
97 123
98static void kvmppc_mmu_pte_flush_all(struct kvm_vcpu *vcpu) 124static void kvmppc_mmu_pte_flush_all(struct kvm_vcpu *vcpu)
99{ 125{
100 struct hpte_cache *pte; 126 struct hpte_cache *pte;
101 struct hlist_node *node, *tmp; 127 struct hlist_node *node;
102 int i; 128 int i;
103 129
130 rcu_read_lock();
131
104 for (i = 0; i < HPTEG_HASH_NUM_VPTE_LONG; i++) { 132 for (i = 0; i < HPTEG_HASH_NUM_VPTE_LONG; i++) {
105 struct hlist_head *list = &vcpu->arch.hpte_hash_vpte_long[i]; 133 struct hlist_head *list = &vcpu->arch.hpte_hash_vpte_long[i];
106 134
107 hlist_for_each_entry_safe(pte, node, tmp, list, list_vpte_long) 135 hlist_for_each_entry_rcu(pte, node, list, list_vpte_long)
108 invalidate_pte(vcpu, pte); 136 invalidate_pte(vcpu, pte);
109 } 137 }
138
139 rcu_read_unlock();
110} 140}
111 141
112static void kvmppc_mmu_pte_flush_page(struct kvm_vcpu *vcpu, ulong guest_ea) 142static void kvmppc_mmu_pte_flush_page(struct kvm_vcpu *vcpu, ulong guest_ea)
113{ 143{
114 struct hlist_head *list; 144 struct hlist_head *list;
115 struct hlist_node *node, *tmp; 145 struct hlist_node *node;
116 struct hpte_cache *pte; 146 struct hpte_cache *pte;
117 147
118 /* Find the list of entries in the map */ 148 /* Find the list of entries in the map */
119 list = &vcpu->arch.hpte_hash_pte[kvmppc_mmu_hash_pte(guest_ea)]; 149 list = &vcpu->arch.hpte_hash_pte[kvmppc_mmu_hash_pte(guest_ea)];
120 150
151 rcu_read_lock();
152
121 /* Check the list for matching entries and invalidate */ 153 /* Check the list for matching entries and invalidate */
122 hlist_for_each_entry_safe(pte, node, tmp, list, list_pte) 154 hlist_for_each_entry_rcu(pte, node, list, list_pte)
123 if ((pte->pte.eaddr & ~0xfffUL) == guest_ea) 155 if ((pte->pte.eaddr & ~0xfffUL) == guest_ea)
124 invalidate_pte(vcpu, pte); 156 invalidate_pte(vcpu, pte);
157
158 rcu_read_unlock();
125} 159}
126 160
127void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong guest_ea, ulong ea_mask) 161static void kvmppc_mmu_pte_flush_long(struct kvm_vcpu *vcpu, ulong guest_ea)
128{ 162{
129 u64 i; 163 struct hlist_head *list;
164 struct hlist_node *node;
165 struct hpte_cache *pte;
130 166
131 dprintk_mmu("KVM: Flushing %d Shadow PTEs: 0x%lx & 0x%lx\n", 167 /* Find the list of entries in the map */
132 vcpu->arch.hpte_cache_count, guest_ea, ea_mask); 168 list = &vcpu->arch.hpte_hash_pte_long[
169 kvmppc_mmu_hash_pte_long(guest_ea)];
133 170
171 rcu_read_lock();
172
173 /* Check the list for matching entries and invalidate */
174 hlist_for_each_entry_rcu(pte, node, list, list_pte_long)
175 if ((pte->pte.eaddr & 0x0ffff000UL) == guest_ea)
176 invalidate_pte(vcpu, pte);
177
178 rcu_read_unlock();
179}
180
181void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong guest_ea, ulong ea_mask)
182{
183 trace_kvm_book3s_mmu_flush("", vcpu, guest_ea, ea_mask);
134 guest_ea &= ea_mask; 184 guest_ea &= ea_mask;
135 185
136 switch (ea_mask) { 186 switch (ea_mask) {
@@ -138,9 +188,7 @@ void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong guest_ea, ulong ea_mask)
138 kvmppc_mmu_pte_flush_page(vcpu, guest_ea); 188 kvmppc_mmu_pte_flush_page(vcpu, guest_ea);
139 break; 189 break;
140 case 0x0ffff000: 190 case 0x0ffff000:
141 /* 32-bit flush w/o segment, go through all possible segments */ 191 kvmppc_mmu_pte_flush_long(vcpu, guest_ea);
142 for (i = 0; i < 0x100000000ULL; i += 0x10000000ULL)
143 kvmppc_mmu_pte_flush(vcpu, guest_ea | i, ~0xfffUL);
144 break; 192 break;
145 case 0: 193 case 0:
146 /* Doing a complete flush -> start from scratch */ 194 /* Doing a complete flush -> start from scratch */
@@ -156,39 +204,46 @@ void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong guest_ea, ulong ea_mask)
156static void kvmppc_mmu_pte_vflush_short(struct kvm_vcpu *vcpu, u64 guest_vp) 204static void kvmppc_mmu_pte_vflush_short(struct kvm_vcpu *vcpu, u64 guest_vp)
157{ 205{
158 struct hlist_head *list; 206 struct hlist_head *list;
159 struct hlist_node *node, *tmp; 207 struct hlist_node *node;
160 struct hpte_cache *pte; 208 struct hpte_cache *pte;
161 u64 vp_mask = 0xfffffffffULL; 209 u64 vp_mask = 0xfffffffffULL;
162 210
163 list = &vcpu->arch.hpte_hash_vpte[kvmppc_mmu_hash_vpte(guest_vp)]; 211 list = &vcpu->arch.hpte_hash_vpte[kvmppc_mmu_hash_vpte(guest_vp)];
164 212
213 rcu_read_lock();
214
165 /* Check the list for matching entries and invalidate */ 215 /* Check the list for matching entries and invalidate */
166 hlist_for_each_entry_safe(pte, node, tmp, list, list_vpte) 216 hlist_for_each_entry_rcu(pte, node, list, list_vpte)
167 if ((pte->pte.vpage & vp_mask) == guest_vp) 217 if ((pte->pte.vpage & vp_mask) == guest_vp)
168 invalidate_pte(vcpu, pte); 218 invalidate_pte(vcpu, pte);
219
220 rcu_read_unlock();
169} 221}
170 222
171/* Flush with mask 0xffffff000 */ 223/* Flush with mask 0xffffff000 */
172static void kvmppc_mmu_pte_vflush_long(struct kvm_vcpu *vcpu, u64 guest_vp) 224static void kvmppc_mmu_pte_vflush_long(struct kvm_vcpu *vcpu, u64 guest_vp)
173{ 225{
174 struct hlist_head *list; 226 struct hlist_head *list;
175 struct hlist_node *node, *tmp; 227 struct hlist_node *node;
176 struct hpte_cache *pte; 228 struct hpte_cache *pte;
177 u64 vp_mask = 0xffffff000ULL; 229 u64 vp_mask = 0xffffff000ULL;
178 230
179 list = &vcpu->arch.hpte_hash_vpte_long[ 231 list = &vcpu->arch.hpte_hash_vpte_long[
180 kvmppc_mmu_hash_vpte_long(guest_vp)]; 232 kvmppc_mmu_hash_vpte_long(guest_vp)];
181 233
234 rcu_read_lock();
235
182 /* Check the list for matching entries and invalidate */ 236 /* Check the list for matching entries and invalidate */
183 hlist_for_each_entry_safe(pte, node, tmp, list, list_vpte_long) 237 hlist_for_each_entry_rcu(pte, node, list, list_vpte_long)
184 if ((pte->pte.vpage & vp_mask) == guest_vp) 238 if ((pte->pte.vpage & vp_mask) == guest_vp)
185 invalidate_pte(vcpu, pte); 239 invalidate_pte(vcpu, pte);
240
241 rcu_read_unlock();
186} 242}
187 243
188void kvmppc_mmu_pte_vflush(struct kvm_vcpu *vcpu, u64 guest_vp, u64 vp_mask) 244void kvmppc_mmu_pte_vflush(struct kvm_vcpu *vcpu, u64 guest_vp, u64 vp_mask)
189{ 245{
190 dprintk_mmu("KVM: Flushing %d Shadow vPTEs: 0x%llx & 0x%llx\n", 246 trace_kvm_book3s_mmu_flush("v", vcpu, guest_vp, vp_mask);
191 vcpu->arch.hpte_cache_count, guest_vp, vp_mask);
192 guest_vp &= vp_mask; 247 guest_vp &= vp_mask;
193 248
194 switch(vp_mask) { 249 switch(vp_mask) {
@@ -206,21 +261,24 @@ void kvmppc_mmu_pte_vflush(struct kvm_vcpu *vcpu, u64 guest_vp, u64 vp_mask)
206 261
207void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, ulong pa_start, ulong pa_end) 262void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, ulong pa_start, ulong pa_end)
208{ 263{
209 struct hlist_node *node, *tmp; 264 struct hlist_node *node;
210 struct hpte_cache *pte; 265 struct hpte_cache *pte;
211 int i; 266 int i;
212 267
213 dprintk_mmu("KVM: Flushing %d Shadow pPTEs: 0x%lx - 0x%lx\n", 268 trace_kvm_book3s_mmu_flush("p", vcpu, pa_start, pa_end);
214 vcpu->arch.hpte_cache_count, pa_start, pa_end); 269
270 rcu_read_lock();
215 271
216 for (i = 0; i < HPTEG_HASH_NUM_VPTE_LONG; i++) { 272 for (i = 0; i < HPTEG_HASH_NUM_VPTE_LONG; i++) {
217 struct hlist_head *list = &vcpu->arch.hpte_hash_vpte_long[i]; 273 struct hlist_head *list = &vcpu->arch.hpte_hash_vpte_long[i];
218 274
219 hlist_for_each_entry_safe(pte, node, tmp, list, list_vpte_long) 275 hlist_for_each_entry_rcu(pte, node, list, list_vpte_long)
220 if ((pte->pte.raddr >= pa_start) && 276 if ((pte->pte.raddr >= pa_start) &&
221 (pte->pte.raddr < pa_end)) 277 (pte->pte.raddr < pa_end))
222 invalidate_pte(vcpu, pte); 278 invalidate_pte(vcpu, pte);
223 } 279 }
280
281 rcu_read_unlock();
224} 282}
225 283
226struct hpte_cache *kvmppc_mmu_hpte_cache_next(struct kvm_vcpu *vcpu) 284struct hpte_cache *kvmppc_mmu_hpte_cache_next(struct kvm_vcpu *vcpu)
@@ -254,11 +312,15 @@ int kvmppc_mmu_hpte_init(struct kvm_vcpu *vcpu)
254 /* init hpte lookup hashes */ 312 /* init hpte lookup hashes */
255 kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_pte, 313 kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_pte,
256 ARRAY_SIZE(vcpu->arch.hpte_hash_pte)); 314 ARRAY_SIZE(vcpu->arch.hpte_hash_pte));
315 kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_pte_long,
316 ARRAY_SIZE(vcpu->arch.hpte_hash_pte_long));
257 kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_vpte, 317 kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_vpte,
258 ARRAY_SIZE(vcpu->arch.hpte_hash_vpte)); 318 ARRAY_SIZE(vcpu->arch.hpte_hash_vpte));
259 kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_vpte_long, 319 kvmppc_mmu_hpte_init_hash(vcpu->arch.hpte_hash_vpte_long,
260 ARRAY_SIZE(vcpu->arch.hpte_hash_vpte_long)); 320 ARRAY_SIZE(vcpu->arch.hpte_hash_vpte_long));
261 321
322 spin_lock_init(&vcpu->arch.mmu_lock);
323
262 return 0; 324 return 0;
263} 325}
264 326