From nobody Wed Aug 26 00:41:04 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass(p=none dis=none) header.from=infradead.org ARC-Seal: i=1; a=rsa-sha256; t=1783113761; cv=none; d=zohomail.com; s=zohoarc; b=B+GX72itEQ6K9kb4WYTMSdIIXtZf+2xwdr1yjctOJmW7T/msxTQ8F5Ei3LPvLOstwDWWO2eKe3qsk+p65UlTVUDrpPzZKOdWRRzPUzGq2AnVTLNQkZNXlWpSU7GX0Y19j+iKHR2yWZ/F9R8ysEQSvP7+0IPu+0B2ksWWk7t25iQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783113761; h=Content-Transfer-Encoding:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To:Cc; bh=EXbsKVccUqJVUsNQz6ddm7iFrU6RHTQ7Y+Y2aEq7ws8=; b=k2zJ7OwLx57slYy6VVgjiOIjps0V6oYrJ2XtHifojQnZ2POeefxsgHLiK5mU7cXb+fJmyqrxhEeWzA2Ji1oGAbWAdYkoB8hKkNvv9TJJtBzX0LxdQv3q8XsINpo1keEeQ9hihCOycJp2j/TVjsgqEDVgbHvmQJSXmRpRHF37f5Q= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass header.from= (p=none dis=none) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1783113761385483.1049666266482; Fri, 3 Jul 2026 14:22:41 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1353753.1609467 (Exim 4.92) (envelope-from ) id 1wflKo-0005Z7-26; Fri, 03 Jul 2026 21:22:06 +0000 Received: by outflank-mailman (output) from mailman id 1353753.1609467; Fri, 03 Jul 2026 21:22:06 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflKn-0005Xe-TV; Fri, 03 Jul 2026 21:22:05 +0000 Received: by outflank-mailman (input) for mailman id 1353753; Fri, 03 Jul 2026 21:22:04 +0000 Received: from mx.expurgate.net ([194.145.224.10]) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1wflKm-00051o-8x for xen-devel@lists.xenproject.org; Fri, 03 Jul 2026 21:22:04 +0000 Received: from mx.expurgate.net (helo=localhost) by mx.expurgate.net with esmtp id 1wflKl-00CeeP-Lo; Fri, 03 Jul 2026 23:22:03 +0200 Received: from [10.42.69.10] (helo=localhost) by localhost with ESMTP (eXpurgate MTA 0.9.1) (envelope-from ) id 6a4827de-bab6-0a2a0a5309dd-0a2a450adcec-14 for ; Fri, 03 Jul 2026 23:22:02 +0200 Received: from [90.155.50.34] (helo=casper.infradead.org) by tlsNG-4011c0.mxtls.expurgate.net with ESMTPS (eXpurgate 4.57.1) (envelope-from ) id 6a4827fa-e40e-0a2a450a0019-5a9b3222c012-3 for ; Fri, 03 Jul 2026 23:22:02 +0200 Received: from [2001:8b0:10b:1::425] (helo=i7.infradead.org) by casper.infradead.org with esmtpsa (Exim 4.99.1 #2 (Red Hat Linux)) id 1wflKX-0000000AsYB-09Vp; Fri, 03 Jul 2026 21:21:49 +0000 Received: from dwoodhou by i7.infradead.org with local (Exim 4.99.2 #2 (Red Hat Linux)) id 1wflKW-00000001RP9-3lTW; Fri, 03 Jul 2026 22:21:48 +0100 X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Authentication-Results: eu.smtp.expurgate.cloud; dkim=pass header.s=casper.20170209 header.d=infradead.org header.i="@infradead.org" header.h="Sender:Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:To:From" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=Sender:Content-Transfer-Encoding: MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:To:From:Reply-To: Cc:Content-Type:Content-ID:Content-Description; bh=EXbsKVccUqJVUsNQz6ddm7iFrU6RHTQ7Y+Y2aEq7ws8=; b=bmWLHuUVFitSUFZOTx9OuvAnfd xPH4uTWi9QwLkGQZiHcolsh2xvG2w+yaFIm6i3YV1ye8RBp7cKq+mwvTGGF+JhdBEMUE5bBTAdMKk 0IYlkrAN/MRrqOBcpHFfI+dzK6kbqckneRzOhdzUIj7qH+AWGPVy7JUQLJYgjbTPxlhB4eB5SwXmA uI1j/2xzbfvh6RW09eoS99Y3PPw//1OiHHNoYebGJIdwL13NuGPRTZD4QY77tAFfJcdzkJgJ6DjLo 8KHrwUNDMmWRZUUINWybBd1Ov9lHW3YVD/FKf6ETSPYBgbG7dkcdaqqxnn57QUV+cq3wubXh174y0 gUWoax4g==; From: David Woodhouse To: Paolo Bonzini , Jonathan Corbet , Shuah Khan , Sean Christopherson , Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , x86@kernel.org, "H. Peter Anvin" , Vitaly Kuznetsov , Juergen Gross , Boris Ostrovsky , David Woodhouse , Paul Durrant , Jonathan Cameron , Sascha Bischoff , Marc Zyngier , Joey Gouly , Jack Allister , Dongli Zhang , joe.jin@oracle.com, kvm@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, xen-devel@lists.xenproject.org, linux-kselftest@vger.kernel.org Subject: [PATCH v6 20/36] KVM: x86: Kill last_tsc_{nsec,write,offset} fields Date: Fri, 3 Jul 2026 22:17:59 +0100 Message-ID: <20260703212145.343527-21-dwmw2@infradead.org> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260703212145.343527-1-dwmw2@infradead.org> References: <20260703212145.343527-1-dwmw2@infradead.org> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: David Woodhouse X-SRS-Rewrite: SMTP reverse-path rewritten from by casper.infradead.org. See http://www.infradead.org/rpr.html X-purgate-ID: tlsNG-4011c0/1783113722-CED3BDDE-051B5C97/0/0 X-purgate-type: clean X-purgate-size: 6394 X-ZohoMail-DKIM: pass (identity @infradead.org) X-ZM-MESSAGEID: 1783113763016158500 Content-Type: text/plain; charset="utf-8" From: David Woodhouse These pointlessly duplicate the cur_tsc_{nsec,write,offset} values. The only place they were used was where the TSC is stable and a new vCPU is being synchronized to the previous setting, in which case the cur_tsc_* value is definitely identical. Rename last_tsc_khz and last_tsc_scaling_ratio to cur_tsc_khz and cur_tsc_scaling_ratio respectively, since they are properties of the current TSC generation. Since cur_tsc_offset now serves as the single source of truth for the TSC generation's offset, the backwards-TSC adjustment (used during S4 resume when the host TSC resets) must also update cur_tsc_offset by the same delta applied to all vCPUs. Without this, subsequent vCPUs that synchronize after the adjustment would get the stale pre-S4 offset. Signed-off-by: David Woodhouse Reviewed-by: Paul Durrant --- arch/x86/include/asm/kvm_host.h | 7 ++--- arch/x86/kvm/x86.c | 45 +++++++++++++++++---------------- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_hos= t.h index 87435ddecde1..e752b13c0809 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -1486,11 +1486,8 @@ struct kvm_arch { * preemption-disabled region, so it must be a raw spinlock. */ raw_spinlock_t tsc_write_lock; - u64 last_tsc_nsec; - u64 last_tsc_write; - u32 last_tsc_khz; - u64 last_tsc_offset; - u64 last_tsc_scaling_ratio; + u32 cur_tsc_khz; + u64 cur_tsc_scaling_ratio; u64 cur_tsc_nsec; u64 cur_tsc_write; u64 cur_tsc_offset; diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index ffe5f98a5688..478147aff56a 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2813,14 +2813,12 @@ static void __kvm_synchronize_tsc(struct kvm_vcpu *= vcpu, u64 offset, u64 tsc, vcpu->kvm->arch.user_set_tsc =3D true; =20 /* - * We also track th most recent recorded KHZ, write and time to - * allow the matching interval to be extended at each write. + * Track the TSC frequency, scaling ratio, and offset for the current + * generation. These are used to detect matching TSC writes and to + * compute the guest TSC from the host clock. */ - kvm->arch.last_tsc_nsec =3D ns; - kvm->arch.last_tsc_write =3D tsc; - kvm->arch.last_tsc_khz =3D vcpu->arch.virtual_tsc_khz; - kvm->arch.last_tsc_offset =3D offset; - kvm->arch.last_tsc_scaling_ratio =3D vcpu->arch.l1_tsc_scaling_ratio; + kvm->arch.cur_tsc_khz =3D vcpu->arch.virtual_tsc_khz; + kvm->arch.cur_tsc_scaling_ratio =3D vcpu->arch.l1_tsc_scaling_ratio; =20 vcpu->arch.last_guest_tsc =3D tsc; =20 @@ -2833,8 +2831,6 @@ static void __kvm_synchronize_tsc(struct kvm_vcpu *vc= pu, u64 offset, u64 tsc, * nanosecond time, offset, and write, so if TSCs are in * sync, we can match exact offset, and if not, we can match * exact software computation in compute_guest_tsc() - * - * These values are tracked in kvm->arch.cur_xxx variables. */ kvm->arch.cur_tsc_generation++; kvm->arch.cur_tsc_nsec =3D ns; @@ -2874,7 +2870,7 @@ static void kvm_synchronize_tsc(struct kvm_vcpu *vcpu= , u64 *user_value) } =20 offset =3D kvm_compute_l1_tsc_offset(vcpu, host_tsc, data); - elapsed =3D ns - kvm->arch.last_tsc_nsec; + elapsed =3D ns - kvm->arch.cur_tsc_nsec; =20 if (vcpu->arch.virtual_tsc_khz) { if (data =3D=3D 0) { @@ -2884,7 +2880,7 @@ static void kvm_synchronize_tsc(struct kvm_vcpu *vcpu= , u64 *user_value) */ synchronizing =3D true; } else if (kvm->arch.user_set_tsc) { - u64 tsc_exp =3D kvm->arch.last_tsc_write + + u64 tsc_exp =3D kvm->arch.cur_tsc_write + nsec_to_cycles(vcpu, elapsed); u64 tsc_hz =3D vcpu->arch.virtual_tsc_khz * 1000LL; /* @@ -2915,7 +2911,7 @@ static void kvm_synchronize_tsc(struct kvm_vcpu *vcpu= , u64 *user_value) * it's better to try to match offsets from the beginning. */ if (synchronizing && - vcpu->arch.virtual_tsc_khz =3D=3D kvm->arch.last_tsc_khz) { + vcpu->arch.virtual_tsc_khz =3D=3D kvm->arch.cur_tsc_khz) { /* * If synchronizing, advance the reference point to "now" * so the matching window slides forward with each vCPU. @@ -3199,7 +3195,7 @@ static void pvclock_update_vm_gtod_copy(struct kvm *k= vm) * get_kvmclock() to compute kvmclock from the host TSC * without needing a vCPU reference. */ - ka->master_tsc_scaling_ratio =3D ka->last_tsc_scaling_ratio; + ka->master_tsc_scaling_ratio =3D ka->cur_tsc_scaling_ratio; tsc_hz =3D (u64)get_cpu_tsc_khz() * 1000; if (tsc_hz && kvm_caps.has_tsc_control) tsc_hz =3D kvm_scale_tsc(tsc_hz, @@ -6068,8 +6064,8 @@ static int kvm_arch_tsc_set_attr(struct kvm_vcpu *vcp= u, raw_spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags); =20 matched =3D (vcpu->arch.virtual_tsc_khz && - kvm->arch.last_tsc_khz =3D=3D vcpu->arch.virtual_tsc_khz && - kvm->arch.last_tsc_offset =3D=3D offset); + kvm->arch.cur_tsc_khz =3D=3D vcpu->arch.virtual_tsc_khz && + kvm->arch.cur_tsc_offset =3D=3D offset); =20 tsc =3D kvm_scale_tsc(rdtsc(), vcpu->arch.l1_tsc_scaling_ratio) + offset; ns =3D get_kvmclock_base_ns(); @@ -13451,7 +13447,7 @@ int kvm_arch_enable_virtualization_cpu(void) { struct kvm *kvm; struct kvm_vcpu *vcpu; - unsigned long i; + unsigned long i, flags; int ret; u64 local_tsc; u64 max_tsc =3D 0; @@ -13530,13 +13526,18 @@ int kvm_arch_enable_virtualization_cpu(void) } =20 /* - * We have to disable TSC offset matching.. if you were - * booting a VM while issuing an S4 host suspend.... - * you may have some problem. Solving this issue is - * left as an exercise to the reader. + * Adjust the TSC matching reference by the same + * delta applied to each vCPU's offset, so that + * future KVM_SET_TSC / vCPU creation still matches + * correctly against the adjusted TSC timeline. + * Scale from host to guest TSC rate. */ - kvm->arch.last_tsc_nsec =3D 0; - kvm->arch.last_tsc_write =3D 0; + raw_spin_lock_irqsave(&kvm->arch.tsc_write_lock, flags); + kvm->arch.cur_tsc_write -=3D + kvm_scale_tsc(delta_cyc, + kvm->arch.cur_tsc_scaling_ratio); + kvm->arch.cur_tsc_offset +=3D delta_cyc; + raw_spin_unlock_irqrestore(&kvm->arch.tsc_write_lock, flags); } =20 } --=20 2.54.0