ia64/xen-unstable

changeset 6108:10b395bc465e

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>
author kaf24@firebug.cl.cam.ac.uk
date Thu Aug 11 13:07:08 2005 +0000 (2005-08-11)
parents 0761551e993a
children 37ac3cf33506
files linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c xen/arch/x86/domain.c xen/arch/x86/domain_build.c xen/arch/x86/time.c
line diff
     1.1 --- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c	Thu Aug 11 12:06:32 2005 +0000
     1.2 +++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c	Thu Aug 11 13:07:08 2005 +0000
     1.3 @@ -227,12 +227,38 @@ static unsigned long get_usec_offset(str
     1.4  	return scale_delta(delta, shadow->tsc_to_usec_mul, shadow->tsc_shift);
     1.5  }
     1.6  
     1.7 +static void __update_wallclock(time_t sec, long nsec)
     1.8 +{
     1.9 +	long wtm_nsec, xtime_nsec;
    1.10 +	time_t wtm_sec, xtime_sec;
    1.11 +	u64 tmp, wc_nsec;
    1.12 +
    1.13 +	/* Adjust wall-clock time base based on wall_jiffies ticks. */
    1.14 +	wc_nsec = processed_system_time;
    1.15 +	wc_nsec += (u64)sec * 1000000000ULL;
    1.16 +	wc_nsec += (u64)nsec;
    1.17 +	wc_nsec -= (jiffies - wall_jiffies) * (u64)(NSEC_PER_SEC / HZ);
    1.18 +
    1.19 +	/* Split wallclock base into seconds and nanoseconds. */
    1.20 +	tmp = wc_nsec;
    1.21 +	xtime_nsec = do_div(tmp, 1000000000);
    1.22 +	xtime_sec  = (time_t)tmp;
    1.23 +
    1.24 +	wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - xtime_sec);
    1.25 +	wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - xtime_nsec);
    1.26 +
    1.27 +	set_normalized_timespec(&xtime, xtime_sec, xtime_nsec);
    1.28 +	set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
    1.29 +
    1.30 +	time_adjust = 0;		/* stop active adjtime() */
    1.31 +	time_status |= STA_UNSYNC;
    1.32 +	time_maxerror = NTP_PHASE_LIMIT;
    1.33 +	time_esterror = NTP_PHASE_LIMIT;
    1.34 +}
    1.35 +
    1.36  static void update_wallclock(void)
    1.37  {
    1.38  	shared_info_t *s = HYPERVISOR_shared_info;
    1.39 -	long wtm_nsec, xtime_nsec;
    1.40 -	time_t wtm_sec, xtime_sec;
    1.41 -	u64 tmp, nsec;
    1.42  
    1.43  	do {
    1.44  		shadow_tv_version = s->wc_version;
    1.45 @@ -243,25 +269,8 @@ static void update_wallclock(void)
    1.46  	}
    1.47  	while ((s->wc_version & 1) | (shadow_tv_version ^ s->wc_version));
    1.48  
    1.49 -	if (independent_wallclock)
    1.50 -		return;
    1.51 -
    1.52 -	/* Adjust wall-clock time base based on wall_jiffies ticks. */
    1.53 -	nsec = processed_system_time;
    1.54 -	nsec += (u64)shadow_tv.tv_sec * 1000000000ULL;
    1.55 -	nsec += (u64)shadow_tv.tv_nsec;
    1.56 -	nsec -= (jiffies - wall_jiffies) * (u64)(NSEC_PER_SEC / HZ);
    1.57 -
    1.58 -	/* Split wallclock base into seconds and nanoseconds. */
    1.59 -	tmp = nsec;
    1.60 -	xtime_nsec = do_div(tmp, 1000000000);
    1.61 -	xtime_sec  = (time_t)tmp;
    1.62 -
    1.63 -	wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - xtime_sec);
    1.64 -	wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - xtime_nsec);
    1.65 -
    1.66 -	set_normalized_timespec(&xtime, xtime_sec, xtime_nsec);
    1.67 -	set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
    1.68 +	if (!independent_wallclock)
    1.69 +		__update_wallclock(shadow_tv.tv_sec, shadow_tv.tv_nsec);
    1.70  }
    1.71  
    1.72  /*
    1.73 @@ -408,19 +417,15 @@ EXPORT_SYMBOL(do_gettimeofday);
    1.74  
    1.75  int do_settimeofday(struct timespec *tv)
    1.76  {
    1.77 -	time_t wtm_sec, sec = tv->tv_sec;
    1.78 -	long wtm_nsec;
    1.79 +	time_t sec;
    1.80  	s64 nsec;
    1.81 -	struct timespec xentime;
    1.82  	unsigned int cpu;
    1.83  	struct shadow_time_info *shadow;
    1.84 +	dom0_op_t op;
    1.85  
    1.86  	if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
    1.87  		return -EINVAL;
    1.88  
    1.89 -	if (!independent_wallclock && !(xen_start_info.flags & SIF_INITDOMAIN))
    1.90 -		return 0; /* Silent failure? */
    1.91 -
    1.92  	cpu = get_cpu();
    1.93  	shadow = &per_cpu(shadow_time, cpu);
    1.94  
    1.95 @@ -431,51 +436,30 @@ int do_settimeofday(struct timespec *tv)
    1.96  	 * overflows. If that were to happen then our shadow time values would
    1.97  	 * be stale, so we can retry with fresh ones.
    1.98  	 */
    1.99 - again:
   1.100 -	nsec = (s64)tv->tv_nsec - (s64)get_nsec_offset(shadow);
   1.101 -	if (unlikely(!time_values_up_to_date(cpu))) {
   1.102 +	for ( ; ; ) {
   1.103 +		nsec = (s64)tv->tv_nsec - (s64)get_nsec_offset(shadow);
   1.104 +		if (time_values_up_to_date(cpu))
   1.105 +			break;
   1.106  		get_time_values_from_xen();
   1.107 -		goto again;
   1.108 +	}
   1.109 +	sec = tv->tv_sec;
   1.110 +	__normalize_time(&sec, &nsec);
   1.111 +
   1.112 +	if ((xen_start_info.flags & SIF_INITDOMAIN) &&
   1.113 +	    !independent_wallclock) {
   1.114 +		op.cmd = DOM0_SETTIME;
   1.115 +		op.u.settime.secs        = sec;
   1.116 +		op.u.settime.nsecs       = nsec;
   1.117 +		op.u.settime.system_time = shadow->system_timestamp;
   1.118 +		HYPERVISOR_dom0_op(&op);
   1.119 +		update_wallclock();
   1.120 +	} else if (independent_wallclock) {
   1.121 +		nsec -= shadow->system_timestamp;
   1.122 +		__normalize_time(&sec, &nsec);
   1.123 +		__update_wallclock(sec, nsec);
   1.124  	}
   1.125  
   1.126 -	__normalize_time(&sec, &nsec);
   1.127 -	set_normalized_timespec(&xentime, sec, nsec);
   1.128 -
   1.129 -	/*
   1.130 -	 * This is revolting. We need to set "xtime" correctly. However, the
   1.131 -	 * value in this location is the value at the most recent update of
   1.132 -	 * wall time.  Discover what correction gettimeofday() would have
   1.133 -	 * made, and then undo it!
   1.134 -	 */
   1.135 -	nsec -= (jiffies - wall_jiffies) * TICK_NSEC;
   1.136 -
   1.137 -	nsec -= (shadow->system_timestamp - processed_system_time);
   1.138 -
   1.139 -	__normalize_time(&sec, &nsec);
   1.140 -	wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
   1.141 -	wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
   1.142 -
   1.143 -	set_normalized_timespec(&xtime, sec, nsec);
   1.144 -	set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
   1.145 -
   1.146 -	time_adjust = 0;		/* stop active adjtime() */
   1.147 -	time_status |= STA_UNSYNC;
   1.148 -	time_maxerror = NTP_PHASE_LIMIT;
   1.149 -	time_esterror = NTP_PHASE_LIMIT;
   1.150 -
   1.151 -#ifdef CONFIG_XEN_PRIVILEGED_GUEST
   1.152 -	if ((xen_start_info.flags & SIF_INITDOMAIN) &&
   1.153 -	    !independent_wallclock) {
   1.154 -		dom0_op_t op;
   1.155 -		op.cmd = DOM0_SETTIME;
   1.156 -		op.u.settime.secs        = xentime.tv_sec;
   1.157 -		op.u.settime.nsecs       = xentime.tv_nsec;
   1.158 -		op.u.settime.system_time = shadow->system_timestamp;
   1.159 -		write_sequnlock_irq(&xtime_lock);
   1.160 -		HYPERVISOR_dom0_op(&op);
   1.161 -	} else
   1.162 -#endif
   1.163 -		write_sequnlock_irq(&xtime_lock);
   1.164 +	write_sequnlock_irq(&xtime_lock);
   1.165  
   1.166  	put_cpu();
   1.167  
   1.168 @@ -492,6 +476,9 @@ static int set_rtc_mmss(unsigned long no
   1.169  
   1.170  	WARN_ON(irqs_disabled());
   1.171  
   1.172 +	if (!(xen_start_info.flags & SIF_INITDOMAIN))
   1.173 +		return 0;
   1.174 +
   1.175  	/* gets recalled with irq locally disabled */
   1.176  	spin_lock_irq(&rtc_lock);
   1.177  	if (efi_enabled)
   1.178 @@ -603,8 +590,10 @@ static inline void do_timer_interrupt(in
   1.179  		profile_tick(CPU_PROFILING, regs);
   1.180  	}
   1.181  
   1.182 -	if (unlikely(shadow_tv_version != HYPERVISOR_shared_info->wc_version))
   1.183 +	if (shadow_tv_version != HYPERVISOR_shared_info->wc_version) {
   1.184  		update_wallclock();
   1.185 +		clock_was_set();
   1.186 +	}
   1.187  }
   1.188  
   1.189  /*
     2.1 --- a/xen/arch/x86/domain.c	Thu Aug 11 12:06:32 2005 +0000
     2.2 +++ b/xen/arch/x86/domain.c	Thu Aug 11 13:07:08 2005 +0000
     2.3 @@ -279,8 +279,6 @@ void arch_do_createdomain(struct vcpu *v
     2.4      
     2.5      shadow_lock_init(d);        
     2.6      INIT_LIST_HEAD(&d->arch.free_shadow_frames);
     2.7 -
     2.8 -    init_domain_time(d);
     2.9  }
    2.10  
    2.11  void arch_do_boot_vcpu(struct vcpu *v)
    2.12 @@ -481,7 +479,10 @@ int arch_set_info_guest(
    2.13      }
    2.14  
    2.15      update_pagetables(v);
    2.16 -    
    2.17 +
    2.18 +    if ( v->vcpu_id == 0 )
    2.19 +        init_domain_time(d);
    2.20 +
    2.21      /* Don't redo final setup */
    2.22      set_bit(_VCPUF_initialised, &v->vcpu_flags);
    2.23  
     3.1 --- a/xen/arch/x86/domain_build.c	Thu Aug 11 12:06:32 2005 +0000
     3.2 +++ b/xen/arch/x86/domain_build.c	Thu Aug 11 13:07:08 2005 +0000
     3.3 @@ -618,6 +618,8 @@ int construct_dom0(struct domain *d,
     3.4      /* DOM0 gets access to everything. */
     3.5      physdev_init_dom0(d);
     3.6  
     3.7 +    init_domain_time(d);
     3.8 +
     3.9      set_bit(_DOMF_constructed, &d->domain_flags);
    3.10  
    3.11      new_thread(v, dsi.v_kernentry, vstack_end, vstartinfo_start);
     4.1 --- a/xen/arch/x86/time.c	Thu Aug 11 12:06:32 2005 +0000
     4.2 +++ b/xen/arch/x86/time.c	Thu Aug 11 13:07:08 2005 +0000
     4.3 @@ -44,6 +44,7 @@ spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED
     4.4  int timer_ack = 0;
     4.5  unsigned long volatile jiffies;
     4.6  static u32 wc_sec, wc_nsec; /* UTC time at last 'time update'. */
     4.7 +static spinlock_t wc_lock = SPIN_LOCK_UNLOCKED;
     4.8  
     4.9  struct time_scale {
    4.10      int shift;
    4.11 @@ -699,13 +700,14 @@ void do_settime(unsigned long secs, unsi
    4.12      struct domain *d;
    4.13      shared_info_t *s;
    4.14  
    4.15 -    x = (secs * 1000000000ULL) + (u64)nsecs + system_time_base;
    4.16 +    x = (secs * 1000000000ULL) + (u64)nsecs - system_time_base;
    4.17      y = do_div(x, 1000000000);
    4.18  
    4.19      wc_sec  = _wc_sec  = (u32)x;
    4.20      wc_nsec = _wc_nsec = (u32)y;
    4.21  
    4.22      read_lock(&domlist_lock);
    4.23 +    spin_lock(&wc_lock);
    4.24  
    4.25      for_each_domain ( d )
    4.26      {
    4.27 @@ -716,15 +718,18 @@ void do_settime(unsigned long secs, unsi
    4.28          version_update_end(&s->wc_version);
    4.29      }
    4.30  
    4.31 +    spin_unlock(&wc_lock);
    4.32      read_unlock(&domlist_lock);
    4.33  }
    4.34  
    4.35  void init_domain_time(struct domain *d)
    4.36  {
    4.37 +    spin_lock(&wc_lock);
    4.38      version_update_begin(&d->shared_info->wc_version);
    4.39      d->shared_info->wc_sec  = wc_sec;
    4.40      d->shared_info->wc_nsec = wc_nsec;
    4.41      version_update_end(&d->shared_info->wc_version);
    4.42 +    spin_unlock(&wc_lock);
    4.43  }
    4.44  
    4.45  static void local_time_calibration(void *unused)