ia64/xen-unstable

changeset 6048:217fb2d1f364

More time-interface fixes.
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