ia64/xen-unstable

changeset 2113:ddda299ee74b

bitkeeper revision 1.1159.3.1 (4113ca544f2ijHD3gffCMUC9u9wOaQ)

Make time code more robust.
author cl349@freefall.cl.cam.ac.uk
date Fri Aug 06 18:13:40 2004 +0000 (2004-08-06)
parents 8d3ff2e0b2e0
children 1b4dbe8d9172
files linux-2.6.7-xen-sparse/arch/xen/i386/kernel/time.c linux-2.6.7-xen-sparse/arch/xen/i386/kernel/timers/timer_tsc.c linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/mach-xen/do_timer.h linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/ptrace.h
line diff
     1.1 --- a/linux-2.6.7-xen-sparse/arch/xen/i386/kernel/time.c	Fri Aug 06 14:11:00 2004 +0000
     1.2 +++ b/linux-2.6.7-xen-sparse/arch/xen/i386/kernel/time.c	Fri Aug 06 18:13:40 2004 +0000
     1.3 @@ -87,15 +87,71 @@ EXPORT_SYMBOL(i8253_lock);
     1.4  
     1.5  struct timer_opts *cur_timer = &timer_none;
     1.6  
     1.7 -extern u64 shadow_system_time;
     1.8 -extern u32 shadow_time_delta_usecs;
     1.9 -extern void __get_time_values_from_xen(void);
    1.10 +/* These are peridically updated in shared_info, and then copied here. */
    1.11 +u32 shadow_tsc_stamp;
    1.12 +u64 shadow_system_time;
    1.13 +static u32 shadow_time_version;
    1.14 +static struct timeval shadow_tv;
    1.15 +extern u64 processed_system_time;
    1.16 +
    1.17 +#define NS_PER_TICK (1000000000ULL/HZ)
    1.18 +
    1.19 +/*
    1.20 + * Reads a consistent set of time-base values from Xen, into a shadow data
    1.21 + * area. Must be called with the xtime_lock held for writing.
    1.22 + */
    1.23 +int __get_time_values_from_xen(void)
    1.24 +{
    1.25 +	s64 delta;
    1.26 +	unsigned int ticks = 0;
    1.27 +
    1.28 +	do {
    1.29 +		shadow_time_version = HYPERVISOR_shared_info->time_version2;
    1.30 +		rmb();
    1.31 +		shadow_tv.tv_sec    = HYPERVISOR_shared_info->wc_sec;
    1.32 +		shadow_tv.tv_usec   = HYPERVISOR_shared_info->wc_usec;
    1.33 +		shadow_tsc_stamp    = HYPERVISOR_shared_info->tsc_timestamp.tsc_bits;
    1.34 +		shadow_system_time  = HYPERVISOR_shared_info->system_time;
    1.35 +		rmb();
    1.36 +	}
    1.37 +	while (shadow_time_version != HYPERVISOR_shared_info->time_version1);
    1.38 +
    1.39 +	delta = (s64)(shadow_system_time +
    1.40 +		      cur_timer->get_offset() * NSEC_PER_USEC -
    1.41 +		      processed_system_time);
    1.42 +	if (delta < 0) {
    1.43 +		printk("Timer ISR: Time went backwards: %lld\n", delta);
    1.44 +		return 1;
    1.45 +	}
    1.46 +
    1.47 +	if (delta < NS_PER_TICK)
    1.48 +		return 1;
    1.49 +
    1.50 +	/* Process elapsed jiffies since last call. */
    1.51 +	while (delta >= NS_PER_TICK) {
    1.52 +		ticks++;
    1.53 +		delta -= NS_PER_TICK;
    1.54 +		processed_system_time += NS_PER_TICK;
    1.55 +	}
    1.56 +	jiffies_64 += ticks - 1;
    1.57 +	/* We leave one tick for the caller to add to jiffies since
    1.58 +	 * the timer interrupt will call do_timer(). */
    1.59 +
    1.60 +	return 0;
    1.61 +}
    1.62 +
    1.63 +#define TIME_VALUES_UP_TO_DATE \
    1.64 +	(shadow_time_version == HYPERVISOR_shared_info->time_version2)
    1.65 +
    1.66 +/*
    1.67 + * We use this to ensure that gettimeofday() is monotonically increasing. We
    1.68 + * only break this guarantee if the wall clock jumps backwards "a long way".
    1.69 + */
    1.70 +static struct timeval last_seen_tv = {0,0};
    1.71  
    1.72  /* Keep track of last time we did processing/updating of jiffies and xtime. */
    1.73  u64 processed_system_time;   /* System time (ns) at last processing. */
    1.74  
    1.75 -#define NS_PER_TICK (1000000000ULL/HZ)
    1.76 -
    1.77  /*
    1.78   * This version of gettimeofday has microsecond resolution
    1.79   * and better than microsecond precision on fast x86 machines with TSC.
    1.80 @@ -130,7 +186,22 @@ void do_gettimeofday(struct timeval *tv)
    1.81  			usec += lost * (USEC_PER_SEC / HZ);
    1.82  
    1.83  		sec = xtime.tv_sec;
    1.84 -		usec += (xtime.tv_nsec / 1000);
    1.85 +		usec += (xtime.tv_nsec / NSEC_PER_USEC);
    1.86 +
    1.87 +		if (unlikely(!TIME_VALUES_UP_TO_DATE)) {
    1.88 +			/*
    1.89 +			 * We may have blocked for a long time,
    1.90 +			 * rendering our calculations invalid
    1.91 +			 * (e.g. the time delta may have
    1.92 +			 * overflowed). Detect that and recalculate
    1.93 +			 * with fresh values.
    1.94 +			 */
    1.95 +			write_seqlock(&xtime_lock);
    1.96 +			if (__get_time_values_from_xen() == 0)
    1.97 +				jiffies_64++;
    1.98 +			write_sequnlock(&xtime_lock);
    1.99 +			continue;
   1.100 +		}
   1.101  	} while (read_seqretry(&xtime_lock, seq));
   1.102  
   1.103  	while (usec >= 1000000) {
   1.104 @@ -138,6 +209,16 @@ void do_gettimeofday(struct timeval *tv)
   1.105  		sec++;
   1.106  	}
   1.107  
   1.108 +	/* Ensure that time-of-day is monotonically increasing. */
   1.109 +	if ((sec < last_seen_tv.tv_sec) ||
   1.110 +	    ((sec == last_seen_tv.tv_sec) && (usec < last_seen_tv.tv_usec))) {
   1.111 +		sec = last_seen_tv.tv_sec;
   1.112 +		usec = last_seen_tv.tv_usec;
   1.113 +	} else {
   1.114 +		last_seen_tv.tv_sec = sec;
   1.115 +		last_seen_tv.tv_usec = usec;
   1.116 +	}
   1.117 +
   1.118  	tv->tv_sec = sec;
   1.119  	tv->tv_usec = usec;
   1.120  }
   1.121 @@ -172,6 +253,9 @@ int do_settimeofday(struct timespec *tv)
   1.122  	time_status |= STA_UNSYNC;
   1.123  	time_maxerror = NTP_PHASE_LIMIT;
   1.124  	time_esterror = NTP_PHASE_LIMIT;
   1.125 +
   1.126 +	last_seen_tv.tv_sec = 0;
   1.127 +
   1.128  	write_sequnlock_irq(&xtime_lock);
   1.129  	clock_was_set();
   1.130  	return 0;
   1.131 @@ -236,8 +320,7 @@ static inline void do_timer_interrupt(in
   1.132  	}
   1.133  #endif
   1.134  
   1.135 -	if (regs)
   1.136 -		do_timer_interrupt_hook(regs);
   1.137 +	do_timer_interrupt_hook(regs);
   1.138  
   1.139  #if 0				/* XEN PRIV */
   1.140  	/*
   1.141 @@ -288,8 +371,6 @@ static inline void do_timer_interrupt(in
   1.142   */
   1.143  irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
   1.144  {
   1.145 -	s64 delta;
   1.146 -
   1.147  	/*
   1.148  	 * Here we are in the timer irq handler. We just have irqs locally
   1.149  	 * disabled but we don't know if the timer_bh is running on the other
   1.150 @@ -299,17 +380,7 @@ irqreturn_t timer_interrupt(int irq, voi
   1.151  	 */
   1.152  	write_seqlock(&xtime_lock);
   1.153  
   1.154 -	__get_time_values_from_xen();
   1.155 -
   1.156 -	shadow_time_delta_usecs = cur_timer->get_offset() * NSEC_PER_USEC;
   1.157 -	delta = (s64)(shadow_system_time + shadow_time_delta_usecs -
   1.158 -		      processed_system_time);
   1.159 -	if (delta < 0) {
   1.160 -		printk("Timer ISR: Time went backwards: %lld\n", delta);
   1.161 -		goto out;
   1.162 -	}
   1.163 -
   1.164 -	if (delta < NS_PER_TICK)
   1.165 +	if (__get_time_values_from_xen())
   1.166  		goto out;
   1.167  
   1.168  	cur_timer->mark_offset();
   1.169 @@ -426,12 +497,15 @@ void __init time_init(void)
   1.170  #endif
   1.171  	xtime.tv_sec = HYPERVISOR_shared_info->wc_sec;
   1.172  	wall_to_monotonic.tv_sec = -xtime.tv_sec;
   1.173 -	xtime.tv_nsec = HYPERVISOR_shared_info->wc_usec * 1000;
   1.174 +	xtime.tv_nsec = HYPERVISOR_shared_info->wc_usec * NSEC_PER_USEC;
   1.175  	wall_to_monotonic.tv_nsec = -xtime.tv_nsec;
   1.176  
   1.177  	cur_timer = select_timer();
   1.178  	printk(KERN_INFO "Using %s for high-res timesource\n",cur_timer->name);
   1.179  
   1.180 +	__get_time_values_from_xen();
   1.181 +	processed_system_time = shadow_system_time;
   1.182 +
   1.183  	time_irq  = bind_virq_to_irq(VIRQ_TIMER);
   1.184  
   1.185  	(void)setup_irq(time_irq, &irq_timer);
     2.1 --- a/linux-2.6.7-xen-sparse/arch/xen/i386/kernel/timers/timer_tsc.c	Fri Aug 06 14:11:00 2004 +0000
     2.2 +++ b/linux-2.6.7-xen-sparse/arch/xen/i386/kernel/timers/timer_tsc.c	Fri Aug 06 18:13:40 2004 +0000
     2.3 @@ -79,39 +79,9 @@ static int count2; /* counter for mark_o
     2.4   */
     2.5  static unsigned long fast_gettimeoffset_quotient;
     2.6  
     2.7 -
     2.8 -/* These are peridically updated in shared_info, and then copied here. */
     2.9 -static u32 shadow_tsc_stamp;
    2.10 -u64 shadow_system_time;
    2.11 -static u32 shadow_time_version;
    2.12 -static struct timeval shadow_tv;
    2.13 -u32 shadow_time_delta_usecs;
    2.14 -static unsigned int rdtsc_bitshift;
    2.15 -extern u64 processed_system_time;
    2.16 -
    2.17 -#define NS_PER_TICK (1000000000ULL/HZ)
    2.18 -
    2.19 -/*
    2.20 - * Reads a consistent set of time-base values from Xen, into a shadow data
    2.21 - * area. Must be called with the xtime_lock held for writing.
    2.22 - */
    2.23 -void __get_time_values_from_xen(void)
    2.24 -{
    2.25 -	do {
    2.26 -		shadow_time_version = HYPERVISOR_shared_info->time_version2;
    2.27 -		rmb();
    2.28 -		shadow_tv.tv_sec    = HYPERVISOR_shared_info->wc_sec;
    2.29 -		shadow_tv.tv_usec   = HYPERVISOR_shared_info->wc_usec;
    2.30 -		shadow_tsc_stamp    = HYPERVISOR_shared_info->tsc_timestamp.tsc_bits;
    2.31 -		shadow_system_time  = HYPERVISOR_shared_info->system_time;
    2.32 -		rmb();
    2.33 -	}
    2.34 -	while (shadow_time_version != HYPERVISOR_shared_info->time_version1);
    2.35 -}
    2.36 -
    2.37 -#define TIME_VALUES_UP_TO_DATE \
    2.38 -	(shadow_time_version == HYPERVISOR_shared_info->time_version2)
    2.39 -
    2.40 +unsigned int rdtsc_bitshift;
    2.41 +extern u32 shadow_tsc_stamp;
    2.42 +extern u64 shadow_system_time;
    2.43  
    2.44  static unsigned long get_offset_tsc(void)
    2.45  {
    2.46 @@ -188,23 +158,9 @@ unsigned long long sched_clock(void)
    2.47  
    2.48  static void mark_offset_tsc(void)
    2.49  {
    2.50 -	s64 delta;
    2.51 -	unsigned int ticks = 0;
    2.52 -
    2.53 -	write_seqlock(&monotonic_lock);
    2.54 -
    2.55 -	delta = (s64)(shadow_system_time + shadow_time_delta_usecs -
    2.56 -		      processed_system_time);
    2.57 -
    2.58 -	/* Process elapsed jiffies since last call. */
    2.59 -	while (delta >= NS_PER_TICK) {
    2.60 -		ticks++;
    2.61 -		delta -= NS_PER_TICK;
    2.62 -		processed_system_time += NS_PER_TICK;
    2.63 -	}
    2.64 -	jiffies_64 += ticks - 1;
    2.65  
    2.66  	/* update the monotonic base value */
    2.67 +	write_seqlock(&monotonic_lock);
    2.68  	monotonic_base = shadow_system_time;
    2.69  	monotonic_offset = shadow_tsc_stamp;
    2.70  	write_sequnlock(&monotonic_lock);
    2.71 @@ -383,7 +339,8 @@ static int __init init_tsc(char* overrid
    2.72  	printk(KERN_INFO "Xen reported: %lu.%03lu MHz processor.\n", 
    2.73  	       cpu_khz / 1000, cpu_khz % 1000);
    2.74  
    2.75 -	/* (10^6 * 2^32) / cpu_khz = (2^32 * 1 / (clocks/us)) */
    2.76 +	/* (10^6 * 2^32) / cpu_hz = (10^3 * 2^32) / cpu_khz =
    2.77 +	   (2^32 * 1 / (clocks/us)) */
    2.78  	{	
    2.79  		unsigned long eax=0, edx=1000;
    2.80  		__asm__("divl %2"
    2.81 @@ -396,9 +353,6 @@ static int __init init_tsc(char* overrid
    2.82  
    2.83  	set_cyc2ns_scale(cpu_khz/1000);
    2.84  
    2.85 -	__get_time_values_from_xen();
    2.86 -	processed_system_time = shadow_system_time;
    2.87 -
    2.88  	rdtscll(alarm);
    2.89  
    2.90  	return 0;
     3.1 --- a/linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/mach-xen/do_timer.h	Fri Aug 06 14:11:00 2004 +0000
     3.2 +++ b/linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/mach-xen/do_timer.h	Fri Aug 06 18:13:40 2004 +0000
     3.3 @@ -22,9 +22,10 @@ static inline void do_timer_interrupt_ho
     3.4   * system, in that case we have to call the local interrupt handler.
     3.5   */
     3.6  #ifndef CONFIG_X86_LOCAL_APIC
     3.7 -	x86_do_profile(regs);
     3.8 +	if (regs)
     3.9 +		x86_do_profile(regs);
    3.10  #else
    3.11 -	if (!using_apic_timer)
    3.12 +	if (regs && !using_apic_timer)
    3.13  		smp_local_timer_interrupt(regs);
    3.14  #endif
    3.15  }
     4.1 --- a/linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/ptrace.h	Fri Aug 06 14:11:00 2004 +0000
     4.2 +++ b/linux-2.6.7-xen-sparse/include/asm-xen/asm-i386/ptrace.h	Fri Aug 06 18:13:40 2004 +0000
     4.3 @@ -55,7 +55,7 @@ struct pt_regs {
     4.4  #define PTRACE_SET_THREAD_AREA    26
     4.5  
     4.6  #ifdef __KERNEL__
     4.7 -#define user_mode(regs) ((VM_MASK & (regs)->eflags) || (2 & (regs)->xcs))
     4.8 +#define user_mode(regs) ((regs) && ((VM_MASK & (regs)->eflags) || (2 & (regs)->xcs)))
     4.9  #define instruction_pointer(regs) ((regs)->eip)
    4.10  #endif
    4.11