KVM: PPC: Book3S: Treat VTB as a per-subcore register, not per-thread
authorPaul Mackerras <paulus@ozlabs.org>
Thu, 15 Sep 2016 03:42:52 +0000 (13:42 +1000)
committerPaul Mackerras <paulus@ozlabs.org>
Tue, 27 Sep 2016 04:41:39 +0000 (14:41 +1000)
POWER8 has one virtual timebase (VTB) register per subcore, not one
per CPU thread.  The HV KVM code currently treats VTB as a per-thread
register, which can lead to spurious soft lockup messages from guests
which use the VTB as the time source for the soft lockup detector.
(CPUs before POWER8 did not have the VTB register.)

For HV KVM, this fixes the problem by making only the primary thread
in each virtual core save and restore the VTB value.  With this,
the VTB state becomes part of the kvmppc_vcore structure.  This
also means that "piggybacking" of multiple virtual cores onto one
subcore is not possible on POWER8, because then the virtual cores
would share a single VTB register.

PR KVM emulates a VTB register, which is per-vcpu because PR KVM
has no notion of CPU threads or SMT.  For PR KVM we move the VTB
state into the kvmppc_vcpu_book3s struct.

Cc: stable@vger.kernel.org # v3.14+
Reported-by: Thomas Huth <thuth@redhat.com>
Tested-by: Thomas Huth <thuth@redhat.com>
Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
arch/powerpc/include/asm/kvm_book3s.h
arch/powerpc/include/asm/kvm_host.h
arch/powerpc/kernel/asm-offsets.c
arch/powerpc/kvm/book3s.c
arch/powerpc/kvm/book3s_emulate.c
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/kvm/book3s_hv_rmhandlers.S
arch/powerpc/kvm/book3s_pr.c

index cef2b892245cc18ebeba0961b36f14353e3381c9..5cf306ae0ac37f69f2c2fd2f691161dffc475652 100644 (file)
@@ -101,6 +101,7 @@ struct kvmppc_vcore {
        u32 arch_compat;
        ulong pcr;
        ulong dpdes;            /* doorbell state (POWER8) */
+       ulong vtb;              /* virtual timebase */
        ulong conferring_threads;
        unsigned int halt_poll_ns;
 };
