ia64/xen-unstable
changeset 7390:f9b300fab36e
This should fix time stopped / going slow problems that
various users have been seeing.
Signed-off-by: Keir Fraser <keir@xensource.com>
various users have been seeing.
Signed-off-by: Keir Fraser <keir@xensource.com>
author | kaf24@firebug.cl.cam.ac.uk |
---|---|
date | Fri Oct 14 18:27:25 2005 +0100 (2005-10-14) |
parents | d48bc069122c |
children | 06ce728dcede |
files | xen/arch/x86/time.c |
line diff
1.1 --- a/xen/arch/x86/time.c Fri Oct 14 16:01:11 2005 +0100 1.2 +++ b/xen/arch/x86/time.c Fri Oct 14 18:27:25 2005 +0100 1.3 @@ -61,7 +61,10 @@ struct cpu_time { 1.4 1.5 static struct cpu_time cpu_time[NR_CPUS]; 1.6 1.7 -/* Protected by platform_timer_lock. */ 1.8 +/* 1.9 + * Protected by platform_timer_lock, which must be acquired with interrupts 1.10 + * disabled because pit_overflow() is called from PIT ch0 interrupt context. 1.11 + */ 1.12 static s_time_t stime_platform_stamp; 1.13 static u64 platform_timer_stamp; 1.14 static struct time_scale platform_timer_scale; 1.15 @@ -69,6 +72,14 @@ static spinlock_t platform_timer_lock = 1.16 static u64 (*read_platform_count)(void); 1.17 1.18 /* 1.19 + * Folding 16-bit PIT into 64-bit software counter is a really critical 1.20 + * operation! We therefore do it directly in PIT ch0 interrupt handler, 1.21 + * based on this flag. 1.22 + */ 1.23 +static int using_pit; 1.24 +static void pit_overflow(void); 1.25 + 1.26 +/* 1.27 * 32-bit division of integer dividend and integer divisor yielding 1.28 * 32-bit fractional quotient. 1.29 */ 1.30 @@ -135,14 +146,16 @@ static inline u64 scale_delta(u64 delta, 1.31 1.32 void timer_interrupt(int irq, void *dev_id, struct cpu_user_regs *regs) 1.33 { 1.34 + ASSERT(local_irq_is_enabled()); 1.35 + 1.36 if ( timer_ack ) 1.37 { 1.38 extern spinlock_t i8259A_lock; 1.39 - spin_lock(&i8259A_lock); 1.40 + spin_lock_irq(&i8259A_lock); 1.41 outb(0x0c, 0x20); 1.42 /* Ack the IRQ; AEOI will end it automatically. */ 1.43 inb(0x20); 1.44 - spin_unlock(&i8259A_lock); 1.45 + spin_unlock_irq(&i8259A_lock); 1.46 } 1.47 1.48 /* Update jiffies counter. */ 1.49 @@ -151,6 +164,9 @@ void timer_interrupt(int irq, void *dev_ 1.50 /* Rough hack to allow accurate timers to sort-of-work with no APIC. */ 1.51 if ( !cpu_has_apic ) 1.52 raise_softirq(AC_TIMER_SOFTIRQ); 1.53 + 1.54 + if ( using_pit ) 1.55 + pit_overflow(); 1.56 } 1.57 1.58 static struct irqaction irq0 = { timer_interrupt, "timer", NULL}; 1.59 @@ -280,7 +296,6 @@ static char *freq_string(u64 freq) 1.60 /* Protected by platform_timer_lock. */ 1.61 static u64 pit_counter64; 1.62 static u16 pit_stamp; 1.63 -static struct ac_timer pit_overflow_timer; 1.64 1.65 static u16 pit_read_counter(void) 1.66 { 1.67 @@ -292,17 +307,15 @@ static u16 pit_read_counter(void) 1.68 return count; 1.69 } 1.70 1.71 -static void pit_overflow(void *unused) 1.72 +static void pit_overflow(void) 1.73 { 1.74 u16 counter; 1.75 1.76 - spin_lock(&platform_timer_lock); 1.77 + spin_lock_irq(&platform_timer_lock); 1.78 counter = pit_read_counter(); 1.79 pit_counter64 += (u16)(pit_stamp - counter); 1.80 pit_stamp = counter; 1.81 - spin_unlock(&platform_timer_lock); 1.82 - 1.83 - set_ac_timer(&pit_overflow_timer, NOW() + MILLISECS(20)); 1.84 + spin_unlock_irq(&platform_timer_lock); 1.85 } 1.86 1.87 static u64 read_pit_count(void) 1.88 @@ -314,12 +327,12 @@ static int init_pit(void) 1.89 { 1.90 read_platform_count = read_pit_count; 1.91 1.92 - init_ac_timer(&pit_overflow_timer, pit_overflow, NULL, 0); 1.93 - pit_overflow(NULL); 1.94 + pit_overflow(); 1.95 platform_timer_stamp = pit_counter64; 1.96 set_time_scale(&platform_timer_scale, CLOCK_TICK_RATE); 1.97 1.98 printk("Platform timer is %s PIT\n", freq_string(CLOCK_TICK_RATE)); 1.99 + using_pit = 1; 1.100 1.101 return 1; 1.102 } 1.103 @@ -337,11 +350,11 @@ static void hpet_overflow(void *unused) 1.104 { 1.105 u32 counter; 1.106 1.107 - spin_lock(&platform_timer_lock); 1.108 + spin_lock_irq(&platform_timer_lock); 1.109 counter = hpet_read32(HPET_COUNTER); 1.110 hpet_counter64 += (u32)(counter - hpet_stamp); 1.111 hpet_stamp = counter; 1.112 - spin_unlock(&platform_timer_lock); 1.113 + spin_unlock_irq(&platform_timer_lock); 1.114 1.115 set_ac_timer(&hpet_overflow_timer, NOW() + hpet_overflow_period); 1.116 } 1.117 @@ -455,11 +468,11 @@ static void cyclone_overflow(void *unuse 1.118 { 1.119 u32 counter; 1.120 1.121 - spin_lock(&platform_timer_lock); 1.122 + spin_lock_irq(&platform_timer_lock); 1.123 counter = *cyclone_timer; 1.124 cyclone_counter64 += (u32)(counter - cyclone_stamp); 1.125 cyclone_stamp = counter; 1.126 - spin_unlock(&platform_timer_lock); 1.127 + spin_unlock_irq(&platform_timer_lock); 1.128 1.129 set_ac_timer(&cyclone_overflow_timer, NOW() + MILLISECS(20000)); 1.130 } 1.131 @@ -526,10 +539,10 @@ static s_time_t read_platform_stime(void 1.132 u64 counter; 1.133 s_time_t stime; 1.134 1.135 - spin_lock(&platform_timer_lock); 1.136 + spin_lock_irq(&platform_timer_lock); 1.137 counter = read_platform_count(); 1.138 stime = __read_platform_stime(counter); 1.139 - spin_unlock(&platform_timer_lock); 1.140 + spin_unlock_irq(&platform_timer_lock); 1.141 1.142 return stime; 1.143 } 1.144 @@ -539,12 +552,12 @@ static void platform_time_calibration(vo 1.145 u64 counter; 1.146 s_time_t stamp; 1.147 1.148 - spin_lock(&platform_timer_lock); 1.149 + spin_lock_irq(&platform_timer_lock); 1.150 counter = read_platform_count(); 1.151 stamp = __read_platform_stime(counter); 1.152 stime_platform_stamp = stamp; 1.153 platform_timer_stamp = counter; 1.154 - spin_unlock(&platform_timer_lock); 1.155 + spin_unlock_irq(&platform_timer_lock); 1.156 } 1.157 1.158 static void init_platform_timer(void)