aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2014-04-14 19:52:27 +1000
committerWang Sen <wangsen@linux.vnet.ibm.com>2014-04-16 11:15:21 +0800
commit846274db638806ae00a048339f345c4779e92b1e (patch)
treea8351a1108ef772ccfd9ac04cd52b1aeb066bbc6
parenta758d7ee38f23bfb828f7e0abf470ca68191fe5c (diff)
downloadpowerkvm-846274db638806ae00a048339f345c4779e92b1e.tar.gz
KVM: PPC: Book3S PR: Implement ARCH_COMPAT register
This provides basic support for the KVM_REG_PPC_ARCH_COMPAT register in PR KVM. At present the value is sanity-checked when set, but doesn't actually affect anything yet. Implementing this makes it possible to use a qemu command-line argument such as "-cpu host,compat=power7" on a POWER8 machine, just as we would with HV KVM. Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r--arch/powerpc/include/asm/kvm_host.h2
-rw-r--r--arch/powerpc/kvm/book3s_pr.c40
2 files changed, 42 insertions, 0 deletions
diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h
index 160faad31e8cf..19144ebb28d83 100644
--- a/arch/powerpc/include/asm/kvm_host.h
+++ b/arch/powerpc/include/asm/kvm_host.h
@@ -576,6 +576,8 @@ struct kvm_vcpu_arch {
u32 ivor[64];
ulong ivpr;
u32 pvr;
+ u32 pvr_arch;
+ u32 compat_arch;
u32 shadow_pid;
u32 shadow_pid1;
diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c
index dc61cbafd6b71..955c75ade84bb 100644
--- a/arch/powerpc/kvm/book3s_pr.c
+++ b/arch/powerpc/kvm/book3s_pr.c
@@ -298,6 +298,28 @@ static void kvmppc_set_msr_pr(struct kvm_vcpu *vcpu, u64 msr)
kvmppc_handle_ext(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL, MSR_FP);
}
+/*
+ * Evaluate the architecture level of a PVR value.
+ * The result is in terms of PVR_ARCH_* values.
+ */
+static u32 pvr_to_arch(u32 pvr)
+{
+ switch (PVR_VER(pvr)) {
+ case PVR_POWER5p:
+ return PVR_ARCH_204;
+ case PVR_POWER6:
+ return PVR_ARCH_205;
+ case PVR_POWER7:
+ case PVR_POWER7p:
+ return PVR_ARCH_206;
+ case PVR_POWER8:
+ case PVR_POWER8E:
+ return PVR_ARCH_207;
+ default:
+ return 0;
+ }
+}
+
void kvmppc_set_pvr_pr(struct kvm_vcpu *vcpu, u32 pvr)
{
u32 host_pvr;
@@ -373,6 +395,18 @@ void kvmppc_set_pvr_pr(struct kvm_vcpu *vcpu, u32 pvr)
/* Enable HID2.PSE - in case we need it later */
mtspr(SPRN_HID2_GEKKO, mfspr(SPRN_HID2_GEKKO) | (1 << 29));
}
+
+ vcpu->arch.pvr_arch = pvr_to_arch(pvr);
+ if (vcpu->arch.pvr_arch < vcpu->arch.compat_arch)
+ vcpu->arch.compat_arch = 0;
+}
+
+static int kvmppc_set_arch_compat(struct kvm_vcpu *vcpu, u32 compat_arch)
+{
+ if (compat_arch > vcpu->arch.pvr_arch)
+ return -EINVAL;
+ vcpu->arch.compat_arch = vcpu->arch.pvr_arch;
+ return 0;
}
/* Book3s_32 CPUs always have 32 bytes cache line size, which Linux assumes. To
@@ -1087,6 +1121,9 @@ static int kvmppc_get_one_reg_pr(struct kvm_vcpu *vcpu, u64 id,
case KVM_REG_PPC_HIOR:
*val = get_reg_val(id, to_book3s(vcpu)->hior);
break;
+ case KVM_REG_PPC_ARCH_COMPAT:
+ *val = get_reg_val(id, vcpu->arch.compat_arch);
+ break;
default:
r = -EINVAL;
break;
@@ -1105,6 +1142,9 @@ static int kvmppc_set_one_reg_pr(struct kvm_vcpu *vcpu, u64 id,
to_book3s(vcpu)->hior = set_reg_val(id, *val);
to_book3s(vcpu)->hior_explicit = true;
break;
+ case KVM_REG_PPC_ARCH_COMPAT:
+ r = kvmppc_set_arch_compat(vcpu, set_reg_val(id, *val));
+ break;
default:
r = -EINVAL;
break;