diff options
author | kaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk> | 2005-08-11 13:07:08 +0000 |
---|---|---|
committer | kaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk> | 2005-08-11 13:07:08 +0000 |
commit | e20872cf5eb608bed38f3f72012ada39c903ef1f (patch) | |
tree | e0f7c94ea147ede98aaccebdfece7c90d48808eb | |
parent | 3140b13b50aaf89b2616fb6b0d4c24350026dd0e (diff) | |
download | xen-e20872cf5eb608bed38f3f72012ada39c903ef1f.tar.gz xen-e20872cf5eb608bed38f3f72012ada39c903ef1f.tar.bz2 xen-e20872cf5eb608bed38f3f72012ada39c903ef1f.zip |
More time fixes. Now time is set properly in domU's, and
settimeofday() is simplified and fixed.
Signed-off-by: Keir Fraser <keir@xensource.com>
-rw-r--r-- | linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c | 115 | ||||
-rw-r--r-- | xen/arch/x86/domain.c | 7 | ||||
-rw-r--r-- | xen/arch/x86/domain_build.c | 2 | ||||
-rw-r--r-- | xen/arch/x86/time.c | 7 |
4 files changed, 64 insertions, 67 deletions
diff --git a/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c b/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c index 4e30c2ec83..6b2fe1ccc5 100644 --- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c +++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c @@ -227,33 +227,20 @@ static unsigned long get_usec_offset(struct shadow_time_info *shadow) return scale_delta(delta, shadow->tsc_to_usec_mul, shadow->tsc_shift); } -static void update_wallclock(void) +static void __update_wallclock(time_t sec, long nsec) { - shared_info_t *s = HYPERVISOR_shared_info; long wtm_nsec, xtime_nsec; time_t wtm_sec, xtime_sec; - u64 tmp, nsec; - - do { - shadow_tv_version = s->wc_version; - rmb(); - shadow_tv.tv_sec = s->wc_sec; - shadow_tv.tv_nsec = s->wc_nsec; - rmb(); - } - while ((s->wc_version & 1) | (shadow_tv_version ^ s->wc_version)); - - if (independent_wallclock) - return; + u64 tmp, wc_nsec; /* Adjust wall-clock time base based on wall_jiffies ticks. */ - nsec = processed_system_time; - nsec += (u64)shadow_tv.tv_sec * 1000000000ULL; - nsec += (u64)shadow_tv.tv_nsec; - nsec -= (jiffies - wall_jiffies) * (u64)(NSEC_PER_SEC / HZ); + wc_nsec = processed_system_time; + wc_nsec += (u64)sec * 1000000000ULL; + wc_nsec += (u64)nsec; + wc_nsec -= (jiffies - wall_jiffies) * (u64)(NSEC_PER_SEC / HZ); /* Split wallclock base into seconds and nanoseconds. */ - tmp = nsec; + tmp = wc_nsec; xtime_nsec = do_div(tmp, 1000000000); xtime_sec = (time_t)tmp; @@ -262,6 +249,28 @@ static void update_wallclock(void) set_normalized_timespec(&xtime, xtime_sec, xtime_nsec); set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); + + time_adjust = 0; /* stop active adjtime() */ + time_status |= STA_UNSYNC; + time_maxerror = NTP_PHASE_LIMIT; + time_esterror = NTP_PHASE_LIMIT; +} + +static void update_wallclock(void) +{ + shared_info_t *s = HYPERVISOR_shared_info; + + do { + shadow_tv_version = s->wc_version; + rmb(); + shadow_tv.tv_sec = s->wc_sec; + shadow_tv.tv_nsec = s->wc_nsec; + rmb(); + } + while ((s->wc_version & 1) | (shadow_tv_version ^ s->wc_version)); + + if (!independent_wallclock) + __update_wallclock(shadow_tv.tv_sec, shadow_tv.tv_nsec); } /* @@ -408,19 +417,15 @@ EXPORT_SYMBOL(do_gettimeofday); int do_settimeofday(struct timespec *tv) { - time_t wtm_sec, sec = tv->tv_sec; - long wtm_nsec; + time_t sec; s64 nsec; - struct timespec xentime; unsigned int cpu; struct shadow_time_info *shadow; + dom0_op_t op; if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) return -EINVAL; - if (!independent_wallclock && !(xen_start_info.flags & SIF_INITDOMAIN)) - return 0; /* Silent failure? */ - cpu = get_cpu(); shadow = &per_cpu(shadow_time, cpu); @@ -431,51 +436,30 @@ int do_settimeofday(struct timespec *tv) * overflows. If that were to happen then our shadow time values would * be stale, so we can retry with fresh ones. */ - again: - nsec = (s64)tv->tv_nsec - (s64)get_nsec_offset(shadow); - if (unlikely(!time_values_up_to_date(cpu))) { + for ( ; ; ) { + nsec = (s64)tv->tv_nsec - (s64)get_nsec_offset(shadow); + if (time_values_up_to_date(cpu)) + break; get_time_values_from_xen(); - goto again; } - + sec = tv->tv_sec; __normalize_time(&sec, &nsec); - set_normalized_timespec(&xentime, sec, nsec); - - /* - * This is revolting. We need to set "xtime" correctly. However, the - * value in this location is the value at the most recent update of - * wall time. Discover what correction gettimeofday() would have - * made, and then undo it! - */ - nsec -= (jiffies - wall_jiffies) * TICK_NSEC; - - nsec -= (shadow->system_timestamp - processed_system_time); - - __normalize_time(&sec, &nsec); - wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); - wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); - - set_normalized_timespec(&xtime, sec, nsec); - set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); - time_adjust = 0; /* stop active adjtime() */ - time_status |= STA_UNSYNC; - time_maxerror = NTP_PHASE_LIMIT; - time_esterror = NTP_PHASE_LIMIT; - -#ifdef CONFIG_XEN_PRIVILEGED_GUEST if ((xen_start_info.flags & SIF_INITDOMAIN) && !independent_wallclock) { - dom0_op_t op; op.cmd = DOM0_SETTIME; - op.u.settime.secs = xentime.tv_sec; - op.u.settime.nsecs = xentime.tv_nsec; + op.u.settime.secs = sec; + op.u.settime.nsecs = nsec; op.u.settime.system_time = shadow->system_timestamp; - write_sequnlock_irq(&xtime_lock); HYPERVISOR_dom0_op(&op); - } else -#endif - write_sequnlock_irq(&xtime_lock); + update_wallclock(); + } else if (independent_wallclock) { + nsec -= shadow->system_timestamp; + __normalize_time(&sec, &nsec); + __update_wallclock(sec, nsec); + } + + write_sequnlock_irq(&xtime_lock); put_cpu(); @@ -492,6 +476,9 @@ static int set_rtc_mmss(unsigned long nowtime) WARN_ON(irqs_disabled()); + if (!(xen_start_info.flags & SIF_INITDOMAIN)) + return 0; + /* gets recalled with irq locally disabled */ spin_lock_irq(&rtc_lock); if (efi_enabled) @@ -603,8 +590,10 @@ static inline void do_timer_interrupt(int irq, void *dev_id, profile_tick(CPU_PROFILING, regs); } - if (unlikely(shadow_tv_version != HYPERVISOR_shared_info->wc_version)) + if (shadow_tv_version != HYPERVISOR_shared_info->wc_version) { update_wallclock(); + clock_was_set(); + } } /* diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c index dedebbbd6c..efd967464d 100644 --- a/xen/arch/x86/domain.c +++ b/xen/arch/x86/domain.c @@ -279,8 +279,6 @@ void arch_do_createdomain(struct vcpu *v) shadow_lock_init(d); INIT_LIST_HEAD(&d->arch.free_shadow_frames); - - init_domain_time(d); } void arch_do_boot_vcpu(struct vcpu *v) @@ -481,7 +479,10 @@ int arch_set_info_guest( } update_pagetables(v); - + + if ( v->vcpu_id == 0 ) + init_domain_time(d); + /* Don't redo final setup */ set_bit(_VCPUF_initialised, &v->vcpu_flags); diff --git a/xen/arch/x86/domain_build.c b/xen/arch/x86/domain_build.c index 9ba5b4512b..b9941763c4 100644 --- a/xen/arch/x86/domain_build.c +++ b/xen/arch/x86/domain_build.c @@ -618,6 +618,8 @@ int construct_dom0(struct domain *d, /* DOM0 gets access to everything. */ physdev_init_dom0(d); + init_domain_time(d); + set_bit(_DOMF_constructed, &d->domain_flags); new_thread(v, dsi.v_kernentry, vstack_end, vstartinfo_start); diff --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c index d978c8170e..81100e7a1c 100644 --- a/xen/arch/x86/time.c +++ b/xen/arch/x86/time.c @@ -44,6 +44,7 @@ spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; int timer_ack = 0; unsigned long volatile jiffies; static u32 wc_sec, wc_nsec; /* UTC time at last 'time update'. */ +static spinlock_t wc_lock = SPIN_LOCK_UNLOCKED; struct time_scale { int shift; @@ -699,13 +700,14 @@ void do_settime(unsigned long secs, unsigned long nsecs, u64 system_time_base) struct domain *d; shared_info_t *s; - x = (secs * 1000000000ULL) + (u64)nsecs + system_time_base; + x = (secs * 1000000000ULL) + (u64)nsecs - system_time_base; y = do_div(x, 1000000000); wc_sec = _wc_sec = (u32)x; wc_nsec = _wc_nsec = (u32)y; read_lock(&domlist_lock); + spin_lock(&wc_lock); for_each_domain ( d ) { @@ -716,15 +718,18 @@ void do_settime(unsigned long secs, unsigned long nsecs, u64 system_time_base) version_update_end(&s->wc_version); } + spin_unlock(&wc_lock); read_unlock(&domlist_lock); } void init_domain_time(struct domain *d) { + spin_lock(&wc_lock); version_update_begin(&d->shared_info->wc_version); d->shared_info->wc_sec = wc_sec; d->shared_info->wc_nsec = wc_nsec; version_update_end(&d->shared_info->wc_version); + spin_unlock(&wc_lock); } static void local_time_calibration(void *unused) |