From: Mushahid Hussain <[email protected]> KVM enables the master clock when every vCPU has a matching TSC, judged by nr_vcpus_matched_tsc + 1 == online_vcpus. online_vcpus counts a vCPU once, but each of its plane vCPUs synchronizes its TSC at creation and counts as another matching vCPU. With one higher plane the count can never equal the number of vCPUs again, the master clock stays off and kvmclock loses PVCLOCK_TSC_STABLE_BIT. Among other things the Hyper-V reference TSC page then breaks: KVM writes sequence 0 to it, finds the clock unstable and leaves it that way.
The planes of a vCPU share its TSC. Give a plane vCPU the current generation and leave the matching count and generation changes to its plane 0 sibling. Assisted-by: LLM Signed-off-by: David Woodhouse <[email protected]> --- arch/x86/kvm/x86.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 0f8a149ba0eb..ba468f7c4d4a 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2858,6 +2858,31 @@ static void __kvm_synchronize_tsc(struct kvm_vcpu *vcpu, u64 offset, u64 tsc, if (vcpu->arch.guest_tsc_protected) return; + /* + * The planes of a vCPU share its TSC and online_vcpus counts the + * vCPU once, so a plane vCPU neither counts as a matching vCPU nor + * starts a generation; its plane 0 sibling speaks for it. Nor may + * it perturb the global matching window (last_tsc_ and + * user_set_tsc): KVM_SET_MSRS is accepted on plane fds, and a TSC + * write on a plane fd + * moving the window would corrupt the next plane-0 write's match + * decision. Latch the generation from the plane-0 sibling, which + * exists by construction for a plane twin, rather than from the + * VM-global cur_tsc_* that may belong to a different vCPU's + * generation entirely. + */ + if (vcpu->plane_level) { + struct kvm_vcpu *sibling = vcpu->common->vcpus[0]; + + vcpu->arch.last_guest_tsc = tsc; + kvm_vcpu_write_tsc_offset(vcpu, offset); + + vcpu->arch.this_tsc_generation = sibling->arch.this_tsc_generation; + vcpu->arch.this_tsc_nsec = sibling->arch.this_tsc_nsec; + vcpu->arch.this_tsc_write = sibling->arch.this_tsc_write; + return; + } + if (user_set_tsc) vcpu->kvm->arch.user_set_tsc = true; -- 2.50.1

