KVM: PPC: Fix nested guest RC bits update
[linux-2.6-microblaze.git] / arch / powerpc / kvm / book3s_hv_rm_mmu.c
index 2203054..88da276 100644 (file)
@@ -210,7 +210,7 @@ long kvmppc_do_h_enter(struct kvm *kvm, unsigned long flags,
        pte_t *ptep;
        unsigned int writing;
        unsigned long mmu_seq;
-       unsigned long rcbits, irq_flags = 0;
+       unsigned long rcbits;
 
        if (kvm_is_radix(kvm))
                return H_FUNCTION;
@@ -248,17 +248,9 @@ long kvmppc_do_h_enter(struct kvm *kvm, unsigned long flags,
 
        /* Translate to host virtual address */
        hva = __gfn_to_hva_memslot(memslot, gfn);
-       /*
-        * If we had a page table table change after lookup, we would
-        * retry via mmu_notifier_retry.
-        */
-       if (!realmode)
-               local_irq_save(irq_flags);
-       /*
-        * If called in real mode we have MSR_EE = 0. Otherwise
-        * we disable irq above.
-        */
-       ptep = __find_linux_pte(pgdir, hva, NULL, &hpage_shift);
+
+       arch_spin_lock(&kvm->mmu_lock.rlock.raw_lock);
+       ptep = find_kvm_host_pte(kvm, mmu_seq, hva, &hpage_shift);
        if (ptep) {
                pte_t pte;
                unsigned int host_pte_size;
@@ -272,8 +264,7 @@ long kvmppc_do_h_enter(struct kvm *kvm, unsigned long flags,
                 * to <= host page size, if host is using hugepage
                 */
                if (host_pte_size < psize) {
-                       if (!realmode)
-                               local_irq_restore(flags);
+                       arch_spin_unlock(&kvm->mmu_lock.rlock.raw_lock);
                        return H_PARAMETER;
                }
                pte = kvmppc_read_update_linux_pte(ptep, writing);
@@ -287,8 +278,7 @@ long kvmppc_do_h_enter(struct kvm *kvm, unsigned long flags,
                        pa |= gpa & ~PAGE_MASK;
                }
        }
-       if (!realmode)
-               local_irq_restore(irq_flags);
+       arch_spin_unlock(&kvm->mmu_lock.rlock.raw_lock);
 
        ptel &= HPTE_R_KEY | HPTE_R_PP0 | (psize-1);
        ptel |= pa;
@@ -888,8 +878,8 @@ long kvmppc_h_clear_mod(struct kvm_vcpu *vcpu, unsigned long flags,
        return ret;
 }
 
-static int kvmppc_get_hpa(struct kvm_vcpu *vcpu, unsigned long gpa,
-                         int writing, unsigned long *hpa,
+static int kvmppc_get_hpa(struct kvm_vcpu *vcpu, unsigned long mmu_seq,
+                         unsigned long gpa, int writing, unsigned long *hpa,
                          struct kvm_memory_slot **memslot_p)
 {
        struct kvm *kvm = vcpu->kvm;
@@ -908,7 +898,7 @@ static int kvmppc_get_hpa(struct kvm_vcpu *vcpu, unsigned long gpa,
        hva = __gfn_to_hva_memslot(memslot, gfn);
 
        /* Try to find the host pte for that virtual address */
-       ptep = __find_linux_pte(vcpu->arch.pgdir, hva, NULL, &shift);
+       ptep = find_kvm_host_pte(kvm, mmu_seq, hva, &shift);
        if (!ptep)
                return H_TOO_HARD;
        pte = kvmppc_read_update_linux_pte(ptep, writing);
@@ -943,16 +933,11 @@ static long kvmppc_do_h_page_init_zero(struct kvm_vcpu *vcpu,
        mmu_seq = kvm->mmu_notifier_seq;
        smp_rmb();
 
-       ret = kvmppc_get_hpa(vcpu, dest, 1, &pa, &memslot);
-       if (ret != H_SUCCESS)
-               return ret;
+       arch_spin_lock(&kvm->mmu_lock.rlock.raw_lock);
 
-       /* Check if we've been invalidated */
-       raw_spin_lock(&kvm->mmu_lock.rlock);
-       if (mmu_notifier_retry(kvm, mmu_seq)) {
-               ret = H_TOO_HARD;
+       ret = kvmppc_get_hpa(vcpu, mmu_seq, dest, 1, &pa, &memslot);
+       if (ret != H_SUCCESS)
                goto out_unlock;
-       }
 
        /* Zero the page */
        for (i = 0; i < SZ_4K; i += L1_CACHE_BYTES, pa += L1_CACHE_BYTES)
@@ -960,7 +945,7 @@ static long kvmppc_do_h_page_init_zero(struct kvm_vcpu *vcpu,
        kvmppc_update_dirty_map(memslot, dest >> PAGE_SHIFT, PAGE_SIZE);
 
 out_unlock:
-       raw_spin_unlock(&kvm->mmu_lock.rlock);
+       arch_spin_unlock(&kvm->mmu_lock.rlock.raw_lock);
        return ret;
 }
 
@@ -976,19 +961,14 @@ static long kvmppc_do_h_page_init_copy(struct kvm_vcpu *vcpu,
        mmu_seq = kvm->mmu_notifier_seq;
        smp_rmb();
 
-       ret = kvmppc_get_hpa(vcpu, dest, 1, &dest_pa, &dest_memslot);
-       if (ret != H_SUCCESS)
-               return ret;
-       ret = kvmppc_get_hpa(vcpu, src, 0, &src_pa, NULL);
+       arch_spin_lock(&kvm->mmu_lock.rlock.raw_lock);
+       ret = kvmppc_get_hpa(vcpu, mmu_seq, dest, 1, &dest_pa, &dest_memslot);
        if (ret != H_SUCCESS)
-               return ret;
+               goto out_unlock;
 
-       /* Check if we've been invalidated */
-       raw_spin_lock(&kvm->mmu_lock.rlock);
-       if (mmu_notifier_retry(kvm, mmu_seq)) {
-               ret = H_TOO_HARD;
+       ret = kvmppc_get_hpa(vcpu, mmu_seq, src, 0, &src_pa, NULL);
+       if (ret != H_SUCCESS)
                goto out_unlock;
-       }
 
        /* Copy the page */
        memcpy((void *)dest_pa, (void *)src_pa, SZ_4K);
@@ -996,7 +976,7 @@ static long kvmppc_do_h_page_init_copy(struct kvm_vcpu *vcpu,
        kvmppc_update_dirty_map(dest_memslot, dest >> PAGE_SHIFT, PAGE_SIZE);
 
 out_unlock:
-       raw_spin_unlock(&kvm->mmu_lock.rlock);
+       arch_spin_unlock(&kvm->mmu_lock.rlock.raw_lock);
        return ret;
 }
 
@@ -1260,7 +1240,7 @@ long kvmppc_hpte_hv_fault(struct kvm_vcpu *vcpu, unsigned long addr,
        status &= ~DSISR_NOHPTE;        /* DSISR_NOHPTE == SRR1_ISI_NOPT */
        if (!data) {
                if (gr & (HPTE_R_N | HPTE_R_G))
-                       return status | SRR1_ISI_N_OR_G;
+                       return status | SRR1_ISI_N_G_OR_CIP;
                if (!hpte_read_permission(pp, slb_v & key))
                        return status | SRR1_ISI_PROT;
        } else if (status & DSISR_ISSTORE) {