Index: sys/x86/include/apicvar.h =================================================================== --- sys/x86/include/apicvar.h +++ sys/x86/include/apicvar.h @@ -229,6 +229,9 @@ 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_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) { Index: sys/x86/include/clock.h =================================================================== --- sys/x86/include/clock.h +++ sys/x86/include/clock.h @@ -27,6 +27,7 @@ void i8254_init(void); void i8254_delay(int); void clock_init(void); +void lapic_calibrate(void); /* * Driver to clock driver interface. Index: sys/x86/isa/clock.c =================================================================== --- sys/x86/isa/clock.c +++ sys/x86/isa/clock.c @@ -66,6 +66,7 @@ #include #include #include +#include #include #include @@ -411,6 +412,8 @@ int i; td = curthread; + + lapic_calibrate_timer(); cpu_initclocks_bsp(); CPU_FOREACH(i) { if (i == 0) @@ -425,6 +428,7 @@ sched_unbind(td); thread_unlock(td); #else + lapic_calibrate_timer(); cpu_initclocks_bsp(); #endif } Index: sys/x86/x86/local_apic.c =================================================================== --- sys/x86/x86/local_apic.c +++ sys/x86/x86/local_apic.c @@ -221,7 +221,7 @@ #endif static void lapic_calibrate_initcount(struct lapic *la); -static void lapic_calibrate_deadline(struct lapic *la); +static void lapic_setup_timer(struct lapic *la); /* * Use __nosanitizethread to exempt the LAPIC I/O accessors from KCSan @@ -354,7 +354,6 @@ struct pic lapic_pic = { .pic_resume = lapic_resume }; -/* Forward declarations for apic_ops */ static void native_lapic_create(u_int apic_id, int boot_cpu); static void native_lapic_init(vm_paddr_t addr); static void native_lapic_xapic_mode(void); @@ -373,6 +372,7 @@ 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 @@ .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, @@ -803,40 +804,19 @@ 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) { - KASSERT(la->la_timer_period != 0, ("lapic%u: zero divisor", - lapic_id())); - switch (la->la_timer_mode) { - case LAT_MODE_PERIODIC: - lapic_timer_set_divisor(lapic_timer_divisor); - lapic_timer_periodic(la); - break; - case LAT_MODE_ONESHOT: - lapic_timer_set_divisor(lapic_timer_divisor); - lapic_timer_oneshot(la); - break; - case LAT_MODE_DEADLINE: - lapic_timer_deadline(la); - break; - default: - panic("corrupted la_timer_mode %p %d", la, - la->la_timer_mode); - } - } + if (boot) + la->la_timer_mode = LAT_MODE_UNDEF; + else + lapic_setup_timer(la); /* Program error LVT and clear any existing errors. */ lapic_write32(LAPIC_LVT_ERROR, lvt_mode(la, APIC_LVT_ERROR, @@ -908,6 +888,21 @@ } #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); + lapic_setup_timer(la); + + intr_restore(intr); +} + static int native_lapic_enable_pmc(void) { @@ -999,12 +994,27 @@ } static void -lapic_calibrate_deadline(struct lapic *la __unused) +lapic_setup_timer(struct lapic *la) { + if (la->la_timer_mode == LAT_MODE_UNDEF) + return; - if (bootverbose) { - printf("lapic: deadline tsc mode, Frequency %ju Hz\n", - (uintmax_t)tsc_freq); + KASSERT(la->la_timer_period != 0, ("lapic%u: zero divisor", + lapic_id())); + switch (la->la_timer_mode) { + case LAT_MODE_PERIODIC: + lapic_timer_set_divisor(lapic_timer_divisor); + lapic_timer_periodic(la); + break; + case LAT_MODE_ONESHOT: + lapic_timer_set_divisor(lapic_timer_divisor); + lapic_timer_oneshot(la); + break; + case LAT_MODE_DEADLINE: + lapic_timer_deadline(la); + break; + default: + panic("corrupted la_timer_mode %p %d", la, la->la_timer_mode); } } @@ -1012,13 +1022,7 @@ 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: Index: sys/x86/xen/xen_apic.c =================================================================== --- sys/x86/xen/xen_apic.c +++ sys/x86/xen/xen_apic.c @@ -223,6 +223,12 @@ 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 @@ .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,