KVM: PPC: Improve split mode

When in split mode, instruction relocation and data relocation are not equal.

So far we implemented this mode by reserving a special pseudo-VSID for the
two cases and flushing all PTEs when going into split mode, which is slow.

Unfortunately 32bit Linux and Mac OS X use split mode extensively. So to not
slow down things too much, I came up with a different idea: Mark the split
mode with a bit in the VSID and then treat it like any other segment.

This means we can just flush the shadow segment cache, but keep the PTEs
intact. I verified that this works with ppc32 Linux and Mac OS X 10.4
guests and does speed them up.

Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Avi Kivity <avi@redhat.com>
diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c
index f66de7e..397701d 100644
--- a/arch/powerpc/kvm/book3s.c
+++ b/arch/powerpc/kvm/book3s.c
@@ -148,16 +148,8 @@
 		}
 	}
 
-	if (((vcpu->arch.msr & (MSR_IR|MSR_DR)) != (old_msr & (MSR_IR|MSR_DR))) ||
-	    (vcpu->arch.msr & MSR_PR) != (old_msr & MSR_PR)) {
-		bool dr = (vcpu->arch.msr & MSR_DR) ? true : false;
-		bool ir = (vcpu->arch.msr & MSR_IR) ? true : false;
-
-		/* Flush split mode PTEs */
-		if (dr != ir)
-			kvmppc_mmu_pte_vflush(vcpu, VSID_SPLIT_MASK,
-					      VSID_SPLIT_MASK);
-
+	if ((vcpu->arch.msr & (MSR_PR|MSR_IR|MSR_DR)) !=
+		   (old_msr & (MSR_PR|MSR_IR|MSR_DR))) {
 		kvmppc_mmu_flush_segments(vcpu);
 		kvmppc_mmu_map_segment(vcpu, kvmppc_get_pc(vcpu));
 	}
@@ -535,6 +527,7 @@
 	bool is_mmio = false;
 	bool dr = (vcpu->arch.msr & MSR_DR) ? true : false;
 	bool ir = (vcpu->arch.msr & MSR_IR) ? true : false;
+	u64 vsid;
 
 	relocated = data ? dr : ir;
 
@@ -552,13 +545,20 @@
 
 	switch (vcpu->arch.msr & (MSR_DR|MSR_IR)) {
 	case 0:
-		pte.vpage |= VSID_REAL;
+		pte.vpage |= ((u64)VSID_REAL << (SID_SHIFT - 12));
 		break;
 	case MSR_DR:
-		pte.vpage |= VSID_REAL_DR;
-		break;
 	case MSR_IR:
-		pte.vpage |= VSID_REAL_IR;
+		vcpu->arch.mmu.esid_to_vsid(vcpu, eaddr >> SID_SHIFT, &vsid);
+
+		if ((vcpu->arch.msr & (MSR_DR|MSR_IR)) == MSR_DR)
+			pte.vpage |= ((u64)VSID_REAL_DR << (SID_SHIFT - 12));
+		else
+			pte.vpage |= ((u64)VSID_REAL_IR << (SID_SHIFT - 12));
+		pte.vpage |= vsid;
+
+		if (vsid == -1)
+			page_found = -EINVAL;
 		break;
 	}