WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] [xen-unstable] x86: Conditionally disable PIT 100HZ time

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] x86: Conditionally disable PIT 100HZ timer interrupt
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Thu, 10 Apr 2008 04:10:15 -0700
Delivery-date: Thu, 10 Apr 2008 04:10:16 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1207822285 -3600
# Node ID 8d750b7acfa363dead3cefab03d79918735c18ac
# Parent  5b7a3e040683ba25766879e89c0c6b87b198f5e2
x86: Conditionally disable PIT 100HZ timer interrupt

100HZ PIT timer interrupt set a 10ms upper limit for C state
residency, which makes Xen not power friendly. This patch disable PIT
timer interrupt in the conditions:
 - CPU has APIC support, and
 - PIT is not used as platform time source

Signed-off-by: Yu Ke <ke.yu@xxxxxxxxx>
Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx>
---
 xen/arch/x86/time.c |  151 ++++++++++++++++++++++++++++++++--------------------
 1 files changed, 93 insertions(+), 58 deletions(-)

diff -r 5b7a3e040683 -r 8d750b7acfa3 xen/arch/x86/time.c
--- a/xen/arch/x86/time.c       Thu Apr 10 10:12:04 2008 +0100
+++ b/xen/arch/x86/time.c       Thu Apr 10 11:11:25 2008 +0100
@@ -67,19 +67,16 @@ static DEFINE_PER_CPU(struct cpu_time, c
 static DEFINE_PER_CPU(struct cpu_time, cpu_time);
 
 /*
- * Protected by platform_timer_lock, which must be acquired with interrupts
- * disabled because plt_overflow() is called from PIT ch0 interrupt context.
- */
-static s_time_t stime_platform_stamp;
-static u64 platform_timer_stamp;
-static DEFINE_SPINLOCK(platform_timer_lock);
-
-/*
- * Folding platform timer into 64-bit software counter is a really critical
- * operation! We therefore do it directly in PIT ch0 interrupt handler.
- */
-static u32 plt_overflow_jiffies;
-static void plt_overflow(void);
+ * We simulate a 32-bit platform timer from the 16-bit PIT ch2 counter.
+ * Otherwise overflow happens too quickly (~50ms) for us to guarantee that
+ * softirq handling will happen in time.
+ * 
+ * The pit_lock protects the 16- and 32-bit stamp fields as well as the 
+ */
+static DEFINE_SPINLOCK(pit_lock);
+static u16 pit_stamp16;
+static u32 pit_stamp32;
+static int using_pit;
 
 /*
  * 32-bit division of integer dividend and integer divisor yielding
@@ -146,21 +143,36 @@ static inline u64 scale_delta(u64 delta,
     return product;
 }
 
-void timer_interrupt(int irq, void *dev_id, struct cpu_user_regs *regs)
+static void timer_interrupt(int irq, void *dev_id, struct cpu_user_regs *regs)
 {
     ASSERT(local_irq_is_enabled());
 
+    /* Only for start-of-day interruopt tests in io_apic.c. */
     (*(volatile unsigned long *)&pit0_ticks)++;
 
     /* Rough hack to allow accurate timers to sort-of-work with no APIC. */
     if ( !cpu_has_apic )
         raise_softirq(TIMER_SOFTIRQ);
 
-    if ( --plt_overflow_jiffies == 0 )
-        plt_overflow();
-}
-
-static struct irqaction irq0 = { timer_interrupt, "timer", NULL};
+    /* Emulate a 32-bit PIT counter. */
+    if ( using_pit )
+    {
+        u16 count;
+
+        spin_lock_irq(&pit_lock);
+
+        outb(0x80, PIT_MODE);
+        count  = inb(PIT_CH2);
+        count |= inb(PIT_CH2) << 8;
+
+        pit_stamp32 += (u16)(pit_stamp16 - count);
+        pit_stamp16 = count;
+
+        spin_unlock_irq(&pit_lock);
+    }
+}
+
+static struct irqaction irq0 = { timer_interrupt, "timer", NULL };
 
 /* ------ Calibrate the TSC ------- 
  * Return processor ticks per second / CALIBRATE_FRAC.
@@ -294,12 +306,21 @@ static char *freq_string(u64 freq)
 
 static u32 read_pit_count(void)
 {
-    u16 count;
-    ASSERT(spin_is_locked(&platform_timer_lock));
+    u16 count16;
+    u32 count32;
+    unsigned long flags;
+
+    spin_lock_irqsave(&pit_lock, flags);
+
     outb(0x80, PIT_MODE);
-    count  = inb(PIT_CH2);
-    count |= inb(PIT_CH2) << 8;
-    return ~count;
+    count16  = inb(PIT_CH2);
+    count16 |= inb(PIT_CH2) << 8;
+
+    count32 = pit_stamp32 + (u16)(pit_stamp16 - count16);
+
+    spin_unlock_irqrestore(&pit_lock, flags);
+
+    return count32;
 }
 
 static void init_pit(struct platform_timesource *pts)
@@ -307,7 +328,8 @@ static void init_pit(struct platform_tim
     pts->name = "PIT";
     pts->frequency = CLOCK_TICK_RATE;
     pts->read_counter = read_pit_count;
-    pts->counter_bits = 16;
+    pts->counter_bits = 32;
+    using_pit = 1;
 }
 
 /************************************************************
@@ -465,24 +487,28 @@ static int init_pmtimer(struct platform_
 
 static struct platform_timesource plt_src; /* details of chosen timesource  */
 static u32 plt_mask;             /* hardware-width mask                     */
