x86/time: correctly honor late clearing of TSC related feature flags As such clearing of flags may have an impact on the selected rendezvous function, defer the establishing of a rendezvous function other than the initial default one (std) until after all APs have been brought up. But don't allow such feature flags to be cleared during CPU hotplug: Platform and local system times may have diverged significantly by then, potentially causing noticeably (even if only temporary) strange behavior. As we're anyway expecting only sufficiently similar CPUs to appear during hotplug, this shouldn't be introducing new limitations. Reported-by: Joao Martins Signed-off-by: Jan Beulich --- v3: Drop original approach entirely - defer everything to verify_tsc_reliability(), making for quite a bit smaller a patch. Note: Considering that tsc_check_writability() checks TSC_RELIABLE, it being run before that feature flag has obtained its final value seems problematic too. Should we defer that call too? --- a/xen/arch/x86/time.c +++ b/xen/arch/x86/time.c @@ -1638,9 +1638,18 @@ static int __init verify_tsc_reliability printk("Switched to Platform timer %s TSC\n", freq_string(plt_src.frequency)); + return 0; } } + /* + * While with constant-rate TSCs the scale factor can be shared, when TSCs + * are not marked as 'reliable', re-sync during rendezvous. + */ + if ( boot_cpu_has(X86_FEATURE_CONSTANT_TSC) && + !boot_cpu_has(X86_FEATURE_TSC_RELIABLE) ) + time_calibration_rendezvous_fn = time_calibration_tsc_rendezvous; + return 0; } __initcall(verify_tsc_reliability); @@ -1650,14 +1659,6 @@ int __init init_xen_time(void) { tsc_check_writability(); - /* If we have constant-rate TSCs then scale factor can be shared. */ - if ( boot_cpu_has(X86_FEATURE_CONSTANT_TSC) ) - { - /* If TSCs are not marked as 'reliable', re-sync during rendezvous. */ - if ( !boot_cpu_has(X86_FEATURE_TSC_RELIABLE) ) - time_calibration_rendezvous_fn = time_calibration_tsc_rendezvous; - } - open_softirq(TIME_CALIBRATE_SOFTIRQ, local_time_calibration); /* NB. get_cmos_time() can take over one second to execute. */