[PATCH] x86/acrn: Set the LAPIC timer period from CPUID leaf 0x40000010 EBX

From: Yuri Zaporozhets

Date: Fri Sep 11 2026 - 06:59:08 EST


ACRN guests without a TSC-deadline timer currently always need the PIT:
apic_needs_pit() returns true because lapic_timer_period is never set,
even though the hypervisor knows the LAPIC bus frequency and could
provide it, in the same way it already provides the TSC frequency.

The ACRN timing information leaf 0x40000010 only defines EAX (TSC
frequency in kHz); EBX, ECX and EDX are reserved and return zero.
Define EBX as the LAPIC bus frequency in kHz and use it to preset
lapic_timer_period, so that the kernel skips both the PIT and the LAPIC
timer calibration. This mirrors what Hyper-V (HV_X64_MSR_APIC_FREQUENCY)
and VMware (VMWARE_CMD_GETHZ) already do, and matches the register layout
VMware defines for its own timing information leaf, which also lives at
0x40000010.

Hypervisors which do not implement this return zero in EBX, in which
case the current behaviour is kept.

Signed-off-by: Yuri Zaporozhets <yuriz@xxxxxxxxxxxxxxx>
---
arch/x86/include/asm/acrn.h | 10 ++++++++--
arch/x86/kernel/cpu/acrn.c | 15 +++++++++++++++
2 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/arch/x86/include/asm/acrn.h b/arch/x86/include/asm/acrn.h
index fab11192c60a..5db1b6e17f7c 100644
--- a/arch/x86/include/asm/acrn.h
+++ b/arch/x86/include/asm/acrn.h
@@ -12,10 +12,11 @@

/*
* Timing Information.
- * This leaf returns the current TSC frequency in kHz.
+ * This leaf returns the current TSC and LAPIC bus frequencies in kHz.
*
* EAX: (Virtual) TSC frequency in kHz.
- * EBX, ECX, EDX: RESERVED (reserved fields are set to zero).
+ * EBX: LAPIC bus frequency in kHz (0 if not provided by hypervisor).
+ * ECX, EDX: RESERVED (reserved fields are set to zero).
*/
#define ACRN_CPUID_TIMING_INFO 0x40000010

@@ -35,6 +36,11 @@ static inline unsigned long acrn_get_tsc_khz(void)
return cpuid_eax(ACRN_CPUID_TIMING_INFO);
}

+static inline unsigned long acrn_get_lapic_khz(void)
+{
+ return cpuid_ebx(ACRN_CPUID_TIMING_INFO);
+}
+
/*
* Hypercalls for ACRN
*
diff --git a/arch/x86/kernel/cpu/acrn.c b/arch/x86/kernel/cpu/acrn.c
index 2c5b51aad91a..23b6d895cccd 100644
--- a/arch/x86/kernel/cpu/acrn.c
+++ b/arch/x86/kernel/cpu/acrn.c
@@ -31,6 +31,21 @@ static void __init acrn_init_platform(void)

x86_platform.calibrate_tsc = acrn_get_tsc_khz;
x86_platform.calibrate_cpu = acrn_get_tsc_khz;
+
+ /*
+ * Set the LAPIC bus frequency if provided by the hypervisor (EBX of
+ * leaf 0x40000010). Hypervisors which do not implement this return 0,
+ * which has no effect. When set, apic_needs_pit() returns false and
+ * the kernel skips PIT initialization entirely.
+ */
+ if (boot_cpu_has(X86_FEATURE_APIC)) {
+ unsigned long lapic_khz = acrn_get_lapic_khz();
+
+ if (lapic_khz) {
+ lapic_timer_period = lapic_khz * (1000 / HZ);
+ pr_info("ACRN: LAPIC bus frequency: %lu kHz\n", lapic_khz);
+ }
+ }
}

static bool acrn_x2apic_available(void)

base-commit: 028ef9c96e96197026887c0f092424679298aae8
--
2.55.0