Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/djbw/async_tx
[pandora-kernel.git] / arch / powerpc / kvm / book3s_64_mmu_host.c
index f2899b2..e4b5744 100644 (file)
 
 static void invalidate_pte(struct hpte_cache *pte)
 {
-       dprintk_mmu("KVM: Flushing SPT %d: 0x%llx (0x%llx) -> 0x%llx\n",
-                   i, pte->pte.eaddr, pte->pte.vpage, pte->host_va);
+       dprintk_mmu("KVM: Flushing SPT: 0x%lx (0x%llx) -> 0x%llx\n",
+                   pte->pte.eaddr, pte->pte.vpage, pte->host_va);
 
        ppc_md.hpte_invalidate(pte->slot, pte->host_va,
                               MMU_PAGE_4K, MMU_SEGSIZE_256M,
                               false);
        pte->host_va = 0;
-       kvm_release_pfn_dirty(pte->pfn);
+
+       if (pte->pte.may_write)
+               kvm_release_pfn_dirty(pte->pfn);
+       else
+               kvm_release_pfn_clean(pte->pfn);
 }
 
-void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, u64 guest_ea, u64 ea_mask)
+void kvmppc_mmu_pte_flush(struct kvm_vcpu *vcpu, ulong guest_ea, ulong ea_mask)
 {
        int i;
 
-       dprintk_mmu("KVM: Flushing %d Shadow PTEs: 0x%llx & 0x%llx\n",
+       dprintk_mmu("KVM: Flushing %d Shadow PTEs: 0x%lx & 0x%lx\n",
                    vcpu->arch.hpte_cache_offset, guest_ea, ea_mask);
        BUG_ON(vcpu->arch.hpte_cache_offset > HPTEG_CACHE_NUM);
 
@@ -106,12 +110,12 @@ void kvmppc_mmu_pte_vflush(struct kvm_vcpu *vcpu, u64 guest_vp, u64 vp_mask)
        }
 }
 
-void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, u64 pa_start, u64 pa_end)
+void kvmppc_mmu_pte_pflush(struct kvm_vcpu *vcpu, ulong pa_start, ulong pa_end)
 {
        int i;
 
-       dprintk_mmu("KVM: Flushing %d Shadow pPTEs: 0x%llx & 0x%llx\n",
-                   vcpu->arch.hpte_cache_offset, guest_pa, pa_mask);
+       dprintk_mmu("KVM: Flushing %d Shadow pPTEs: 0x%lx & 0x%lx\n",
+                   vcpu->arch.hpte_cache_offset, pa_start, pa_end);
        BUG_ON(vcpu->arch.hpte_cache_offset > HPTEG_CACHE_NUM);
 
        for (i = 0; i < vcpu->arch.hpte_cache_offset; i++) {
@@ -182,7 +186,7 @@ static struct kvmppc_sid_map *find_sid_vsid(struct kvm_vcpu *vcpu, u64 gvsid)
        sid_map_mask = kvmppc_sid_hash(vcpu, gvsid);
        map = &to_book3s(vcpu)->sid_map[sid_map_mask];
        if (map->guest_vsid == gvsid) {
-               dprintk_slb("SLB: Searching 0x%llx -> 0x%llx\n",
+               dprintk_slb("SLB: Searching: 0x%llx -> 0x%llx\n",
                            gvsid, map->host_vsid);
                return map;
        }
@@ -194,7 +198,8 @@ static struct kvmppc_sid_map *find_sid_vsid(struct kvm_vcpu *vcpu, u64 gvsid)
                return map;
        }
 
-       dprintk_slb("SLB: Searching 0x%llx -> not found\n", gvsid);
+       dprintk_slb("SLB: Searching %d/%d: 0x%llx -> not found\n",
+                   sid_map_mask, SID_MAP_MASK - sid_map_mask, gvsid);
        return NULL;
 }
 
@@ -212,7 +217,7 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte)
        /* Get host physical address for gpa */
        hpaddr = gfn_to_pfn(vcpu->kvm, orig_pte->raddr >> PAGE_SHIFT);
        if (kvm_is_error_hva(hpaddr)) {
-               printk(KERN_INFO "Couldn't get guest page for gfn %llx!\n", orig_pte->eaddr);
+               printk(KERN_INFO "Couldn't get guest page for gfn %lx!\n", orig_pte->eaddr);
                return -EINVAL;
        }
        hpaddr <<= PAGE_SHIFT;
