diff -r 8951c3b84e2a xen/arch/x86/time.c --- a/xen/arch/x86/time.c Fri Aug 01 09:54:54 2008 +0100 +++ b/xen/arch/x86/time.c Sun Aug 03 10:34:11 2008 -0600 @@ -876,7 +876,8 @@ void do_settime(unsigned long secs, unsi rcu_read_unlock(&domlist_read_lock); } -static void local_time_calibration(void *unused) +static void local_time_calibration(s_time_t curr_master_stime, + s_time_t curr_local_stime, u64 curr_tsc) { struct cpu_time *t = &this_cpu(cpu_time); @@ -884,11 +885,11 @@ static void local_time_calibration(void * System timestamps, extrapolated from local and master oscillators, * taken during this calibration and the previous calibration. */ - s_time_t prev_local_stime, curr_local_stime; - s_time_t prev_master_stime, curr_master_stime; + s_time_t prev_local_stime; + s_time_t prev_master_stime; /* TSC timestamps taken during this calibration and prev calibration. */ - u64 prev_tsc, curr_tsc; + u64 prev_tsc; /* * System time and TSC ticks elapsed during the previous calibration @@ -909,14 +910,6 @@ static void local_time_calibration(void /* The overall calibration scale multiplier. */ u32 calibration_mul_frac; - if ( platform_timer_is_tsc() ) - { - make_tsctimer_record(); - update_vcpu_system_time(current); - set_timer(&t->calibration_timer, NOW() + MILLISECS(10*1000)); - return; - } - prev_tsc = t->local_tsc_stamp; prev_local_stime = t->stime_local_stamp; prev_master_stime = t->stime_master_stamp; @@ -925,12 +918,6 @@ static void local_time_calibration(void * Disable IRQs to get 'instantaneous' current timestamps. We read platform * time first, as we may be delayed when acquiring platform_timer_lock. */ - local_irq_disable(); - curr_master_stime = read_platform_stime(); - curr_local_stime = get_s_time(); - rdtscll(curr_tsc); - local_irq_enable(); - #if 0 printk("PRE%d: tsc=%"PRIu64" stime=%"PRIu64" master=%"PRIu64"\n", smp_processor_id(), prev_tsc, prev_local_stime, prev_master_stime); @@ -952,7 +939,7 @@ static void local_time_calibration(void * We could be smarter here: resync platform timer with local timer? */ if ( ((s64)stime_elapsed64 < (EPOCH / 2)) ) - goto out; + return; /* * Calculate error-correction factor. This only slows down a fast local @@ -1020,12 +1007,71 @@ static void local_time_calibration(void local_irq_enable(); update_vcpu_system_time(current); +} - out: +static cpumask_t local_time_calibrate_cpumask = CPU_MASK_NONE; +s_time_t curr_master_stime; + +static void slave_local_time_calibration(void *unused) +{ + unsigned int cpu = smp_processor_id(); + u64 curr_tsc; + s_time_t curr_local_stime; + + if ( platform_timer_is_tsc() ) + { + make_tsctimer_record(); + update_vcpu_system_time(current); + return; + } + + local_irq_disable(); + while ( !cpu_isset(cpu, local_time_calibrate_cpumask) ) + cpu_relax(); + curr_local_stime = get_s_time(); + rdtscll(curr_tsc); + cpu_clear(cpu, local_time_calibrate_cpumask); + local_irq_enable(); + + local_time_calibration(curr_master_stime, curr_local_stime, curr_tsc); +} + +static void master_local_time_calibration(void *unused) +{ + unsigned int cpu = smp_processor_id(); + static DEFINE_SPINLOCK(lock); + u64 curr_tsc; + s_time_t curr_local_stime; + struct cpu_time *t = &this_cpu(cpu_time); + + if ( platform_timer_is_tsc() ) + { + smp_call_function(slave_local_time_calibration, NULL, 0, 0); + make_tsctimer_record(); + update_vcpu_system_time(current); + set_timer(&t->calibration_timer, NOW() + MILLISECS(10*1000)); + return; + } + + spin_lock(&lock); + + smp_call_function(slave_local_time_calibration, NULL, 0, 0); + + local_irq_disable(); + curr_master_stime = read_platform_stime(); + local_time_calibrate_cpumask = cpu_online_map; + curr_local_stime = get_s_time(); + rdtscll(curr_tsc); + cpu_clear(cpu, local_time_calibrate_cpumask); + local_irq_enable(); + + local_time_calibration(curr_master_stime, curr_local_stime, curr_tsc); + + spin_unlock(&lock); + set_timer(&t->calibration_timer, NEXT_EPOCH(curr_local_stime)); - if ( smp_processor_id() == 0 ) - platform_time_calibration(); + platform_time_calibration(); } void init_percpu_time(void) @@ -1049,9 +1095,12 @@ void init_percpu_time(void) t->stime_local_stamp = now; out: - init_timer(&t->calibration_timer, local_time_calibration, + if ( smp_processor_id() == 0 ) + { + init_timer(&t->calibration_timer, master_local_time_calibration, NULL, smp_processor_id()); - set_timer(&t->calibration_timer, NEXT_EPOCH(NOW())); + set_timer(&t->calibration_timer, NEXT_EPOCH(NOW())); + } } /* Late init function (after all CPUs are booted). */