[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] Fix both Xen and XenLinux to correctly handle 64-bit
# HG changeset patch # User kaf24@xxxxxxxxxxxxxxxxxxxx # Node ID 6fc0b68b0a9ca2ab6164ee02db7fcf70905665f0 # Parent a9ee400a5da98acc8da566a24ecae05902b2bed2 Fix both Xen and XenLinux to correctly handle 64-bit time deltas. Good for robustness and future-proofing. Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx> diff -r a9ee400a5da9 -r 6fc0b68b0a9c linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c --- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c Mon Aug 8 09:13:19 2005 +++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c Mon Aug 8 10:59:22 2005 @@ -166,25 +166,34 @@ .delay = delay_tsc, }; -static inline u32 down_shift(u64 time, int shift) -{ +/* + * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction, + * yielding a 64-bit result. + */ +static inline u64 scale_delta(u64 delta, u32 mul_frac, int shift) +{ + u64 product; + u32 tmp; + if ( shift < 0 ) - return (u32)(time >> -shift); - return (u32)((u32)time << shift); -} - -/* - * 32-bit multiplication of integer multiplicand and fractional multiplier - * yielding 32-bit integer product. - */ -static inline u32 mul_frac(u32 multiplicand, u32 multiplier) -{ - u32 product_int, product_frac; + delta >>= -shift; + else + delta <<= shift; + __asm__ ( - "mul %3" - : "=a" (product_frac), "=d" (product_int) - : "0" (multiplicand), "r" (multiplier) ); - return product_int; + "pushl %%edx ; " + "mull %3 ; " + "popl %%eax ; " + "pushl %%edx ; " + "mull %3 ; " + "popl %3 ; " + "addl %3,%%eax ; " + "xorl %3,%3 ; " + "adcl %3,%%edx ; " + : "=A" (product), "=r" (tmp) + : "A" (delta), "1" (mul_frac) ); + + return product; } void init_cpu_khz(void) @@ -192,27 +201,28 @@ u64 __cpu_khz = 1000000ULL << 32; struct vcpu_time_info *info = &HYPERVISOR_shared_info->vcpu_time[0]; do_div(__cpu_khz, info->tsc_to_system_mul); - cpu_khz = down_shift(__cpu_khz, -info->tsc_shift); + if ( info->tsc_shift < 0 ) + cpu_khz = __cpu_khz >> -info->tsc_shift; + else + cpu_khz = __cpu_khz << info->tsc_shift; printk(KERN_INFO "Xen reported: %lu.%03lu MHz processor.\n", cpu_khz / 1000, cpu_khz % 1000); } static u64 get_nsec_offset(struct shadow_time_info *shadow) { - u64 now; - u32 delta; + u64 now, delta; rdtscll(now); - delta = down_shift(now - shadow->tsc_timestamp, shadow->tsc_shift); - return mul_frac(delta, shadow->tsc_to_nsec_mul); + delta = now - shadow->tsc_timestamp; + return scale_delta(delta, shadow->tsc_to_nsec_mul, shadow->tsc_shift); } static unsigned long get_usec_offset(struct shadow_time_info *shadow) { - u64 now; - u32 delta; + u64 now, delta; rdtscll(now); - delta = down_shift(now - shadow->tsc_timestamp, shadow->tsc_shift); - return mul_frac(delta, shadow->tsc_to_usec_mul); + delta = now - shadow->tsc_timestamp; + return scale_delta(delta, shadow->tsc_to_usec_mul, shadow->tsc_shift); } static void update_wallclock(void) diff -r a9ee400a5da9 -r 6fc0b68b0a9c xen/arch/x86/time.c --- a/xen/arch/x86/time.c Mon Aug 8 09:13:19 2005 +++ b/xen/arch/x86/time.c Mon Aug 8 10:59:22 2005 @@ -67,13 +67,6 @@ static spinlock_t platform_timer_lock = SPIN_LOCK_UNLOCKED; static u64 (*read_platform_count)(void); -static inline u32 down_shift(u64 time, int shift) -{ - if ( shift < 0 ) - return (u32)(time >> -shift); - return (u32)((u32)time << shift); -} - /* * 32-bit division of integer dividend and integer divisor yielding * 32-bit fractional quotient. @@ -83,7 +76,7 @@ u32 quotient, remainder; ASSERT(dividend < divisor); __asm__ ( - "div %4" + "divl %4" : "=a" (quotient), "=d" (remainder) : "0" (0), "1" (dividend), "r" (divisor) ); return quotient; @@ -101,6 +94,36 @@ : "=a" (product_frac), "=d" (product_int) : "0" (multiplicand), "r" (multiplier) ); return product_int; +} + +/* + * Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction, + * yielding a 64-bit result. + */ +static inline u64 scale_delta(u64 delta, struct time_scale *scale) +{ + u64 product; + u32 tmp; + + if ( scale->shift < 0 ) + delta >>= -scale->shift; + else + delta <<= scale->shift; + + __asm__ ( + "pushl %%edx ; " + "mull %3 ; " + "popl %%eax ; " + "pushl %%edx ; " + "mull %3 ; " + "popl %3 ; " + "addl %3,%%eax ; " + "xorl %3,%3 ; " + "adcl %3,%%edx ; " + : "=A" (product), "=r" (tmp) + : "A" (delta), "1" (scale->mul_frac) ); + + return product; } void timer_interrupt(int irq, void *dev_id, struct cpu_user_regs *regs) @@ -486,11 +509,9 @@ static s_time_t __read_platform_stime(u64 platform_time) { - u64 diff64 = platform_time - platform_timer_stamp; - u32 diff = down_shift(diff64, platform_timer_scale.shift); + u64 diff = platform_time - platform_timer_stamp; ASSERT(spin_is_locked(&platform_timer_lock)); - return (stime_platform_stamp + - (u64)mul_frac(diff, platform_timer_scale.mul_frac)); + return (stime_platform_stamp + scale_delta(diff, &platform_timer_scale)); } static s_time_t read_platform_stime(void) @@ -619,13 +640,12 @@ s_time_t get_s_time(void) { struct cpu_time *t = &cpu_time[smp_processor_id()]; - u64 tsc; - u32 delta; + u64 tsc, delta; s_time_t now; rdtscll(tsc); - delta = down_shift(tsc - t->local_tsc_stamp, t->tsc_scale.shift); - now = t->stime_local_stamp + (u64)mul_frac(delta, t->tsc_scale.mul_frac); + delta = tsc - t->local_tsc_stamp; + now = t->stime_local_stamp + scale_delta(delta, &t->tsc_scale); return now; } _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |