diff options
| author | Colin Percival <cperciva@FreeBSD.org> | 2022-01-09 00:59:31 +0000 |
|---|---|---|
| committer | Colin Percival <cperciva@FreeBSD.org> | 2022-01-15 01:30:17 +0000 |
| commit | de1292c6ff8a445fd453effba8cc23c38cea223f (patch) | |
| tree | f8221a193cf2cbaf2f6a80e2a46c0bcc0505ba1b /sys | |
| parent | 4a432614f68cf35879dbb4ebef089f5b8db95334 (diff) | |
Diffstat (limited to 'sys')
| -rw-r--r-- | sys/x86/x86/local_apic.c | 33 |
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); |