-static u32 plt_overflow_period;  /* jiffies between calls to plt_overflow() */
+static u64 plt_overflow_period;  /* ns between calls to plt_overflow()      */
 static struct time_scale plt_scale; /* scale: platform counter -> nanosecs  */
 
 /* Protected by platform_timer_lock. */
-static u64 plt_count64;          /* 64-bit platform counter stamp           */
-static u32 plt_count;            /* hardware-width platform counter stamp   */
-
-static void plt_overflow(void)
+static DEFINE_SPINLOCK(platform_timer_lock);
+static s_time_t stime_platform_stamp; /* System time at below platform time */
+static u64 platform_timer_stamp;      /* Platform time at above system time */
+static u64 plt_stamp64;          /* 64-bit platform counter stamp           */
+static u32 plt_stamp;            /* hardware-width platform counter stamp   */
+static struct timer plt_overflow_timer;
+
+static void plt_overflow(void *unused)
 {
     u32 count;
-    unsigned long flags;
-
-    spin_lock_irqsave(&platform_timer_lock, flags);
+
+    spin_lock(&platform_timer_lock);
     count = plt_src.read_counter();
-    plt_count64 += (count - plt_count) & plt_mask;
-    plt_count = count;
-    plt_overflow_jiffies = plt_overflow_period;
-    spin_unlock_irqrestore(&platform_timer_lock, flags);
+    plt_stamp64 += (count - plt_stamp) & plt_mask;
+    plt_stamp = count;
+    spin_unlock(&platform_timer_lock);
+
+    set_timer(&plt_overflow_timer, NOW() + plt_overflow_period);
 }
 
 static s_time_t __read_platform_stime(u64 platform_time)
@@ -496,12 +522,11 @@ static s_time_t read_platform_stime(void
 {
     u64 count;
     s_time_t stime;
-    unsigned long flags;
-
-    spin_lock_irqsave(&platform_timer_lock, flags);
-    count = plt_count64 + ((plt_src.read_counter() - plt_count) & plt_mask);
+
+    spin_lock(&platform_timer_lock);
+    count = plt_stamp64 + ((plt_src.read_counter() - plt_stamp) & plt_mask);
     stime = __read_platform_stime(count);
-    spin_unlock_irqrestore(&platform_timer_lock, flags);
+    spin_unlock(&platform_timer_lock);
 
     return stime;
 }
@@ -510,27 +535,25 @@ static void platform_time_calibration(vo
 {
     u64 count;
     s_time_t stamp;
-    unsigned long flags;
-
-    spin_lock_irqsave(&platform_timer_lock, flags);
-    count = plt_count64 + ((plt_src.read_counter() - plt_count) & plt_mask);
+
+    spin_lock(&platform_timer_lock);
+    count = plt_stamp64 + ((plt_src.read_counter() - plt_stamp) & plt_mask);
     stamp = __read_platform_stime(count);
     stime_platform_stamp = stamp;
     platform_timer_stamp = count;
-    spin_unlock_irqrestore(&platform_timer_lock, flags);
+    spin_unlock(&platform_timer_lock);
 }
 
 static void resume_platform_timer(void)
 {
     /* No change in platform_stime across suspend/resume. */
-    platform_timer_stamp = plt_count64;
-    plt_count = plt_src.read_counter();
+    platform_timer_stamp = plt_stamp64;
+    plt_stamp = plt_src.read_counter();
 }
 
 static void init_platform_timer(void)
 {
     struct platform_timesource *pts = &plt_src;
-    u64 overflow_period;
     int rc = -1;
 
     if ( opt_clocksource[0] != '\0' )
@@ -560,13 +583,12 @@ static void init_platform_timer(void)
 
     set_time_scale(&plt_scale, pts->frequency);
 
-    overflow_period = scale_delta(1ull << (pts->counter_bits-1), &plt_scale);
-    do_div(overflow_period, MILLISECS(1000/HZ));
-    plt_overflow_period = overflow_period;
-    plt_overflow();
-    printk("Platform timer overflows in %d jiffies.\n", plt_overflow_period);
-
-    platform_timer_stamp = plt_count64;
+    plt_overflow_period = scale_delta(
+        1ull << (pts->counter_bits-1), &plt_scale);
+    init_timer(&plt_overflow_timer, plt_overflow, NULL, 0);
+    plt_overflow(NULL);
+
+    platform_timer_stamp = plt_stamp64;
 
     printk("Platform timer is %s %s\n",
            freq_string(pts->frequency), pts->name);
@@ -968,6 +990,19 @@ void __init early_time_init(void)
     setup_irq(0, &irq0);
 }
 
+static int __init late_time_init(void)
+{
+    if ( !using_pit && cpu_has_apic )
+    {
+        /* Disable PIT CH0 timer interrupt. */
+        outb_p(0x30, PIT_MODE);
+        outb_p(0, PIT_CH0);
+        outb_p(0, PIT_CH0);
+    }
+    return 0;
+}
+__initcall(late_time_init);
+
 void send_timer_event(struct vcpu *v)
 {
     send_guest_vcpu_virq(v, VIRQ_TIMER);
@@ -1018,7 +1053,7 @@ int dom0_pit_access(struct ioreq *ioreq)
 int dom0_pit_access(struct ioreq *ioreq)
 {
     /* Is Xen using Channel 2? Then disallow direct dom0 access. */
-    if ( plt_src.read_counter == read_pit_count )
+    if ( using_pit )
         return 0;
 
     switch ( ioreq->addr )

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-unstable] x86: Conditionally disable PIT 100HZ timer interrupt, Xen patchbot-unstable <=