ia64/xen-unstable

changeset 6059:6fc0b68b0a9c

Fix both Xen and XenLinux to correctly handle 64-bit
time deltas. Good for robustness and future-proofing.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Mon Aug 08 10:59:22 2005 +0000 (2005-08-08)
parents a9ee400a5da9
children 704e6cc4a684
files linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c xen/arch/x86/time.c
line diff
     1.1 --- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c	Mon Aug 08 09:13:19 2005 +0000
     1.2 +++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c	Mon Aug 08 10:59:22 2005 +0000
     1.3 @@ -166,25 +166,34 @@ struct timer_opts timer_tsc = {
     1.4  	.delay = delay_tsc,
     1.5  };
     1.6  
     1.7 -static inline u32 down_shift(u64 time, int shift)
     1.8 +/*
     1.9 + * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction,
    1.10 + * yielding a 64-bit result.
    1.11 + */
    1.12 +static inline u64 scale_delta(u64 delta, u32 mul_frac, int shift)
    1.13  {
    1.14 +	u64 product;
    1.15 +	u32 tmp;
    1.16 +
    1.17  	if ( shift < 0 )
    1.18 -		return (u32)(time >> -shift);
    1.19 -	return (u32)((u32)time << shift);
    1.20 -}
    1.21 +		delta >>= -shift;
    1.22 +	else
    1.23 +		delta <<= shift;
    1.24  
    1.25 -/*
    1.26 - * 32-bit multiplication of integer multiplicand and fractional multiplier
    1.27 - * yielding 32-bit integer product.
    1.28 - */
    1.29 -static inline u32 mul_frac(u32 multiplicand, u32 multiplier)
    1.30 -{
    1.31 -	u32 product_int, product_frac;
    1.32  	__asm__ (
    1.33 -		"mul %3"
    1.34 -		: "=a" (product_frac), "=d" (product_int)
    1.35 -		: "0" (multiplicand), "r" (multiplier) );
    1.36 -	return product_int;
    1.37 +		"pushl %%edx    ; "
    1.38 +		"mull  %3       ; "
    1.39 +		"popl  %%eax    ; "
    1.40 +		"pushl %%edx    ; "
    1.41 +		"mull  %3       ; "
    1.42 +		"popl  %3       ; "
    1.43 +		"addl  %3,%%eax ; "
    1.44 +		"xorl  %3,%3    ; "
    1.45 +		"adcl  %3,%%edx ; "
    1.46 +		: "=A" (product), "=r" (tmp)
    1.47 +		: "A" (delta), "1" (mul_frac) );
    1.48 +
    1.49 +	return product;
    1.50  }
    1.51  
    1.52  void init_cpu_khz(void)
    1.53 @@ -192,27 +201,28 @@ void init_cpu_khz(void)
    1.54  	u64 __cpu_khz = 1000000ULL << 32;
    1.55  	struct vcpu_time_info *info = &HYPERVISOR_shared_info->vcpu_time[0];
    1.56  	do_div(__cpu_khz, info->tsc_to_system_mul);
    1.57 -	cpu_khz = down_shift(__cpu_khz, -info->tsc_shift);
    1.58 +	if ( info->tsc_shift < 0 )
    1.59 +		cpu_khz = __cpu_khz >> -info->tsc_shift;
    1.60 +	else
    1.61 +		cpu_khz = __cpu_khz << info->tsc_shift;
    1.62  	printk(KERN_INFO "Xen reported: %lu.%03lu MHz processor.\n",
    1.63  	       cpu_khz / 1000, cpu_khz % 1000);
    1.64  }
    1.65  
    1.66  static u64 get_nsec_offset(struct shadow_time_info *shadow)
    1.67  {
    1.68 -	u64 now;
    1.69 -	u32 delta;
    1.70 +	u64 now, delta;
    1.71  	rdtscll(now);
    1.72 -	delta = down_shift(now - shadow->tsc_timestamp, shadow->tsc_shift);
    1.73 -	return mul_frac(delta, shadow->tsc_to_nsec_mul);
    1.74 +	delta = now - shadow->tsc_timestamp;
    1.75 +	return scale_delta(delta, shadow->tsc_to_nsec_mul, shadow->tsc_shift);
    1.76  }
    1.77  
    1.78  static unsigned long get_usec_offset(struct shadow_time_info *shadow)
    1.79  {
    1.80 -	u64 now;
    1.81 -	u32 delta;
    1.82 +	u64 now, delta;
    1.83  	rdtscll(now);
    1.84 -	delta = down_shift(now - shadow->tsc_timestamp, shadow->tsc_shift);
    1.85 -	return mul_frac(delta, shadow->tsc_to_usec_mul);
    1.86 +	delta = now - shadow->tsc_timestamp;
    1.87 +	return scale_delta(delta, shadow->tsc_to_usec_mul, shadow->tsc_shift);
    1.88  }
    1.89  
    1.90  static void update_wallclock(void)
     2.1 --- a/xen/arch/x86/time.c	Mon Aug 08 09:13:19 2005 +0000
     2.2 +++ b/xen/arch/x86/time.c	Mon Aug 08 10:59:22 2005 +0000
     2.3 @@ -67,13 +67,6 @@ static struct time_scale platform_timer_
     2.4  static spinlock_t platform_timer_lock = SPIN_LOCK_UNLOCKED;
     2.5  static u64 (*read_platform_count)(void);
     2.6  
     2.7 -static inline u32 down_shift(u64 time, int shift)
     2.8 -{
     2.9 -    if ( shift < 0 )
    2.10 -        return (u32)(time >> -shift);
    2.11 -    return (u32)((u32)time << shift);
    2.12 -}
    2.13 -
    2.14  /*
    2.15   * 32-bit division of integer dividend and integer divisor yielding
    2.16   * 32-bit fractional quotient.
    2.17 @@ -83,7 +76,7 @@ static inline u32 div_frac(u32 dividend,
    2.18      u32 quotient, remainder;
    2.19      ASSERT(dividend < divisor);
    2.20      __asm__ ( 
    2.21 -        "div %4"
    2.22 +        "divl %4"
    2.23          : "=a" (quotient), "=d" (remainder)
    2.24          : "0" (0), "1" (dividend), "r" (divisor) );
    2.25      return quotient;
    2.26 @@ -103,6 +96,36 @@ static inline u32 mul_frac(u32 multiplic
    2.27      return product_int;
    2.28  }
    2.29  
    2.30 +/*
    2.31 + * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction,
    2.32 + * yielding a 64-bit result.
    2.33 + */
    2.34 +static inline u64 scale_delta(u64 delta, struct time_scale *scale)
    2.35 +{
    2.36 +    u64 product;
    2.37 +    u32 tmp;
    2.38 +
    2.39 +    if ( scale->shift < 0 )
    2.40 +        delta >>= -scale->shift;
    2.41 +    else
    2.42 +        delta <<= scale->shift;
    2.43 +
    2.44 +    __asm__ (
    2.45 +        "pushl %%edx    ; "
    2.46 +        "mull  %3       ; "
    2.47 +        "popl  %%eax    ; "
    2.48 +        "pushl %%edx    ; "
    2.49 +        "mull  %3       ; "
    2.50 +        "popl  %3       ; "
    2.51 +        "addl  %3,%%eax ; "
    2.52 +        "xorl  %3,%3    ; "
    2.53 +        "adcl  %3,%%edx ; "
    2.54 +        : "=A" (product), "=r" (tmp)
    2.55 +        : "A" (delta), "1" (scale->mul_frac) );
    2.56 +
    2.57 +    return product;
    2.58 +}
    2.59 +
    2.60  void timer_interrupt(int irq, void *dev_id, struct cpu_user_regs *regs)
    2.61  {
    2.62      if ( timer_ack ) 
    2.63 @@ -486,11 +509,9 @@ static int init_cyclone(void)
    2.64  
    2.65  static s_time_t __read_platform_stime(u64 platform_time)
    2.66  {
    2.67 -    u64 diff64 = platform_time - platform_timer_stamp;
    2.68 -    u32 diff   = down_shift(diff64, platform_timer_scale.shift);
    2.69 +    u64 diff = platform_time - platform_timer_stamp;
    2.70      ASSERT(spin_is_locked(&platform_timer_lock));
    2.71 -    return (stime_platform_stamp + 
    2.72 -            (u64)mul_frac(diff, platform_timer_scale.mul_frac));
    2.73 +    return (stime_platform_stamp + scale_delta(diff, &platform_timer_scale));
    2.74  }
    2.75  
    2.76  static s_time_t read_platform_stime(void)
    2.77 @@ -619,13 +640,12 @@ static unsigned long get_cmos_time(void)
    2.78  s_time_t get_s_time(void)
    2.79  {
    2.80      struct cpu_time *t = &cpu_time[smp_processor_id()];
    2.81 -    u64 tsc;
    2.82 -    u32 delta;
    2.83 +    u64 tsc, delta;
    2.84      s_time_t now;
    2.85  
    2.86      rdtscll(tsc);
    2.87 -    delta = down_shift(tsc - t->local_tsc_stamp, t->tsc_scale.shift);
    2.88 -    now = t->stime_local_stamp + (u64)mul_frac(delta, t->tsc_scale.mul_frac);
    2.89 +    delta = tsc - t->local_tsc_stamp;
    2.90 +    now = t->stime_local_stamp + scale_delta(delta, &t->tsc_scale);
    2.91  
    2.92      return now;
    2.93  }