aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Percival <cperciva@FreeBSD.org>2022-01-09 00:59:31 +0000
committerColin Percival <cperciva@FreeBSD.org>2022-02-11 06:52:00 +0000
commita605a66017ec53e42c06b35a1786edf1b33cd8ab (patch)
tree3be3be8c3397beec049a6a72057a8c85f8b7e9d0
parent51e77b34e4bf76c8aa2c882f64ef923c2fbe6108 (diff)
downloadsrc-a605a66017ec53e42c06b35a1786edf1b33cd8ab.tar.gz
src-a605a66017ec53e42c06b35a1786edf1b33cd8ab.zip
Use CPUID leaf 0x40000010 for local APIC freq
Some VM systems announce the frequency of the local APIC via the CPUID leaf 0x40000010. Using this allows us to boot slightly faster by avoiding the need for timer calibration. Reviewed by: markj Sponsored by: https://www.patreon.com/cperciva (cherry picked from commit de1292c6ff8a445fd453effba8cc23c38cea223f)
-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 c5f72a7ff43c..59b5cb600725 100644
--- a/sys/x86/x86/local_apic.c
+++ b/sys/x86/x86/local_apic.c
@@ -991,6 +991,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)
{
@@ -1003,6 +1032,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);
@@ -1020,6 +1052,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);