@@ -119,6 +120,7 @@ struct kvmppc_vcpu_book3s {
        u64 sdr1;
        u64 hior;
        u64 msr_mask;
+       u64 vtb;
 #ifdef CONFIG_PPC_BOOK3S_32
        u32 vsid_pool[VSID_POOL_SIZE];
        u32 vsid_next;
index ed30d2ea21b7b3a5630b6965591427172776bf11..28350a294b1e04decfb4fed94a5f89dc2e87d7c9 100644 (file)
@@ -475,7 +475,6 @@ struct kvm_vcpu_arch {
        ulong purr;
        ulong spurr;
        ulong ic;
-       ulong vtb;
        ulong dscr;
        ulong amr;
        ulong uamor;
index b89d14c0352c500cf7cf4b6cc5b13b7db8ec4f77..a51ae9b165e0e104584fa264ac8b5be7a6cdafb0 100644 (file)
@@ -506,7 +506,6 @@ int main(void)
        DEFINE(VCPU_PURR, offsetof(struct kvm_vcpu, arch.purr));
        DEFINE(VCPU_SPURR, offsetof(struct kvm_vcpu, arch.spurr));
        DEFINE(VCPU_IC, offsetof(struct kvm_vcpu, arch.ic));
-       DEFINE(VCPU_VTB, offsetof(struct kvm_vcpu, arch.vtb));
        DEFINE(VCPU_DSCR, offsetof(struct kvm_vcpu, arch.dscr));
        DEFINE(VCPU_AMR, offsetof(struct kvm_vcpu, arch.amr));
        DEFINE(VCPU_UAMOR, offsetof(struct kvm_vcpu, arch.uamor));
@@ -557,6 +556,7 @@ int main(void)
        DEFINE(VCORE_LPCR, offsetof(struct kvmppc_vcore, lpcr));
        DEFINE(VCORE_PCR, offsetof(struct kvmppc_vcore, pcr));
        DEFINE(VCORE_DPDES, offsetof(struct kvmppc_vcore, dpdes));
+       DEFINE(VCORE_VTB, offsetof(struct kvmppc_vcore, vtb));
        DEFINE(VCPU_SLB_E, offsetof(struct kvmppc_slb, orige));
        DEFINE(VCPU_SLB_V, offsetof(struct kvmppc_slb, origv));
        DEFINE(VCPU_SLB_SIZE, sizeof(struct kvmppc_slb));
index ba231a1d43d46835bda1ef4664a91f77e122bc91..b6952dd2315213c1cc31c7565632612e8b806c86 100644 (file)
@@ -599,9 +599,6 @@ int kvmppc_get_one_reg(struct kvm_vcpu *vcpu, u64 id,
                case KVM_REG_PPC_BESCR:
                        *val = get_reg_val(id, vcpu->arch.bescr);
                        break;
-               case KVM_REG_PPC_VTB:
-                       *val = get_reg_val(id, vcpu->arch.vtb);
-                       break;
                case KVM_REG_PPC_IC:
                        *val = get_reg_val(id, vcpu->arch.ic);
                        break;
@@ -673,9 +670,6 @@ int kvmppc_set_one_reg(struct kvm_vcpu *vcpu, u64 id,
                case KVM_REG_PPC_BESCR:
                        vcpu->arch.bescr = set_reg_val(id, *val);
                        break;
-               case KVM_REG_PPC_VTB:
-                       vcpu->arch.vtb = set_reg_val(id, *val);
-                       break;
                case KVM_REG_PPC_IC:
                        vcpu->arch.ic = set_reg_val(id, *val);
                        break;
index 2afdb9c0937dbd3b7471b88d75e17ca714bba1ae..7d9e4ed2e415e50c62f1d55bff930ea8d46e0582 100644 (file)
@@ -579,7 +579,7 @@ int kvmppc_core_emulate_mfspr_pr(struct kvm_vcpu *vcpu, int sprn, ulong *spr_val
                *spr_val = vcpu->arch.spurr;
                break;
        case SPRN_VTB:
-               *spr_val = vcpu->arch.vtb;
+               *spr_val = to_book3s(vcpu)->vtb;
                break;
        case SPRN_IC:
                *spr_val = vcpu->arch.ic;
index 9b3bba643b43e04f6f9a911b520b22c819aec167..c4f8971c954d75348683494798835fa19ce2cf17 100644 (file)
@@ -1199,6 +1199,9 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
        case KVM_REG_PPC_DPDES:
                *val = get_reg_val(id, vcpu->arch.vcore->dpdes);
                break;
+       case KVM_REG_PPC_VTB:
+               *val = get_reg_val(id, vcpu->arch.vcore->vtb);
+               break;
        case KVM_REG_PPC_DAWR:
                *val = get_reg_val(id, vcpu->arch.dawr);
                break;
@@ -1391,6 +1394,9 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
        case KVM_REG_PPC_DPDES:
                vcpu->arch.vcore->dpdes = set_reg_val(id, *val);
                break;
+       case KVM_REG_PPC_VTB:
+               vcpu->arch.vcore->vtb = set_reg_val(id, *val);
+               break;
        case KVM_REG_PPC_DAWR:
                vcpu->arch.dawr = set_reg_val(id, *val);
                break;
@@ -2213,9 +2219,11 @@ static bool can_piggyback_subcore(struct kvmppc_vcore *pvc,
            pvc->lpcr != vc->lpcr)
                return false;
 
-       /* P8 guest with > 1 thread per core would see wrong TIR value */
-       if (cpu_has_feature(CPU_FTR_ARCH_207S) &&
-           (vc->num_threads > 1 || pvc->num_threads > 1))
+       /*
+        * P8 guests can't do piggybacking, because then the
+        * VTB would be shared between the vcpus.
+        */
+       if (cpu_has_feature(CPU_FTR_ARCH_207S))
                return false;
 
        n_thr = cip->subcore_threads[sub] + pvc->num_threads;
index 7cc924b5eea272f75d078ba50aa36217c7ba25d9..c3c1d1bcfc67dad17b522b029af9f4ed07dcdab0 100644 (file)
@@ -644,9 +644,11 @@ ALT_FTR_SECTION_END_IFSET(CPU_FTR_ARCH_207S)
 38:
 
 BEGIN_FTR_SECTION
-       /* DPDES is shared between threads */
+       /* DPDES and VTB are shared between threads */
        ld      r8, VCORE_DPDES(r5)
+       ld      r7, VCORE_VTB(r5)
        mtspr   SPRN_DPDES, r8
+       mtspr   SPRN_VTB, r7
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
 
        /* Mark the subcore state as inside guest */
@@ -806,10 +808,8 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
        mtspr   SPRN_CIABR, r7
        mtspr   SPRN_TAR, r8
        ld      r5, VCPU_IC(r4)
-       ld      r6, VCPU_VTB(r4)
-       mtspr   SPRN_IC, r5
-       mtspr   SPRN_VTB, r6
        ld      r8, VCPU_EBBHR(r4)
+       mtspr   SPRN_IC, r5
        mtspr   SPRN_EBBHR, r8
        ld      r5, VCPU_EBBRR(r4)
        ld      r6, VCPU_BESCR(r4)
@@ -1334,10 +1334,8 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
        stw     r6, VCPU_PSPB(r9)
        std     r7, VCPU_FSCR(r9)
        mfspr   r5, SPRN_IC
-       mfspr   r6, SPRN_VTB
        mfspr   r7, SPRN_TAR
        std     r5, VCPU_IC(r9)
-       std     r6, VCPU_VTB(r9)
        std     r7, VCPU_TAR(r9)
        mfspr   r8, SPRN_EBBHR
        std     r8, VCPU_EBBHR(r9)
@@ -1564,9 +1562,11 @@ kvmhv_switch_to_host:
        isync
 
 BEGIN_FTR_SECTION
-       /* DPDES is shared between threads */
+       /* DPDES and VTB are shared between threads */
        mfspr   r7, SPRN_DPDES
+       mfspr   r8, SPRN_VTB
        std     r7, VCORE_DPDES(r5)
+       std     r8, VCORE_VTB(r5)
        /* clear DPDES so we don't get guest doorbells in the host */
        li      r8, 0
        mtspr   SPRN_DPDES, r8
index e76f79a45988815cfebb879ddfe29cee1a6311a8..69ebd70160f2611dc3c90fa751930bb30667bc47 100644 (file)
@@ -226,7 +226,7 @@ void kvmppc_copy_from_svcpu(struct kvm_vcpu *vcpu,
         */
        vcpu->arch.purr += get_tb() - vcpu->arch.entry_tb;
        vcpu->arch.spurr += get_tb() - vcpu->arch.entry_tb;
-       vcpu->arch.vtb += get_vtb() - vcpu->arch.entry_vtb;
+       to_book3s(vcpu)->vtb += get_vtb() - vcpu->arch.entry_vtb;
        if (cpu_has_feature(CPU_FTR_ARCH_207S))
                vcpu->arch.ic += mfspr(SPRN_IC) - vcpu->arch.entry_ic;
        svcpu->in_use = false;
@@ -1361,6 +1361,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_VTB:
+               *val = get_reg_val(id, to_book3s(vcpu)->vtb);
+               break;
        case KVM_REG_PPC_LPCR:
        case KVM_REG_PPC_LPCR_64:
                /*
@@ -1397,6 +1400,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_VTB:
+               to_book3s(vcpu)->vtb = set_reg_val(id, *val);
+               break;
        case KVM_REG_PPC_LPCR:
        case KVM_REG_PPC_LPCR_64:
                kvmppc_set_lpcr_pr(vcpu, set_reg_val(id, *val));