The branch main has been updated by markj:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=62d09b46ad7508ae74d462e49234f0a80f91ff69

commit 62d09b46ad7508ae74d462e49234f0a80f91ff69
Author:     Mark Johnston <[email protected]>
AuthorDate: 2021-12-06 15:42:10 +0000
Commit:     Mark Johnston <[email protected]>
CommitDate: 2021-12-06 15:42:10 +0000

    x86: Defer LAPIC calibration until after timecounters are available
    
    This ensures that we have a good reference timecounter for performing
    calibration.
    
    Change lapic_setup to avoid configuring the timer when booting, and move
    calibration and initial configuration to a new lapic routine,
    lapic_calibrate_timer.  This calibration will be initiated from
    cpu_initclocks(), before an eventtimer is selected.
    
    Reviewed by:    kib, jhb
    MFC after:      2 weeks
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D33206
---
 sys/x86/include/apicvar.h | 10 +++++++++
 sys/x86/include/clock.h   |  1 +
 sys/x86/isa/clock.c       |  4 ++++
 sys/x86/x86/local_apic.c  | 57 ++++++++++++++++++++++++-----------------------
 sys/x86/xen/xen_apic.c    |  7 ++++++
 5 files changed, 51 insertions(+), 28 deletions(-)

diff --git a/sys/x86/include/apicvar.h b/sys/x86/include/apicvar.h
index f1794afa0bbd..373e7d576426 100644
--- a/sys/x86/include/apicvar.h
+++ b/sys/x86/include/apicvar.h
@@ -229,6 +229,9 @@ struct apic_ops {
        void    (*disable_vector)(u_int, u_int);
        void    (*free_vector)(u_int, u_int, u_int);
 
+       /* Timer */
+       void    (*calibrate_timer)(void);
+
        /* PMC */
        int     (*enable_pmc)(void);
        void    (*disable_pmc)(void);
@@ -376,6 +379,13 @@ apic_free_vector(u_int apic_id, u_int vector, u_int irq)
        apic_ops.free_vector(apic_id, vector, irq);
 }
 
