]> git.hungrycats.org Git - linux/commitdiff
KVM: PPC: Book3S: Fix LPCR one_reg interface
authorAlexey Kardashevskiy <aik@ozlabs.ru>
Sat, 19 Jul 2014 07:59:34 +0000 (17:59 +1000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 5 Sep 2014 23:36:32 +0000 (16:36 -0700)
commit a0840240c0c6bcbac8f0f5db11f95c19aaf9b52f upstream.

Unfortunately, the LPCR got defined as a 32-bit register in the
one_reg interface.  This is unfortunate because KVM allows userspace
to control the DPFD (default prefetch depth) field, which is in the
upper 32 bits.  The result is that DPFD always get set to 0, which
reduces performance in the guest.

We can't just change KVM_REG_PPC_LPCR to be a 64-bit register ID,
since that would break existing userspace binaries.  Instead we define
a new KVM_REG_PPC_LPCR_64 id which is 64-bit.  Userspace can still use
the old KVM_REG_PPC_LPCR id, but it now only modifies those fields in
the bottom 32 bits that userspace can modify (ILE, TC and AIL).
If userspace uses the new KVM_REG_PPC_LPCR_64 id, it can modify DPFD
as well.

Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
Signed-off-by: Paul Mackerras <paulus@samba.org>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Documentation/virtual/kvm/api.txt
arch/powerpc/include/uapi/asm/kvm.h
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/kvm/book3s_pr.c

index 0fe36497642c90087514e4d2b0707d7f794d0949..612e6e99d1e572239e12dc01587635bb8ca39b77 100644 (file)
@@ -1869,7 +1869,8 @@ registers, find a list below:
   PPC   | KVM_REG_PPC_PID      | 64
   PPC   | KVM_REG_PPC_ACOP     | 64
   PPC   | KVM_REG_PPC_VRSAVE   | 32
-  PPC   | KVM_REG_PPC_LPCR     | 64
+  PPC   | KVM_REG_PPC_LPCR     | 32
+  PPC   | KVM_REG_PPC_LPCR_64  | 64
   PPC   | KVM_REG_PPC_PPR      | 64
   PPC   | KVM_REG_PPC_ARCH_COMPAT 32
   PPC   | KVM_REG_PPC_DABRX     | 32
index 2bc4a9409a934e4e7416e5a058191eca9dfe2e72..de7d426a9b0ce624dc900779f79fee45e8da4421 100644 (file)
@@ -548,6 +548,7 @@ struct kvm_get_htab_header {
 
 #define KVM_REG_PPC_VRSAVE     (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb4)
 #define KVM_REG_PPC_LPCR       (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb5)
+#define KVM_REG_PPC_LPCR_64    (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb5)
 #define KVM_REG_PPC_PPR                (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb6)
 
 /* Architecture compatibility level */
index 7a12edbb61e7c2c9f6851bc0ef01e6b0b398ed83..0f3a192374446b72c65b056fbd66dec4cc0c14a1 100644 (file)
@@ -785,7 +785,8 @@ static int kvm_arch_vcpu_ioctl_set_sregs_hv(struct kvm_vcpu *vcpu,
        return 0;
 }
 
-static void kvmppc_set_lpcr(struct kvm_vcpu *vcpu, u64 new_lpcr)
+static void kvmppc_set_lpcr(struct kvm_vcpu *vcpu, u64 new_lpcr,
+               bool preserve_top32)
 {
        struct kvmppc_vcore *vc = vcpu->arch.vcore;
        u64 mask;
@@ -820,6 +821,10 @@ static void kvmppc_set_lpcr(struct kvm_vcpu *vcpu, u64 new_lpcr)
        mask = LPCR_DPFD | LPCR_ILE | LPCR_TC;
        if (cpu_has_feature(CPU_FTR_ARCH_207S))
                mask |= LPCR_AIL;
+
+       /* Broken 32-bit version of LPCR must not clear top bits */
+       if (preserve_top32)
+               mask &= 0xFFFFFFFF;
        vc->lpcr = (vc->lpcr & ~mask) | (new_lpcr & mask);
        spin_unlock(&vc->lock);
 }
@@ -939,6 +944,7 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
                *val = get_reg_val(id, vcpu->arch.vcore->tb_offset);
                break;
        case KVM_REG_PPC_LPCR:
+       case KVM_REG_PPC_LPCR_64:
                *val = get_reg_val(id, vcpu->arch.vcore->lpcr);
                break;
        case KVM_REG_PPC_PPR:
@@ -1150,7 +1156,10 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
                        ALIGN(set_reg_val(id, *val), 1UL << 24);
                break;
        case KVM_REG_PPC_LPCR:
-               kvmppc_set_lpcr(vcpu, set_reg_val(id, *val));
+               kvmppc_set_lpcr(vcpu, set_reg_val(id, *val), true);
+               break;
+       case KVM_REG_PPC_LPCR_64:
+               kvmppc_set_lpcr(vcpu, set_reg_val(id, *val), false);
                break;
        case KVM_REG_PPC_PPR:
                vcpu->arch.ppr = set_reg_val(id, *val);
index 8eef1e5190773c9c290bf46581e7fd025f7dfaeb..66b7afec250fa5a0abeb18ea9266eb78ae99229f 100644 (file)
@@ -1233,6 +1233,7 @@ static int kvmppc_get_one_reg_pr(struct kvm_vcpu *vcpu, u64 id,
                *val = get_reg_val(id, to_book3s(vcpu)->hior);
                break;
        case KVM_REG_PPC_LPCR:
+       case KVM_REG_PPC_LPCR_64:
                /*
                 * We are only interested in the LPCR_ILE bit
                 */
@@ -1268,6 +1269,7 @@ static int kvmppc_set_one_reg_pr(struct kvm_vcpu *vcpu, u64 id,
                to_book3s(vcpu)->hior_explicit = true;
                break;
        case KVM_REG_PPC_LPCR:
+       case KVM_REG_PPC_LPCR_64:
                kvmppc_set_lpcr_pr(vcpu, set_reg_val(id, *val));
                break;
        default: