xen-vtx-unstable
changeset 6033:217fb2d1f364
More time-interface fixes.
Signed-off-by: Keir Fraser <keir@xensource.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
author | kaf24@firebug.cl.cam.ac.uk |
---|---|
date | Sat Aug 06 15:24:22 2005 +0000 (2005-08-06) |
parents | 7931f14bd447 |
children | eb98d18771ca |
files | linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c xen/arch/ia64/xentime.c xen/arch/x86/domain.c xen/arch/x86/time.c xen/common/dom0_ops.c xen/include/asm-x86/time.h xen/include/public/dom0_ops.h xen/include/public/xen.h xen/include/xen/time.h |
line diff
1.1 --- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c Sat Aug 06 09:54:57 2005 +0000 1.2 +++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c Sat Aug 06 15:24:22 2005 +0000 1.3 @@ -115,7 +115,8 @@ struct shadow_time_info { 1.4 u32 version; 1.5 }; 1.6 static DEFINE_PER_CPU(struct shadow_time_info, shadow_time); 1.7 -static struct timeval shadow_tv; 1.8 +static struct timespec shadow_tv; 1.9 +static u32 shadow_tv_version; 1.10 1.11 /* Keep track of last time we did processing/updating of jiffies and xtime. */ 1.12 static u64 processed_system_time; /* System time (ns) at last processing. */ 1.13 @@ -123,18 +124,6 @@ static DEFINE_PER_CPU(u64, processed_sys 1.14 1.15 #define NS_PER_TICK (1000000000ULL/HZ) 1.16 1.17 -#define HANDLE_USEC_UNDERFLOW(_tv) do { \ 1.18 - while ((_tv).tv_usec < 0) { \ 1.19 - (_tv).tv_usec += USEC_PER_SEC; \ 1.20 - (_tv).tv_sec--; \ 1.21 - } \ 1.22 -} while (0) 1.23 -#define HANDLE_USEC_OVERFLOW(_tv) do { \ 1.24 - while ((_tv).tv_usec >= USEC_PER_SEC) { \ 1.25 - (_tv).tv_usec -= USEC_PER_SEC; \ 1.26 - (_tv).tv_sec++; \ 1.27 - } \ 1.28 -} while (0) 1.29 static inline void __normalize_time(time_t *sec, s64 *nsec) 1.30 { 1.31 while (*nsec >= NSEC_PER_SEC) { 1.32 @@ -231,14 +220,16 @@ static void update_wallclock(void) 1.33 shared_info_t *s = HYPERVISOR_shared_info; 1.34 long wtm_nsec, xtime_nsec; 1.35 time_t wtm_sec, xtime_sec; 1.36 - u64 tmp, usec; 1.37 + u64 tmp, nsec; 1.38 1.39 - if ((shadow_tv.tv_sec == s->wc_sec) && 1.40 - (shadow_tv.tv_usec == s->wc_usec)) 1.41 - return; 1.42 - 1.43 - shadow_tv.tv_sec = s->wc_sec; 1.44 - shadow_tv.tv_usec = s->wc_usec; 1.45 + do { 1.46 + shadow_tv_version = s->wc_version; 1.47 + rmb(); 1.48 + shadow_tv.tv_sec = s->wc_sec; 1.49 + shadow_tv.tv_nsec = s->wc_nsec; 1.50 + rmb(); 1.51 + } 1.52 + while ((s->wc_version & 1) | (shadow_tv_version ^ s->wc_version)); 1.53 1.54 if (INDEPENDENT_WALLCLOCK()) 1.55 return; 1.56 @@ -247,15 +238,14 @@ static void update_wallclock(void) 1.57 return; 1.58 1.59 /* Adjust wall-clock time base based on wall_jiffies ticks. */ 1.60 - usec = processed_system_time; 1.61 - do_div(usec, 1000); 1.62 - usec += (u64)shadow_tv.tv_sec * 1000000ULL; 1.63 - usec += (u64)shadow_tv.tv_usec; 1.64 - usec -= (jiffies - wall_jiffies) * (USEC_PER_SEC / HZ); 1.65 + nsec = processed_system_time; 1.66 + nsec += (u64)shadow_tv.tv_sec * 1000000000ULL; 1.67 + nsec += (u64)shadow_tv.tv_nsec; 1.68 + nsec -= (jiffies - wall_jiffies) * (u64)(NSEC_PER_SEC / HZ); 1.69 1.70 /* Split wallclock base into seconds and nanoseconds. */ 1.71 - tmp = usec; 1.72 - xtime_nsec = do_div(tmp, 1000000) * 1000ULL; 1.73 + tmp = nsec; 1.74 + xtime_nsec = do_div(tmp, 1000000000); 1.75 xtime_sec = (time_t)tmp; 1.76 1.77 wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - xtime_sec); 1.78 @@ -279,7 +269,7 @@ static void get_time_values_from_xen(voi 1.79 dst = &per_cpu(shadow_time, smp_processor_id()); 1.80 1.81 do { 1.82 - dst->version = src->time_version2; 1.83 + dst->version = src->version; 1.84 rmb(); 1.85 dst->tsc_timestamp = src->tsc_timestamp; 1.86 dst->system_timestamp = src->system_time; 1.87 @@ -287,7 +277,7 @@ static void get_time_values_from_xen(voi 1.88 dst->tsc_shift = src->tsc_shift; 1.89 rmb(); 1.90 } 1.91 - while (dst->version != src->time_version1); 1.92 + while ((src->version & 1) | (dst->version ^ src->version)); 1.93 1.94 dst->tsc_to_usec_mul = dst->tsc_to_nsec_mul / 1000; 1.95 } 1.96 @@ -300,7 +290,7 @@ static inline int time_values_up_to_date 1.97 src = &HYPERVISOR_shared_info->vcpu_time[cpu]; 1.98 dst = &per_cpu(shadow_time, cpu); 1.99 1.100 - return (dst->version == src->time_version2); 1.101 + return (dst->version == src->version); 1.102 } 1.103 1.104 /* 1.105 @@ -469,7 +459,7 @@ int do_settimeofday(struct timespec *tv) 1.106 dom0_op_t op; 1.107 op.cmd = DOM0_SETTIME; 1.108 op.u.settime.secs = xentime.tv_sec; 1.109 - op.u.settime.usecs = xentime.tv_nsec / NSEC_PER_USEC; 1.110 + op.u.settime.nsecs = xentime.tv_nsec; 1.111 op.u.settime.system_time = shadow->system_timestamp; 1.112 write_sequnlock_irq(&xtime_lock); 1.113 HYPERVISOR_dom0_op(&op); 1.114 @@ -574,7 +564,7 @@ static inline void do_timer_interrupt(in 1.115 } 1.116 while (!time_values_up_to_date(cpu)); 1.117 1.118 - if (unlikely(delta < 0) || unlikely(delta_cpu < 0)) { 1.119 + if (unlikely(delta < (s64)-1000000) || unlikely(delta_cpu < 0)) { 1.120 printk("Timer ISR/%d: Time went backwards: " 1.121 "delta=%lld cpu_delta=%lld shadow=%lld " 1.122 "off=%lld processed=%lld cpu_processed=%lld\n", 1.123 @@ -603,7 +593,8 @@ static inline void do_timer_interrupt(in 1.124 profile_tick(CPU_PROFILING, regs); 1.125 } 1.126 1.127 - update_wallclock(); 1.128 + if (unlikely(shadow_tv_version != HYPERVISOR_shared_info->wc_version)) 1.129 + update_wallclock(); 1.130 } 1.131 1.132 /* 1.133 @@ -792,8 +783,6 @@ void __init time_init(void) 1.134 #endif 1.135 get_time_values_from_xen(); 1.136 update_wallclock(); 1.137 - xtime.tv_sec = shadow_tv.tv_sec; 1.138 - xtime.tv_nsec = shadow_tv.tv_usec * NSEC_PER_USEC; 1.139 set_normalized_timespec(&wall_to_monotonic, 1.140 -xtime.tv_sec, -xtime.tv_nsec); 1.141 processed_system_time = per_cpu(shadow_time, 0).system_timestamp;
2.1 --- a/xen/arch/ia64/xentime.c Sat Aug 06 09:54:57 2005 +0000 2.2 +++ b/xen/arch/ia64/xentime.c Sat Aug 06 15:24:22 2005 +0000 2.3 @@ -48,7 +48,7 @@ static inline u64 get_time_delta(void) 2.4 static s_time_t stime_irq = 0x0; /* System time at last 'time update' */ 2.5 unsigned long itc_scale; 2.6 unsigned long itc_at_irq; 2.7 -static unsigned long wc_sec, wc_usec; /* UTC time at last 'time update'. */ 2.8 +static unsigned long wc_sec, wc_nsec; /* UTC time at last 'time update'. */ 2.9 //static rwlock_t time_lock = RW_LOCK_UNLOCKED; 2.10 static irqreturn_t vmx_timer_interrupt (int irq, void *dev_id, struct pt_regs *regs); 2.11 2.12 @@ -103,25 +103,22 @@ void update_dom_time(struct vcpu *v) 2.13 } 2.14 2.15 /* Set clock to <secs,usecs> after 00:00:00 UTC, 1 January, 1970. */ 2.16 -void do_settime(unsigned long secs, unsigned long usecs, u64 system_time_base) 2.17 +void do_settime(unsigned long secs, unsigned long nsecs, u64 system_time_base) 2.18 { 2.19 #ifdef CONFIG_VTI 2.20 - s64 delta; 2.21 - long _usecs = (long)usecs; 2.22 + u64 _nsecs; 2.23 2.24 write_lock_irq(&xtime_lock); 2.25 2.26 - delta = (s64)(stime_irq - system_time_base); 2.27 - 2.28 - _usecs += (long)(delta/1000); 2.29 - while ( _usecs >= 1000000 ) 2.30 + _nsecs = (u64)nsecs + (s64)(stime_irq - system_time_base); 2.31 + while ( _nsecs >= 1000000000 ) 2.32 { 2.33 - _usecs -= 1000000; 2.34 + _nsecs -= 1000000000; 2.35 secs++; 2.36 } 2.37 2.38 wc_sec = secs; 2.39 - wc_usec = _usecs; 2.40 + wc_nsec = (unsigned long)_nsecs; 2.41 2.42 write_unlock_irq(&xtime_lock); 2.43 2.44 @@ -290,13 +287,13 @@ int __init init_xen_time() 2.45 /* Wallclock time starts as the initial RTC time. */ 2.46 efi_gettimeofday(&tm); 2.47 wc_sec = tm.tv_sec; 2.48 - wc_usec = tm.tv_nsec/1000; 2.49 + wc_nsec = tm.tv_nsec; 2.50 2.51 2.52 printk("Time init:\n"); 2.53 printk(".... System Time: %ldns\n", NOW()); 2.54 printk(".... scale: %16lX\n", itc_scale); 2.55 - printk(".... Wall Clock: %lds %ldus\n", wc_sec, wc_usec); 2.56 + printk(".... Wall Clock: %lds %ldus\n", wc_sec, wc_nsec/1000); 2.57 2.58 return 0; 2.59 } 2.60 @@ -338,10 +335,10 @@ vmx_timer_interrupt (int irq, void *dev_ 2.61 (*(unsigned long *)&jiffies_64)++; 2.62 2.63 /* Update wall time. */ 2.64 - wc_usec += 1000000/HZ; 2.65 - if ( wc_usec >= 1000000 ) 2.66 + wc_nsec += 1000000000/HZ; 2.67 + if ( wc_nsec >= 1000000000 ) 2.68 { 2.69 - wc_usec -= 1000000; 2.70 + wc_nsec -= 1000000000; 2.71 wc_sec++; 2.72 } 2.73
3.1 --- a/xen/arch/x86/domain.c Sat Aug 06 09:54:57 2005 +0000 3.2 +++ b/xen/arch/x86/domain.c Sat Aug 06 15:24:22 2005 +0000 3.3 @@ -279,6 +279,8 @@ void arch_do_createdomain(struct vcpu *v 3.4 3.5 shadow_lock_init(d); 3.6 INIT_LIST_HEAD(&d->arch.free_shadow_frames); 3.7 + 3.8 + init_domain_time(d); 3.9 } 3.10 3.11 void arch_do_boot_vcpu(struct vcpu *v)
4.1 --- a/xen/arch/x86/time.c Sat Aug 06 09:54:57 2005 +0000 4.2 +++ b/xen/arch/x86/time.c Sat Aug 06 15:24:22 2005 +0000 4.3 @@ -43,7 +43,7 @@ unsigned long hpet_address; 4.4 spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; 4.5 int timer_ack = 0; 4.6 unsigned long volatile jiffies; 4.7 -static unsigned long wc_sec, wc_usec; /* UTC time at last 'time update'. */ 4.8 +static u32 wc_sec, wc_nsec; /* UTC time at last 'time update'. */ 4.9 4.10 struct time_scale { 4.11 int shift; 4.12 @@ -630,25 +630,32 @@ s_time_t get_s_time(void) 4.13 return now; 4.14 } 4.15 4.16 +static inline void version_update_begin(u32 *version) 4.17 +{ 4.18 + /* Explicitly OR with 1 just in case version number gets out of sync. */ 4.19 + *version = (*version + 1) | 1; 4.20 + wmb(); 4.21 +} 4.22 + 4.23 +static inline void version_update_end(u32 *version) 4.24 +{ 4.25 + wmb(); 4.26 + (*version)++; 4.27 +} 4.28 + 4.29 static inline void __update_dom_time(struct vcpu *v) 4.30 { 4.31 struct cpu_time *t = &cpu_time[smp_processor_id()]; 4.32 struct vcpu_time_info *u = &v->domain->shared_info->vcpu_time[v->vcpu_id]; 4.33 4.34 - u->time_version1++; 4.35 - wmb(); 4.36 + version_update_begin(&u->version); 4.37 4.38 u->tsc_timestamp = t->local_tsc_stamp; 4.39 u->system_time = t->stime_local_stamp; 4.40 u->tsc_to_system_mul = t->tsc_scale.mul_frac; 4.41 u->tsc_shift = (s8)t->tsc_scale.shift; 4.42 4.43 - wmb(); 4.44 - u->time_version2++; 4.45 - 4.46 - /* Should only do this during do_settime(). */ 4.47 - v->domain->shared_info->wc_sec = wc_sec; 4.48 - v->domain->shared_info->wc_usec = wc_usec; 4.49 + version_update_end(&u->version); 4.50 } 4.51 4.52 void update_dom_time(struct vcpu *v) 4.53 @@ -659,21 +666,39 @@ void update_dom_time(struct vcpu *v) 4.54 } 4.55 4.56 /* Set clock to <secs,usecs> after 00:00:00 UTC, 1 January, 1970. */ 4.57 -void do_settime(unsigned long secs, unsigned long usecs, u64 system_time_base) 4.58 +void do_settime(unsigned long secs, unsigned long nsecs, u64 system_time_base) 4.59 { 4.60 - u64 x, base_usecs; 4.61 - u32 y; 4.62 + u64 x; 4.63 + u32 y, _wc_sec, _wc_nsec; 4.64 + struct domain *d; 4.65 + shared_info_t *s; 4.66 4.67 - base_usecs = system_time_base; 4.68 - do_div(base_usecs, 1000); 4.69 + x = (secs * 1000000000ULL) + (u64)nsecs + system_time_base; 4.70 + y = do_div(x, 1000000000); 4.71 + 4.72 + wc_sec = _wc_sec = (u32)x; 4.73 + wc_nsec = _wc_nsec = (u32)y; 4.74 + 4.75 + read_lock(&domlist_lock); 4.76 4.77 - x = (secs * 1000000ULL) + (u64)usecs + base_usecs; 4.78 - y = do_div(x, 1000000); 4.79 + for_each_domain ( d ) 4.80 + { 4.81 + s = d->shared_info; 4.82 + version_update_begin(&s->wc_version); 4.83 + s->wc_sec = _wc_sec; 4.84 + s->wc_nsec = _wc_nsec; 4.85 + version_update_end(&s->wc_version); 4.86 + } 4.87 4.88 - wc_sec = (unsigned long)x; 4.89 - wc_usec = (unsigned long)y; 4.90 + read_unlock(&domlist_lock); 4.91 +} 4.92 4.93 - __update_dom_time(current); 4.94 +void init_domain_time(struct domain *d) 4.95 +{ 4.96 + version_update_begin(&d->shared_info->wc_version); 4.97 + d->shared_info->wc_sec = wc_sec; 4.98 + d->shared_info->wc_nsec = wc_nsec; 4.99 + version_update_end(&d->shared_info->wc_version); 4.100 } 4.101 4.102 static void local_time_calibration(void *unused)
5.1 --- a/xen/common/dom0_ops.c Sat Aug 06 09:54:57 2005 +0000 5.2 +++ b/xen/common/dom0_ops.c Sat Aug 06 15:24:22 2005 +0000 5.3 @@ -475,7 +475,7 @@ long do_dom0_op(dom0_op_t *u_dom0_op) 5.4 case DOM0_SETTIME: 5.5 { 5.6 do_settime(op->u.settime.secs, 5.7 - op->u.settime.usecs, 5.8 + op->u.settime.nsecs, 5.9 op->u.settime.system_time); 5.10 ret = 0; 5.11 }
6.1 --- a/xen/include/asm-x86/time.h Sat Aug 06 09:54:57 2005 +0000 6.2 +++ b/xen/include/asm-x86/time.h Sat Aug 06 15:24:22 2005 +0000 6.3 @@ -7,4 +7,7 @@ extern int timer_ack; 6.4 extern void calibrate_tsc_bp(void); 6.5 extern void calibrate_tsc_ap(void); 6.6 6.7 +struct domain; 6.8 +extern void init_domain_time(struct domain *d); 6.9 + 6.10 #endif /* __X86_TIME_H__ */
7.1 --- a/xen/include/public/dom0_ops.h Sat Aug 06 09:54:57 2005 +0000 7.2 +++ b/xen/include/public/dom0_ops.h Sat Aug 06 15:24:22 2005 +0000 7.3 @@ -131,14 +131,14 @@ typedef struct { 7.4 } dom0_debug_t; 7.5 7.6 /* 7.7 - * Set clock such that it would read <secs,usecs> after 00:00:00 UTC, 7.8 + * Set clock such that it would read <secs,nsecs> after 00:00:00 UTC, 7.9 * 1 January, 1970 if the current system time was <system_time>. 7.10 */ 7.11 #define DOM0_SETTIME 17 7.12 typedef struct { 7.13 /* IN variables. */ 7.14 u32 secs; 7.15 - u32 usecs; 7.16 + u32 nsecs; 7.17 u64 system_time; 7.18 } dom0_settime_t; 7.19
8.1 --- a/xen/include/public/xen.h Sat Aug 06 09:54:57 2005 +0000 8.2 +++ b/xen/include/public/xen.h Sat Aug 06 15:24:22 2005 +0000 8.3 @@ -331,14 +331,15 @@ typedef struct vcpu_info { 8.4 8.5 typedef struct vcpu_time_info { 8.6 /* 8.7 - * The following values are updated periodically (and not necessarily 8.8 - * atomically!). The guest OS detects this because 'time_version1' is 8.9 - * incremented just before updating these values, and 'time_version2' is 8.10 - * incremented immediately after. See the Xen-specific Linux code for an 8.11 - * example of how to read these values safely (arch/xen/kernel/time.c). 8.12 + * Updates to the following values are preceded and followed by an 8.13 + * increment of 'version'. The guest can therefore detect updates by 8.14 + * looking for changes to 'version'. If the least-significant bit of 8.15 + * the version number is set then an update is in progress and the guest 8.16 + * must wait to read a consistent set of values. 8.17 + * The correct way to interact with the version number is similar to 8.18 + * Linux's seqlock: see the implementations of read_seqbegin/read_seqretry. 8.19 */ 8.20 - u32 time_version1; 8.21 - u32 time_version2; 8.22 + u32 version; 8.23 u64 tsc_timestamp; /* TSC at last update of time vals. */ 8.24 u64 system_time; /* Time, in nanosecs, since boot. */ 8.25 /* 8.26 @@ -400,8 +401,9 @@ typedef struct shared_info { 8.27 * Wallclock time: updated only by control software. Guests should base 8.28 * their gettimeofday() syscall on this wallclock-base value. 8.29 */ 8.30 - u32 wc_sec; /* Secs 00:00:00 UTC, Jan 1, 1970. */ 8.31 - u32 wc_usec; /* Usecs 00:00:00 UTC, Jan 1, 1970. */ 8.32 + u32 wc_version; /* Version counter: see vcpu_time_info_t. */ 8.33 + u32 wc_sec; /* Secs 00:00:00 UTC, Jan 1, 1970. */ 8.34 + u32 wc_nsec; /* Nsecs 00:00:00 UTC, Jan 1, 1970. */ 8.35 8.36 arch_shared_info_t arch; 8.37
9.1 --- a/xen/include/xen/time.h Sat Aug 06 09:54:57 2005 +0000 9.2 +++ b/xen/include/xen/time.h Sat Aug 06 15:24:22 2005 +0000 9.3 @@ -57,7 +57,7 @@ s_time_t get_s_time(void); 9.4 9.5 extern void update_dom_time(struct vcpu *v); 9.6 extern void do_settime( 9.7 - unsigned long secs, unsigned long usecs, u64 system_time_base); 9.8 + unsigned long secs, unsigned long nsecs, u64 system_time_base); 9.9 9.10 #endif /* __XEN_TIME_H__ */ 9.11