# HG changeset patch
# User kaf24@xxxxxxxxxxxxxxxxxxxx
# Node ID f9b300fab36e2a7fef2160ca2e6ab0db1f1b3280
# Parent d48bc069122cad701be691ad456b5b3f1a0c479f
This should fix time stopped / going slow problems that
various users have been seeing.
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
diff -r d48bc069122c -r f9b300fab36e xen/arch/x86/time.c
--- a/xen/arch/x86/time.c Fri Oct 14 15:01:11 2005
+++ b/xen/arch/x86/time.c Fri Oct 14 17:27:25 2005
@@ -61,12 +61,23 @@
static struct cpu_time cpu_time[NR_CPUS];
-/* Protected by platform_timer_lock. */
+/*
+ * Protected by platform_timer_lock, which must be acquired with interrupts
+ * disabled because pit_overflow() is called from PIT ch0 interrupt context.
+ */
static s_time_t stime_platform_stamp;
static u64 platform_timer_stamp;
static struct time_scale platform_timer_scale;
static spinlock_t platform_timer_lock = SPIN_LOCK_UNLOCKED;
static u64 (*read_platform_count)(void);
+
+/*
+ * Folding 16-bit PIT into 64-bit software counter is a really critical
+ * operation! We therefore do it directly in PIT ch0 interrupt handler,
+ * based on this flag.
+ */
+static int using_pit;
+static void pit_overflow(void);
/*
* 32-bit division of integer dividend and integer divisor yielding
@@ -135,14 +146,16 @@
void timer_interrupt(int irq, void *dev_id, struct cpu_user_regs *regs)
{
+ ASSERT(local_irq_is_enabled());
+
if ( timer_ack )
{
extern spinlock_t i8259A_lock;
- spin_lock(&i8259A_lock);
+ spin_lock_irq(&i8259A_lock);
outb(0x0c, 0x20);
/* Ack the IRQ; AEOI will end it automatically. */
inb(0x20);
- spin_unlock(&i8259A_lock);
+ spin_unlock_irq(&i8259A_lock);
}
/* Update jiffies counter. */
@@ -151,6 +164,9 @@
/* Rough hack to allow accurate timers to sort-of-work with no APIC. */
if ( !cpu_has_apic )
raise_softirq(AC_TIMER_SOFTIRQ);
+
+ if ( using_pit )
+ pit_overflow();
}
static struct irqaction irq0 = { timer_interrupt, "timer", NULL};
@@ -280,7 +296,6 @@
/* Protected by platform_timer_lock. */
static u64 pit_counter64;
static u16 pit_stamp;
-static struct ac_timer pit_overflow_timer;
static u16 pit_read_counter(void)
{
@@ -292,17 +307,15 @@
return count;
}
-static void pit_overflow(void *unused)
+static void pit_overflow(void)
{
u16 counter;
- spin_lock(&platform_timer_lock);
+ spin_lock_irq(&platform_timer_lock);
counter = pit_read_counter();
pit_counter64 += (u16)(pit_stamp - counter);
pit_stamp = counter;
- spin_unlock(&platform_timer_lock);
-
- set_ac_timer(&pit_overflow_timer, NOW() + MILLISECS(20));
+ spin_unlock_irq(&platform_timer_lock);
}
static u64 read_pit_count(void)
@@ -314,12 +327,12 @@
{
read_platform_count = read_pit_count;
- init_ac_timer(&pit_overflow_timer, pit_overflow, NULL, 0);
- pit_overflow(NULL);
+ pit_overflow();
platform_timer_stamp = pit_counter64;
set_time_scale(&platform_timer_scale, CLOCK_TICK_RATE);
printk("Platform timer is %s PIT\n", freq_string(CLOCK_TICK_RATE));
+ using_pit = 1;
return 1;
}
@@ -337,11 +350,11 @@
{
u32 counter;
- spin_lock(&platform_timer_lock);
+ spin_lock_irq(&platform_timer_lock);
counter = hpet_read32(HPET_COUNTER);
hpet_counter64 += (u32)(counter - hpet_stamp);
hpet_stamp = counter;
- spin_unlock(&platform_timer_lock);
+ spin_unlock_irq(&platform_timer_lock);
set_ac_timer(&hpet_overflow_timer, NOW() + hpet_overflow_period);
}
@@ -455,11 +468,11 @@
{
u32 counter;
- spin_lock(&platform_timer_lock);
+ spin_lock_irq(&platform_timer_lock);
counter = *cyclone_timer;
cyclone_counter64 += (u32)(counter - cyclone_stamp);
cyclone_stamp = counter;
- spin_unlock(&platform_timer_lock);
+ spin_unlock_irq(&platform_timer_lock);
set_ac_timer(&cyclone_overflow_timer, NOW() + MILLISECS(20000));
}
@@ -526,10 +539,10 @@
u64 counter;
s_time_t stime;
- spin_lock(&platform_timer_lock);
+ spin_lock_irq(&platform_timer_lock);
counter = read_platform_count();
stime = __read_platform_stime(counter);
- spin_unlock(&platform_timer_lock);
+ spin_unlock_irq(&platform_timer_lock);
return stime;
}
@@ -539,12 +552,12 @@
u64 counter;
s_time_t stamp;
- spin_lock(&platform_timer_lock);
+ spin_lock_irq(&platform_timer_lock);
counter = read_platform_count();
stamp = __read_platform_stime(counter);
stime_platform_stamp = stamp;
platform_timer_stamp = counter;
- spin_unlock(&platform_timer_lock);
+ spin_unlock_irq(&platform_timer_lock);
}
static void init_platform_timer(void)
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|