aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/kvm/book3s_64_mmu_radix.c69
-rw-r--r--arch/powerpc/kvm/book3s_hv.c17
-rw-r--r--arch/powerpc/kvm/powerpc.c4
3 files changed, 55 insertions, 35 deletions
diff --git a/arch/powerpc/kvm/book3s_64_mmu_radix.c b/arch/powerpc/kvm/book3s_64_mmu_radix.c
index 0c854816e653..5cb4e4687107 100644
--- a/arch/powerpc/kvm/book3s_64_mmu_radix.c
+++ b/arch/powerpc/kvm/book3s_64_mmu_radix.c
@@ -195,6 +195,12 @@ static void kvmppc_pte_free(pte_t *ptep)
195 kmem_cache_free(kvm_pte_cache, ptep); 195 kmem_cache_free(kvm_pte_cache, ptep);
196} 196}
197 197
198/* Like pmd_huge() and pmd_large(), but works regardless of config options */
199static inline int pmd_is_leaf(pmd_t pmd)
200{
201 return !!(pmd_val(pmd) & _PAGE_PTE);
202}
203
198static int kvmppc_create_pte(struct kvm *kvm, pte_t pte, unsigned long gpa, 204static int kvmppc_create_pte(struct kvm *kvm, pte_t pte, unsigned long gpa,
199 unsigned int level, unsigned long mmu_seq) 205 unsigned int level, unsigned long mmu_seq)
200{ 206{
@@ -219,7 +225,7 @@ static int kvmppc_create_pte(struct kvm *kvm, pte_t pte, unsigned long gpa,
219 else 225 else
220 new_pmd = pmd_alloc_one(kvm->mm, gpa); 226 new_pmd = pmd_alloc_one(kvm->mm, gpa);
221 227
222 if (level == 0 && !(pmd && pmd_present(*pmd))) 228 if (level == 0 && !(pmd && pmd_present(*pmd) && !pmd_is_leaf(*pmd)))
223 new_ptep = kvmppc_pte_alloc(); 229 new_ptep = kvmppc_pte_alloc();
224 230
225 /* Check if we might have been invalidated; let the guest retry if so */ 231 /* Check if we might have been invalidated; let the guest retry if so */
@@ -244,12 +250,30 @@ static int kvmppc_create_pte(struct kvm *kvm, pte_t pte, unsigned long gpa,
244 new_pmd = NULL; 250 new_pmd = NULL;
245 } 251 }
246 pmd = pmd_offset(pud, gpa); 252 pmd = pmd_offset(pud, gpa);
247 if (pmd_large(*pmd)) { 253 if (pmd_is_leaf(*pmd)) {
248 /* Someone else has instantiated a large page here; retry */ 254 unsigned long lgpa = gpa & PMD_MASK;
249 ret = -EAGAIN; 255
250 goto out_unlock; 256 /*
251 } 257 * If we raced with another CPU which has just put
252 if (level == 1 && !pmd_none(*pmd)) { 258 * a 2MB pte in after we saw a pte page, try again.
259 */
260 if (level == 0 && !new_ptep) {
261 ret = -EAGAIN;
262 goto out_unlock;
263 }
264 /* Valid 2MB page here already, remove it */
265 old = kvmppc_radix_update_pte(kvm, pmdp_ptep(pmd),
266 ~0UL, 0, lgpa, PMD_SHIFT);
267 kvmppc_radix_tlbie_page(kvm, lgpa, PMD_SHIFT);
268 if (old & _PAGE_DIRTY) {
269 unsigned long gfn = lgpa >> PAGE_SHIFT;
270 struct kvm_memory_slot *memslot;
271 memslot = gfn_to_memslot(kvm, gfn);
272 if (memslot && memslot->dirty_bitmap)
273 kvmppc_update_dirty_map(memslot,
274 gfn, PMD_SIZE);
275 }
276 } else if (level == 1 && !pmd_none(*pmd)) {
253 /* 277 /*
254 * There's a page table page here, but we wanted 278 * There's a page table page here, but we wanted
255 * to install a large page. Tell the caller and let 279 * to install a large page. Tell the caller and let
@@ -412,28 +436,24 @@ int kvmppc_book3s_radix_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
412 } else { 436 } else {
413 page = pages[0]; 437 page = pages[0];
414 pfn = page_to_pfn(page); 438 pfn = page_to_pfn(page);
415 if (PageHuge(page)) { 439 if (PageCompound(page)) {
416 page = compound_head(page); 440 pte_size <<= compound_order(compound_head(page));
417 pte_size <<= compound_order(page);
418 /* See if we can insert a 2MB large-page PTE here */ 441 /* See if we can insert a 2MB large-page PTE here */
419 if (pte_size >= PMD_SIZE && 442 if (pte_size >= PMD_SIZE &&
420 (gpa & PMD_MASK & PAGE_MASK) == 443 (gpa & (PMD_SIZE - PAGE_SIZE)) ==
421 (hva & PMD_MASK & PAGE_MASK)) { 444 (hva & (PMD_SIZE - PAGE_SIZE))) {
422 level = 1; 445 level = 1;
423 pfn &= ~((PMD_SIZE >> PAGE_SHIFT) - 1); 446 pfn &= ~((PMD_SIZE >> PAGE_SHIFT) - 1);
424 } 447 }
425 } 448 }
426 /* See if we can provide write access */ 449 /* See if we can provide write access */
427 if (writing) { 450 if (writing) {
428 /*
429 * We assume gup_fast has set dirty on the host PTE.
430 */
431 pgflags |= _PAGE_WRITE; 451 pgflags |= _PAGE_WRITE;
432 } else { 452 } else {
433 local_irq_save(flags); 453 local_irq_save(flags);
434 ptep = find_current_mm_pte(current->mm->pgd, 454 ptep = find_current_mm_pte(current->mm->pgd,
435 hva, NULL, NULL); 455 hva, NULL, NULL);
436 if (ptep && pte_write(*ptep) && pte_dirty(*ptep)) 456 if (ptep && pte_write(*ptep))
437 pgflags |= _PAGE_WRITE; 457 pgflags |= _PAGE_WRITE;
438 local_irq_restore(flags); 458 local_irq_restore(flags);
439 } 459 }
@@ -459,18 +479,15 @@ int kvmppc_book3s_radix_page_fault(struct kvm_run *run, struct kvm_vcpu *vcpu,
459 pte = pfn_pte(pfn, __pgprot(pgflags)); 479 pte = pfn_pte(pfn, __pgprot(pgflags));
460 ret = kvmppc_create_pte(kvm, pte, gpa, level, mmu_seq); 480 ret = kvmppc_create_pte(kvm, pte, gpa, level, mmu_seq);
461 } 481 }
462 if (ret == 0 || ret == -EAGAIN)
463 ret = RESUME_GUEST;
464 482
465 if (page) { 483 if (page) {
466 /* 484 if (!ret && (pgflags & _PAGE_WRITE))
467 * We drop pages[0] here, not page because page might 485 set_page_dirty_lock(page);
468 * have been set to the head page of a compound, but 486 put_page(page);
469 * we have to drop the reference on the correct tail
470 * page to match the get inside gup()
471 */
472 put_page(pages[0]);
473 } 487 }
488
489 if (ret == 0 || ret == -EAGAIN)
490 ret = RESUME_GUEST;
474 return ret; 491 return ret;
475} 492}
476 493
@@ -644,7 +661,7 @@ void kvmppc_free_radix(struct kvm *kvm)
644 continue; 661 continue;
645 pmd = pmd_offset(pud, 0); 662 pmd = pmd_offset(pud, 0);
646 for (im = 0; im < PTRS_PER_PMD; ++im, ++pmd) { 663 for (im = 0; im < PTRS_PER_PMD; ++im, ++pmd) {
647 if (pmd_huge(*pmd)) { 664 if (pmd_is_leaf(*pmd)) {
648 pmd_clear(pmd); 665 pmd_clear(pmd);
649 continue; 666 continue;
650 } 667 }
diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c
index 89707354c2ef..9cb9448163c4 100644
--- a/arch/powerpc/kvm/book3s_hv.c
+++ b/arch/powerpc/kvm/book3s_hv.c
@@ -2885,7 +2885,7 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)
2885 */ 2885 */
2886 trace_hardirqs_on(); 2886 trace_hardirqs_on();
2887 2887
2888 guest_enter(); 2888 guest_enter_irqoff();
2889 2889
2890 srcu_idx = srcu_read_lock(&vc->kvm->srcu); 2890 srcu_idx = srcu_read_lock(&vc->kvm->srcu);
2891 2891
@@ -2893,8 +2893,6 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)
2893 2893
2894 srcu_read_unlock(&vc->kvm->srcu, srcu_idx); 2894 srcu_read_unlock(&vc->kvm->srcu, srcu_idx);
2895 2895
2896 guest_exit();
2897
2898 trace_hardirqs_off(); 2896 trace_hardirqs_off();
2899 set_irq_happened(trap); 2897 set_irq_happened(trap);
2900 2898
@@ -2937,6 +2935,7 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc)
2937 kvmppc_set_host_core(pcpu); 2935 kvmppc_set_host_core(pcpu);
2938 2936
2939 local_irq_enable(); 2937 local_irq_enable();
2938 guest_exit();
2940 2939
2941 /* Let secondaries go back to the offline loop */ 2940 /* Let secondaries go back to the offline loop */
2942 for (i = 0; i < controlled_threads; ++i) { 2941 for (i = 0; i < controlled_threads; ++i) {
@@ -3656,15 +3655,17 @@ static int kvmppc_hv_setup_htab_rma(struct kvm_vcpu *vcpu)
3656 goto up_out; 3655 goto up_out;
3657 3656
3658 psize = vma_kernel_pagesize(vma); 3657 psize = vma_kernel_pagesize(vma);
3659 porder = __ilog2(psize);
3660 3658
3661 up_read(&current->mm->mmap_sem); 3659 up_read(&current->mm->mmap_sem);
3662 3660
3663 /* We can handle 4k, 64k or 16M pages in the VRMA */ 3661 /* We can handle 4k, 64k or 16M pages in the VRMA */