aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/x86/x86/local_apic.c33
1 files changed, 33 insertions, 0 deletions
diff --git a/sys/x86/x86/local_apic.c b/sys/x86/x86/local_apic.c
index 4b66d10cb5ae..7be603c71146 100644
--- a/sys/x86/x86/local_apic.c
+++ b/sys/x86/x86/local_apic.c
@@ -1002,6 +1002,35 @@ native_lapic_disable_pmc(void)
#endif
}
+static int
+lapic_calibrate_initcount_cpuid_vm(void)
+{
+ u_int regs[4];
+ uint64_t freq;
+
+ /* Get value from CPUID leaf if possible. */
+ if (vm_guest == VM_GUEST_NO)
+ return (false);
+ if (hv_high < 0x40000010)
+ return (false);
+ do_cpuid(0x40000010, regs);
+ freq = (uint64_t)(regs[1]) * 1000;
+
+ /* Pick timer divisor. */
+ lapic_timer_divisor = 2;
+ do {
+ if (freq / lapic_timer_divisor < APIC_TIMER_MAX_COUNT)
+ break;
+ lapic_timer_divisor <<= 1;
+ } while (lapic_timer_divisor <= 128);
+ if (lapic_timer_divisor > 128)
+ return (false);
+
+ /* Record divided frequency. */
+ count_freq = freq / lapic_timer_divisor;
+ return (true);
+}
+
static uint64_t
cb_lapic_getcount(void)
{
@@ -1014,6 +1043,9 @@ lapic_calibrate_initcount(struct lapic *la)
{
uint64_t freq;
+ if (lapic_calibrate_initcount_cpuid_vm())
+ goto done;
+
/* Calibrate the APIC timer frequency. */
lapic_timer_set_divisor(2);
lapic_timer_oneshot_nointr(la, APIC_TIMER_MAX_COUNT);
@@ -1031,6 +1063,7 @@ lapic_calibrate_initcount(struct lapic *la)
if (lapic_timer_divisor > 128)
panic("lapic: Divisor too big");
count_freq = freq * 2 / lapic_timer_divisor;
+done:
if (bootverbose) {
printf("lapic: Divisor %lu, Frequency %lu Hz\n",
lapic_timer_divisor, count_freq);