@@ -227,10 +232,16 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte)
        vcpu->arch.mmu.esid_to_vsid(vcpu, orig_pte->eaddr >> SID_SHIFT, &vsid);
        map = find_sid_vsid(vcpu, vsid);
        if (!map) {
-               kvmppc_mmu_map_segment(vcpu, orig_pte->eaddr);
+               ret = kvmppc_mmu_map_segment(vcpu, orig_pte->eaddr);
+               WARN_ON(ret < 0);
                map = find_sid_vsid(vcpu, vsid);
        }
-       BUG_ON(!map);
+       if (!map) {
+               printk(KERN_ERR "KVM: Segment map for 0x%llx (0x%lx) failed\n",
+                               vsid, orig_pte->eaddr);
+               WARN_ON(true);
+               return -EINVAL;
+       }
 
        vsid = map->host_vsid;
        va = hpt_va(orig_pte->eaddr, vsid, MMU_SEGSIZE_256M);
@@ -257,26 +268,26 @@ map_again:
 
        if (ret < 0) {
                /* If we couldn't map a primary PTE, try a secondary */
-#ifdef USE_SECONDARY
                hash = ~hash;
+               vflags ^= HPTE_V_SECONDARY;
                attempt++;
-               if (attempt % 2)
-                       vflags = HPTE_V_SECONDARY;
-               else
-                       vflags = 0;
-#else
-               attempt = 2;
-#endif
                goto map_again;
        } else {
                int hpte_id = kvmppc_mmu_hpte_cache_next(vcpu);
                struct hpte_cache *pte = &vcpu->arch.hpte_cache[hpte_id];
 
-               dprintk_mmu("KVM: %c%c Map 0x%llx: [%lx] 0x%lx (0x%llx) -> %lx\n",
+               dprintk_mmu("KVM: %c%c Map 0x%lx: [%lx] 0x%lx (0x%llx) -> %lx\n",
                            ((rflags & HPTE_R_PP) == 3) ? '-' : 'w',
                            (rflags & HPTE_R_N) ? '-' : 'x',
                            orig_pte->eaddr, hpteg, va, orig_pte->vpage, hpaddr);
 
+               /* The ppc_md code may give us a secondary entry even though we
+                  asked for a primary. Fix up. */
+               if ((ret & _PTEIDX_SECONDARY) && !(vflags & HPTE_V_SECONDARY)) {
+                       hash = ~hash;
+                       hpteg = ((hash & htab_hash_mask) * HPTES_PER_GROUP);
+               }
+
                pte->slot = hpteg + (ret & 7);
                pte->host_va = va;
                pte->pte = *orig_pte;
@@ -321,6 +332,9 @@ static struct kvmppc_sid_map *create_sid_map(struct kvm_vcpu *vcpu, u64 gvsid)
        map->guest_vsid = gvsid;
        map->valid = true;
 
+       dprintk_slb("SLB: New mapping at %d: 0x%llx -> 0x%llx\n",
+                   sid_map_mask, gvsid, map->host_vsid);
+
        return map;
 }
 
@@ -331,14 +345,14 @@ static int kvmppc_mmu_next_segment(struct kvm_vcpu *vcpu, ulong esid)
        int found_inval = -1;
        int r;
 
-       if (!get_paca()->kvm_slb_max)
-               get_paca()->kvm_slb_max = 1;
+       if (!to_svcpu(vcpu)->slb_max)
+               to_svcpu(vcpu)->slb_max = 1;
 
        /* Are we overwriting? */
-       for (i = 1; i < get_paca()->kvm_slb_max; i++) {
-               if (!(get_paca()->kvm_slb[i].esid & SLB_ESID_V))
+       for (i = 1; i < to_svcpu(vcpu)->slb_max; i++) {
+               if (!(to_svcpu(vcpu)->slb[i].esid & SLB_ESID_V))
                        found_inval = i;
-               else if ((get_paca()->kvm_slb[i].esid & ESID_MASK) == esid)
+               else if ((to_svcpu(vcpu)->slb[i].esid & ESID_MASK) == esid)
                        return i;
        }
 
@@ -352,11 +366,11 @@ static int kvmppc_mmu_next_segment(struct kvm_vcpu *vcpu, ulong esid)
                max_slb_size = mmu_slb_size;
 
        /* Overflowing -> purge */
-       if ((get_paca()->kvm_slb_max) == max_slb_size)
+       if ((to_svcpu(vcpu)->slb_max) == max_slb_size)
                kvmppc_mmu_flush_segments(vcpu);
 
-       r = get_paca()->kvm_slb_max;
-       get_paca()->kvm_slb_max++;
+       r = to_svcpu(vcpu)->slb_max;
+       to_svcpu(vcpu)->slb_max++;
 
        return r;
 }
@@ -374,7 +388,7 @@ int kvmppc_mmu_map_segment(struct kvm_vcpu *vcpu, ulong eaddr)
 
        if (vcpu->arch.mmu.esid_to_vsid(vcpu, esid, &gvsid)) {
                /* Invalidate an entry */
-               get_paca()->kvm_slb[slb_index].esid = 0;
+               to_svcpu(vcpu)->slb[slb_index].esid = 0;
                return -ENOENT;
        }
 
@@ -388,8 +402,8 @@ int kvmppc_mmu_map_segment(struct kvm_vcpu *vcpu, ulong eaddr)
        slb_vsid &= ~SLB_VSID_KP;
        slb_esid |= slb_index;
 
-       get_paca()->kvm_slb[slb_index].esid = slb_esid;
-       get_paca()->kvm_slb[slb_index].vsid = slb_vsid;
+       to_svcpu(vcpu)->slb[slb_index].esid = slb_esid;
+       to_svcpu(vcpu)->slb[slb_index].vsid = slb_vsid;
 
        dprintk_slb("slbmte %#llx, %#llx\n", slb_vsid, slb_esid);
 
@@ -398,11 +412,29 @@ int kvmppc_mmu_map_segment(struct kvm_vcpu *vcpu, ulong eaddr)
 
 void kvmppc_mmu_flush_segments(struct kvm_vcpu *vcpu)
 {
-       get_paca()->kvm_slb_max = 1;
-       get_paca()->kvm_slb[0].esid = 0;
+       to_svcpu(vcpu)->slb_max = 1;
+       to_svcpu(vcpu)->slb[0].esid = 0;
 }
 
 void kvmppc_mmu_destroy(struct kvm_vcpu *vcpu)
 {
        kvmppc_mmu_pte_flush(vcpu, 0, 0);
+       __destroy_context(to_book3s(vcpu)->context_id);
+}
+
+int kvmppc_mmu_init(struct kvm_vcpu *vcpu)
+{
+       struct kvmppc_vcpu_book3s *vcpu3s = to_book3s(vcpu);
+       int err;
+
+       err = __init_new_context();
+       if (err < 0)
+               return -1;
+       vcpu3s->context_id = err;
+
+       vcpu3s->vsid_max = ((vcpu3s->context_id + 1) << USER_ESID_BITS) - 1;
+       vcpu3s->vsid_first = vcpu3s->context_id << USER_ESID_BITS;
+       vcpu3s->vsid_next = vcpu3s->vsid_first;
+
+       return 0;
 }