ia64/xen-unstable
changeset 14467:0611355e0df2
hvm: Lower HPET frequency to 1/32 of the TSC.
The frequency of HPET device model is defined to be the same as TSC's,
but this doesn't work well with calibrate_tsc_hpet() in Linux kernel
2.6.16-33, causing some IA32 Linux HVM guests to failt o boot.
Calibrate_tsc_hpet() tries to figure out how many HPET ticks a TSC
cycle equals; it magnifies the result by scale of 2^32, trying to get
a more accurate result since it assumes the frequency of HPET in real
world is usually less than 1/100 of TSC, so the result of "(2^32 *
hpet_freq) / tsc_freq" may exceed 32bits, then a "divide error
(overflow)" would occur!
The result doesn't overflow every time because hpet_freq/tsc_freq may
less than 1.0 due to the little inaccuracy in the implementation of
HVM timer virtualization.
Signed-off-by: Dexuan Cui <dexuan.cui@intel.com>
The frequency of HPET device model is defined to be the same as TSC's,
but this doesn't work well with calibrate_tsc_hpet() in Linux kernel
2.6.16-33, causing some IA32 Linux HVM guests to failt o boot.
Calibrate_tsc_hpet() tries to figure out how many HPET ticks a TSC
cycle equals; it magnifies the result by scale of 2^32, trying to get
a more accurate result since it assumes the frequency of HPET in real
world is usually less than 1/100 of TSC, so the result of "(2^32 *
hpet_freq) / tsc_freq" may exceed 32bits, then a "divide error
(overflow)" would occur!
The result doesn't overflow every time because hpet_freq/tsc_freq may
less than 1.0 due to the little inaccuracy in the implementation of
HVM timer virtualization.
Signed-off-by: Dexuan Cui <dexuan.cui@intel.com>
author | kfraser@localhost.localdomain |
---|---|
date | Mon Mar 19 13:48:00 2007 +0000 (2007-03-19) |
parents | 9b9aa9d6603b |
children | bbda47597917 |
files | xen/arch/x86/hvm/hpet.c |
line diff
1.1 --- a/xen/arch/x86/hvm/hpet.c Mon Mar 19 13:44:31 2007 +0000 1.2 +++ b/xen/arch/x86/hvm/hpet.c Mon Mar 19 13:48:00 2007 +0000 1.3 @@ -29,6 +29,10 @@ 1.4 #define S_TO_NS 1000000000ULL /* 1s = 10^9 ns */ 1.5 #define S_TO_FS 1000000000000000ULL /* 1s = 10^15 fs */ 1.6 1.7 +/* Frequency_of_TSC / frequency_of_HPET = 32 */ 1.8 +#define TSC_PER_HPET_TICK 32 1.9 +#define guest_time_hpet(v) (hvm_get_guest_time(v) / TSC_PER_HPET_TICK) 1.10 + 1.11 #define HPET_ID 0x000 1.12 #define HPET_PERIOD 0x004 1.13 #define HPET_CFG 0x010 1.14 @@ -67,7 +71,9 @@ 1.15 #define HPET_TN_INT_ROUTE_CAP_MASK (0xffffffffULL \ 1.16 << HPET_TN_INT_ROUTE_CAP_SHIFT) 1.17 1.18 -#define hpet_tick_to_ns(h, tick) ((s_time_t)(tick)*S_TO_NS/h->tsc_freq) 1.19 +#define hpet_tick_to_ns(h, tick) ((s_time_t)(tick)* \ 1.20 + (S_TO_NS*TSC_PER_HPET_TICK)/h->tsc_freq) 1.21 + 1.22 #define timer_config(h, n) (h->hpet.timers[n].config) 1.23 #define timer_enabled(h, n) (timer_config(h, n) & HPET_TN_ENABLE) 1.24 #define timer_is_periodic(h, n) (timer_config(h, n) & HPET_TN_PERIODIC) 1.25 @@ -108,7 +114,7 @@ static inline int hpet_check_access_leng 1.26 static inline uint64_t hpet_read_maincounter(HPETState *h) 1.27 { 1.28 if ( hpet_enabled(h) ) 1.29 - return hvm_get_guest_time(h->vcpu) + h->mc_offset; 1.30 + return guest_time_hpet(h->vcpu) + h->mc_offset; 1.31 else 1.32 return h->hpet.mc64; 1.33 } 1.34 @@ -144,7 +150,7 @@ static void hpet_stop_timer(HPETState *h 1.35 1.36 /* the number of HPET tick that stands for 1.37 * 1/(2^10) second, namely, 0.9765625 milliseconds */ 1.38 -#define HPET_TINY_TIME_SPAN (h->tsc_freq >> 10) 1.39 +#define HPET_TINY_TIME_SPAN ((h->tsc_freq >> 10) / TSC_PER_HPET_TICK) 1.40 1.41 static void hpet_set_timer(HPETState *h, unsigned int tn) 1.42 { 1.43 @@ -225,14 +231,14 @@ static void hpet_write( 1.44 if ( !(old_val & HPET_CFG_ENABLE) && (new_val & HPET_CFG_ENABLE) ) 1.45 { 1.46 /* Enable main counter and interrupt generation. */ 1.47 - h->mc_offset = h->hpet.mc64 - hvm_get_guest_time(h->vcpu); 1.48 + h->mc_offset = h->hpet.mc64 - guest_time_hpet(h->vcpu); 1.49 for ( i = 0; i < HPET_TIMER_NUM; i++ ) 1.50 hpet_set_timer(h, i); 1.51 } 1.52 else if ( (old_val & HPET_CFG_ENABLE) && !(new_val & HPET_CFG_ENABLE) ) 1.53 { 1.54 /* Halt main counter and disable interrupt generation. */ 1.55 - h->hpet.mc64 = h->mc_offset + hvm_get_guest_time(h->vcpu); 1.56 + h->hpet.mc64 = h->mc_offset + guest_time_hpet(h->vcpu); 1.57 for ( i = 0; i < HPET_TIMER_NUM; i++ ) 1.58 hpet_stop_timer(h, i); 1.59 } 1.60 @@ -384,7 +390,7 @@ static int hpet_save(struct domain *d, h 1.61 HPETState *hp = &d->arch.hvm_domain.pl_time.vhpet; 1.62 1.63 /* Write the proper value into the main counter */ 1.64 - hp->hpet.mc64 = hp->mc_offset + hvm_get_guest_time(hp->vcpu); 1.65 + hp->hpet.mc64 = hp->mc_offset + guest_time_hpet(hp->vcpu); 1.66 1.67 /* Save the HPET registers */ 1.68 return hvm_save_entry(HPET, 0, h, &hp->hpet); 1.69 @@ -400,7 +406,7 @@ static int hpet_load(struct domain *d, h 1.70 return -EINVAL; 1.71 1.72 /* Recalculate the offset between the main counter and guest time */ 1.73 - hp->mc_offset = hp->hpet.mc64 - hvm_get_guest_time(hp->vcpu); 1.74 + hp->mc_offset = hp->hpet.mc64 - guest_time_hpet(hp->vcpu); 1.75 1.76 /* Restart the timers */ 1.77 for ( i = 0; i < HPET_TIMER_NUM; i++ ) 1.78 @@ -425,8 +431,8 @@ void hpet_init(struct vcpu *v) 1.79 h->hpet.capability = 0x8086A201ULL; 1.80 1.81 /* This is the number of femptoseconds per HPET tick. */ 1.82 - /* Here we define HPET's frequency to be the same as the TSC's. */ 1.83 - h->hpet.capability |= ((S_TO_FS/h->tsc_freq) << 32); 1.84 + /* Here we define HPET's frequency to be 1/32 of the TSC's */ 1.85 + h->hpet.capability |= ((S_TO_FS*TSC_PER_HPET_TICK/h->tsc_freq) << 32); 1.86 1.87 for ( i = 0; i < HPET_TIMER_NUM; i++ ) 1.88 {