diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /arch/powerpc/kvm/book3s_mmu_hpte.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (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.c | 140 |
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 | |||
41 | static struct kmem_cache *hpte_cache; | 34 | static struct kmem_cache *hpte_cache; |
42 | 35 | ||
43 | static inline u64 kvmppc_mmu_hash_pte(u64 eaddr) | 36 | static 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 | ||
41 | static 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 | |||
48 | static inline u64 kvmppc_mmu_hash_vpte(u64 vpage) | 47 | static 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 | |||
87 | static 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 | ||
77 | static void invalidate_pte(struct kvm_vcpu *vcpu, struct hpte_cache *pte) | 93 | static 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 | ||
98 | static void kvmppc_mmu_pte_flush_all(struct kvm_vcpu *vcpu) | 124 | static 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 | ||
112 | static void kvmppc_mmu_pte_flush_page(struct kvm_vcpu *vcpu, ulong guest_ea) | 142 | static 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 | ||
127 | void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong guest_ea, ulong ea_mask) | 161 | static 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 | |||
181 | void 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) | |||
156 | static void kvmppc_mmu_pte_vflush_short(struct kvm_vcpu *vcpu, u64 guest_vp) | 204 | static 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 */ |
172 | static void kvmppc_mmu_pte_vflush_long(struct kvm_vcpu *vcpu, u64 guest_vp) | 224 | static 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 | ||
188 | void kvmppc_mmu_pte_vflush(struct kvm_vcpu *vcpu, u64 guest_vp, u64 vp_mask) | 244 | void 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 | ||
207 | void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, ulong pa_start, ulong pa_end) | 262 | void 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 | ||
226 | struct hpte_cache *kvmppc_mmu_hpte_cache_next(struct kvm_vcpu *vcpu) | 284 | struct 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 | ||