summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Woodhouse <dwmw@amazon.co.uk>2026-08-26 14:32:57 -0700
committerSean Christopherson <seanjc@google.com>2026-09-11 11:46:19 -0700
commit2918af628d0dae8476f89abeb76fe9fe3fd029cb (patch)
tree206f55116a7b077a021a3d87934331f9bf61a8dd
parent92fac63cc73920175f712cec792f9ab698923ffb (diff)
downloadlinux-next-2918af628d0dae8476f89abeb76fe9fe3fd029cb.tar.gz
linux-next-2918af628d0dae8476f89abeb76fe9fe3fd029cb.zip
KVM: x86: Simplify and comment kvm_get_time_scale()
The kvm_get_time_scale() function was entirely opaque. Add comments explaining what it does: compute a fixed-point multiplier and shift for converting TSC ticks to nanoseconds via pvclock_scale_delta(). Rename the local variables from the cryptic tps64/tps32/scaled64 to base_hz_u64/base32/scaled_hz_u64 to make the code self-documenting. The "tps32" name stood for "Ticks Per Second" but was misleading since it held the shifted base frequency, not a tick count. No functional change. Signed-off-by: David Woodhouse <dwmw@amazon.co.uk> Reviewed-by: Paul Durrant <paul@xen.org> Link: https://patch.msgid.link/20260826213303.914988-18-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
-rw-r--r--arch/x86/kvm/x86.c55
1 files changed, 40 insertions, 15 deletions
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 4180e18e0cbb..fb585470746e 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -940,32 +940,57 @@ static uint32_t div_frac(uint32_t dividend, uint32_t divisor)
return dividend;
}
-static void kvm_get_time_scale(uint64_t scaled_hz, uint64_t base_hz,
+static void kvm_get_time_scale(u64 scaled_hz, u64 base_hz,
s8 *pshift, u32 *pmultiplier)
{
- uint64_t scaled64;
- int32_t shift = 0;
- uint64_t tps64;
- uint32_t tps32;
+ u64 scaled_hz_u64 = scaled_hz;
+ s32 shift = 0;
+ u64 base_hz_u64;
+ u32 base32;
- tps64 = base_hz;
- scaled64 = scaled_hz;
- while (tps64 > scaled64*2 || tps64 & 0xffffffff00000000ULL) {
- tps64 >>= 1;
+ /*
+ * This function calculates a fixed-point multiplier and shift such
+ * that:
+ * time_ns = (tsc_cycles << shift) * multiplier >> 32
+ *
+ * Where tsc_cycles tick at base_hz, and time_ns should count at
+ * scaled_hz (typically NSEC_PER_SEC for a TSC→nanoseconds conversion).
+ *
+ * The multiplier is: (scaled_hz << 32) / base_hz, adjusted by shift
+ * to keep everything in range.
+ */
+
+ base_hz_u64 = base_hz;
+
+ /*
+ * Start by shifting base_hz right until it fits in 32 bits, and
+ * is lower than double the target rate. This introduces a negative
+ * shift value which would result in pvclock_scale_delta() shifting
+ * the actual tick count right before performing the multiplication.
+ */
+ while (base_hz_u64 > scaled_hz_u64 * 2 || base_hz_u64 >> 32) {
+ base_hz_u64 >>= 1;
shift--;
}
- tps32 = (uint32_t)tps64;
- while (tps32 <= scaled64 || scaled64 & 0xffffffff00000000ULL) {
- if (scaled64 & 0xffffffff00000000ULL || tps32 & 0x80000000)
- scaled64 >>= 1;
+ /* Now the shifted base_hz fits in 32 bits. */
+ base32 = (u32)base_hz_u64;
+
+ /*
+ * Next, shift scaled_hz right until it fits in 32 bits, and ensure
+ * that the shifted base_hz is strictly larger (so that the result of the
+ * final division also fits in 32 bits).
+ */
+ while (base32 <= scaled_hz_u64 || scaled_hz_u64 >> 32) {
+ if (scaled_hz_u64 >> 32 || base32 & BIT(31))
+ scaled_hz_u64 >>= 1;
else
- tps32 <<= 1;
+ base32 <<= 1;
shift++;
}
*pshift = shift;
- *pmultiplier = div_frac(scaled64, tps32);
+ *pmultiplier = div_frac(scaled_hz_u64, base32);
}
#ifdef CONFIG_X86_64