+static inline void
+lapic_calibrate_timer(void)
+{
+
+       apic_ops.calibrate_timer();
+}
+
 static inline int
 lapic_enable_pmc(void)
 {
diff --git a/sys/x86/include/clock.h b/sys/x86/include/clock.h
index 86a4541568ed..d492196bac85 100644
--- a/sys/x86/include/clock.h
+++ b/sys/x86/include/clock.h
@@ -27,6 +27,7 @@ extern int    smp_tsc;
 void   i8254_init(void);
 void   i8254_delay(int);
 void   clock_init(void);
+void   lapic_calibrate(void);
 
 /*
  * Driver to clock driver interface.
diff --git a/sys/x86/isa/clock.c b/sys/x86/isa/clock.c
index 568097d18fdf..2eb1c343f4db 100644
--- a/sys/x86/isa/clock.c
+++ b/sys/x86/isa/clock.c
@@ -66,6 +66,7 @@ __FBSDID("$FreeBSD$");
 #include <machine/intr_machdep.h>
 #include <machine/ppireg.h>
 #include <machine/timerreg.h>
+#include <x86/apicvar.h>
 #include <x86/init.h>
 
 #include <isa/rtc.h>
@@ -411,6 +412,8 @@ cpu_initclocks(void)
        int i;
 
        td = curthread;
+
+       lapic_calibrate_timer();
        cpu_initclocks_bsp();
        CPU_FOREACH(i) {
                if (i == 0)
@@ -425,6 +428,7 @@ cpu_initclocks(void)
                sched_unbind(td);
        thread_unlock(td);
 #else
+       lapic_calibrate_timer();
        cpu_initclocks_bsp();
 #endif
 }
diff --git a/sys/x86/x86/local_apic.c b/sys/x86/x86/local_apic.c
index 778760be1921..7e8db869a884 100644
--- a/sys/x86/x86/local_apic.c
+++ b/sys/x86/x86/local_apic.c
@@ -221,7 +221,6 @@ SYSCTL_INT(_hw_apic, OID_AUTO, ds_idle_timeout, 
CTLFLAG_RWTUN,
 #endif
 
 static void lapic_calibrate_initcount(struct lapic *la);
-static void lapic_calibrate_deadline(struct lapic *la);
 
 /*
  * Use __nosanitizethread to exempt the LAPIC I/O accessors from KCSan
@@ -373,6 +372,7 @@ static void         native_apic_enable_vector(u_int 
apic_id, u_int vector);
 static void    native_apic_free_vector(u_int apic_id, u_int vector, u_int irq);
 static void    native_lapic_set_logical_id(u_int apic_id, u_int cluster,
                    u_int cluster_id);
+static void    native_lapic_calibrate_timer(void);
 static int     native_lapic_enable_pmc(void);
 static void    native_lapic_disable_pmc(void);
 static void    native_lapic_reenable_pmc(void);
@@ -412,6 +412,7 @@ struct apic_ops apic_ops = {
        .enable_vector          = native_apic_enable_vector,
        .disable_vector         = native_apic_disable_vector,
        .free_vector            = native_apic_free_vector,
+       .calibrate_timer        = native_lapic_calibrate_timer,
        .enable_pmc             = native_lapic_enable_pmc,
        .disable_pmc            = native_lapic_disable_pmc,
        .reenable_pmc           = native_lapic_reenable_pmc,
@@ -804,21 +805,18 @@ native_lapic_setup(int boot)
                    LAPIC_LVT_PCINT));
        }
 
-       /* Program timer LVT. */
+       /*
+        * Program the timer LVT.  Calibration is deferred until it is certain
+        * that we have a reliable timecounter.
+        */
        la->lvt_timer_base = lvt_mode(la, APIC_LVT_TIMER,
            lapic_read32(LAPIC_LVT_TIMER));
        la->lvt_timer_last = la->lvt_timer_base;
        lapic_write32(LAPIC_LVT_TIMER, la->lvt_timer_base);
 
-       /* Calibrate the timer parameters using BSP. */
-       if (boot && IS_BSP()) {
-               lapic_calibrate_initcount(la);
-               if (lapic_timer_tsc_deadline)
-                       lapic_calibrate_deadline(la);
-       }
-
-       /* Setup the timer if configured. */
-       if (la->la_timer_mode != LAT_MODE_UNDEF) {
+       if (boot)
+               la->la_timer_mode = LAT_MODE_UNDEF;
+       else if (la->la_timer_mode != LAT_MODE_UNDEF) {
                KASSERT(la->la_timer_period != 0, ("lapic%u: zero divisor",
                    lapic_id()));
                switch (la->la_timer_mode) {
@@ -909,6 +907,25 @@ lapic_update_pmc(void *dummy)
 }
 #endif
 
+static void
+native_lapic_calibrate_timer(void)
+{
+       struct lapic *la;
+       register_t intr;
+
+       intr = intr_disable();
+       la = &lapics[lapic_id()];
+
+       lapic_calibrate_initcount(la);
+
+       intr_restore(intr);
+
+       if (lapic_timer_tsc_deadline && bootverbose) {
+               printf("lapic: deadline tsc mode, Frequency %ju Hz\n",
+                   (uintmax_t)tsc_freq);
+       }
+}
+
 static int
 native_lapic_enable_pmc(void)
 {
@@ -999,27 +1016,11 @@ lapic_calibrate_initcount(struct lapic *la)
        count_freq = value;
 }
 
-static void
-lapic_calibrate_deadline(struct lapic *la __unused)
-{
-
-       if (bootverbose) {
-               printf("lapic: deadline tsc mode, Frequency %ju Hz\n",
-                   (uintmax_t)tsc_freq);
-       }
-}
-
 static void
 lapic_change_mode(struct eventtimer *et, struct lapic *la,
     enum lat_timer_mode newmode)
 {
-
-       /*
-        * The TSC frequency may change during late calibration against other
-        * timecounters (HPET or ACPI PMTimer).
-        */
-       if (la->la_timer_mode == newmode &&
-           (newmode != LAT_MODE_DEADLINE || et->et_frequency == tsc_freq))
+       if (la->la_timer_mode == newmode)
                return;
        switch (newmode) {
        case LAT_MODE_PERIODIC:
diff --git a/sys/x86/xen/xen_apic.c b/sys/x86/xen/xen_apic.c
index 01dae36de2e8..b553e5248716 100644
--- a/sys/x86/xen/xen_apic.c
+++ b/sys/x86/xen/xen_apic.c
@@ -223,6 +223,12 @@ xen_pv_apic_free_vector(u_int apic_id, u_int vector, u_int 
irq)
        XEN_APIC_UNSUPPORTED;
 }
 
+static void
+xen_pv_lapic_calibrate_timer(void)
+{
+
+}
+
 static void
 xen_pv_lapic_set_logical_id(u_int apic_id, u_int cluster, u_int cluster_id)
 {
@@ -420,6 +426,7 @@ struct apic_ops xen_apic_ops = {
        .enable_vector          = xen_pv_apic_enable_vector,
        .disable_vector         = xen_pv_apic_disable_vector,
        .free_vector            = xen_pv_apic_free_vector,
+       .calibrate_timer        = xen_pv_lapic_calibrate_timer,
        .enable_pmc             = xen_pv_lapic_enable_pmc,
        .disable_pmc            = xen_pv_lapic_disable_pmc,
        .reenable_pmc           = xen_pv_lapic_reenable_pmc,

Reply via email to