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: Clean up interface to platform timer

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] x86: Clean up interface to platform timers to extract more common code.
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Thu, 14 Jun 2007 12:52:55 -0700
Delivery-date: Thu, 14 Jun 2007 15:24:13 -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 kfraser@xxxxxxxxxxxxxxxxxxxxx
# Date 1181571023 -3600
# Node ID bd94f75fe469a5593e49545824e656818f320d86
# Parent  ed254cf78f7ca758539ba3314932fbbd808807d2
x86: Clean up interface to platform timers to extract more common code.
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
 xen/arch/x86/time.c |  306 ++++++++++++++++++++--------------------------------
 1 files changed, 122 insertions(+), 184 deletions(-)

diff -r ed254cf78f7c -r bd94f75fe469 xen/arch/x86/time.c
--- a/xen/arch/x86/time.c       Mon Jun 11 14:56:50 2007 +0100
+++ b/xen/arch/x86/time.c       Mon Jun 11 15:10:23 2007 +0100
@@ -57,25 +57,29 @@ struct cpu_time {
     struct timer calibration_timer;
 };
 
+struct platform_timesource {
+    char *name;
+    u64 frequency;
+    u32 (*read_counter)(void);
+    int counter_bits;
+};
+
 static DEFINE_PER_CPU(struct cpu_time, cpu_time);
 
 /*
  * Protected by platform_timer_lock, which must be acquired with interrupts
- * disabled because pit_overflow() is called from PIT ch0 interrupt context.
+ * disabled because plt_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 DEFINE_SPINLOCK(platform_timer_lock);
-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);
+ * 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);
 
 /*
  * 32-bit division of integer dividend and integer divisor yielding
@@ -153,8 +157,8 @@ void timer_interrupt(int irq, void *dev_
     if ( !cpu_has_apic )
         raise_softirq(TIMER_SOFTIRQ);
 
-    if ( using_pit )
-        pit_overflow();
+    if ( --plt_overflow_jiffies == 0 )
+        plt_overflow();
 }
 
 static struct irqaction irq0 = { timer_interrupt, "timer", NULL};
@@ -281,76 +285,34 @@ static char *freq_string(u64 freq)
  * PLATFORM TIMER 1: PROGRAMMABLE INTERVAL TIMER (LEGACY PIT)
  */
 
-/* Protected by platform_timer_lock. */
-static u64 pit_counter64;
-static u16 pit_stamp;
-
-static u16 pit_read_counter(void)
+static u32 read_pit_count(void)
 {
     u16 count;
     ASSERT(spin_is_locked(&platform_timer_lock));
     outb(0x80, PIT_MODE);
     count  = inb(PIT_CH2);
     count |= inb(PIT_CH2) << 8;
-    return count;
-}
-
-static void pit_overflow(void)
-{
-    u16 counter;
-
-    spin_lock_irq(&platform_timer_lock);
-    counter = pit_read_counter();
-    pit_counter64 += (u16)(pit_stamp - counter);
-    pit_stamp = counter;
-    spin_unlock_irq(&platform_timer_lock);
-}
-
-static u64 read_pit_count(void)
-{
-    return pit_counter64 + (u16)(pit_stamp - pit_read_counter());
-}
-
-static void init_pit(void)
-{
-    read_platform_count = read_pit_count;
-
-    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 ~count;
+}
+
+static void init_pit(struct platform_timesource *pts)
+{
+    pts->name = "PIT";
+    pts->frequency = CLOCK_TICK_RATE;
+    pts->read_counter = read_pit_count;
+    pts->counter_bits = 16;
 }
 
 /************************************************************
  * PLATFORM TIMER 2: HIGH PRECISION EVENT TIMER (HPET)
  */
 
-/* Protected by platform_timer_lock. */
-static u64 hpet_counter64, hpet_overflow_period;
-static u32 hpet_stamp;
-static struct timer hpet_overflow_timer;
-
-static void hpet_overflow(void *unused)
-{
-    u32 counter;
-
-    spin_lock_irq(&platform_timer_lock);
-    counter = hpet_read32(HPET_COUNTER);
-    hpet_counter64 += (u32)(counter - hpet_stamp);
-    hpet_stamp = counter;
-    spin_unlock_irq(&platform_timer_lock);
-
-    set_timer(&hpet_overflow_timer, NOW() + hpet_overflow_period);
-}
-
-static u64 read_hpet_count(void)
-{
-    return hpet_counter64 + (u32)(hpet_read32(HPET_COUNTER) - hpet_stamp);
-}
-
-static int init_hpet(void)
+static u32 read_hpet_count(void)
+{
+    return hpet_read32(HPET_COUNTER);
+}
+
+static int init_hpet(struct platform_timesource *pts)
 {
     u64 hpet_rate;
     u32 hpet_id, hpet_period, cfg;
@@ -391,29 +353,13 @@ static int init_hpet(void)
     cfg |= HPET_CFG_ENABLE;
     hpet_write32(cfg, HPET_CFG);
 
-    read_platform_count = read_hpet_count;
-
     hpet_rate = 1000000000000000ULL; /* 10^15 */
     (void)do_div(hpet_rate, hpet_period);
-    set_time_scale(&platform_timer_scale, hpet_rate);
-
-    /* Trigger overflow avoidance roughly when counter increments 2^31. */
-    if ( (hpet_rate >> 31) != 0 )
-    {
-        hpet_overflow_period = MILLISECS(1000);
-        (void)do_div(hpet_overflow_period, (u32)(hpet_rate >> 31) + 1);
-    }
-    else
-    {
-        hpet_overflow_period = MILLISECS(1000) << 31;
-        (void)do_div(hpet_overflow_period, (u32)hpet_rate);
-    }
-
-    init_timer(&hpet_overflow_timer, hpet_overflow, NULL, 0);
-    hpet_overflow(NULL);
-    platform_timer_stamp = hpet_counter64;
-
-    printk("Platform timer is %s HPET\n", freq_string(hpet_rate));
+
+    pts->name = "HPET";
+    pts->frequency = hpet_rate;
+    pts->read_counter = read_hpet_count;
+    pts->counter_bits = 32;
 
     return 1;
 }
@@ -435,28 +381,12 @@ int use_cyclone;
 #define CYCLONE_MPCS_OFFSET 0x51A8
 #define CYCLONE_TIMER_FREQ  100000000
 
-/* Protected by platform_timer_lock. */
-static u64 cyclone_counter64;
-static u32 cyclone_stamp;
-static struct timer cyclone_overflow_timer;
-static volatile u32 *cyclone_timer; /* Cyclone MPMC0 register */
-
-static void cyclone_overflow(void *unused)
-{
-    u32 counter;
-
-    spin_lock_irq(&platform_timer_lock);
-    counter = *cyclone_timer;
-    cyclone_counter64 += (u32)(counter - cyclone_stamp);
-    cyclone_stamp = counter;
-    spin_unlock_irq(&platform_timer_lock);
-
-    set_timer(&cyclone_overflow_timer, NOW() + MILLISECS(20000));
-}
-
-static u64 read_cyclone_count(void)
-{
-    return cyclone_counter64 + (u32)(*cyclone_timer - cyclone_stamp);
+/* Cyclone MPMC0 register. */
+static volatile u32 *cyclone_timer;
+
+static u32 read_cyclone_count(void)
+{
+    return *cyclone_timer;
 }
 
 static volatile u32 *map_cyclone_reg(unsigned long regaddr)
@@ -467,7 +397,7 @@ static volatile u32 *map_cyclone_reg(uns
     return (volatile u32 *)(fix_to_virt(FIX_CYCLONE_TIMER) + offset);
 }
 
-static int init_cyclone(void)
+static int init_cyclone(struct platform_timesource *pts)
 {
     u32 base;
     
@@ -487,15 +417,10 @@ static int init_cyclone(void)
     *(map_cyclone_reg(base + CYCLONE_MPCS_OFFSET)) = 1;
     cyclone_timer = map_cyclone_reg(base + CYCLONE_MPMC_OFFSET);
 
-    read_platform_count = read_cyclone_count;
-
-    init_timer(&cyclone_overflow_timer, cyclone_overflow, NULL, 0);
-    cyclone_overflow(NULL);
-    platform_timer_stamp = cyclone_counter64;
-    set_time_scale(&platform_timer_scale, CYCLONE_TIMER_FREQ);
-
-    printk("Platform timer is %s IBM Cyclone\n",
-           freq_string(CYCLONE_TIMER_FREQ));
+    pts->name = "IBM Cyclone";
+    pts->frequency = CYCLONE_TIMER_FREQ;
+    pts->read_counter = read_cyclone_count;
+    pts->counter_bits = 32;
 
     return 1;
 }
@@ -506,50 +431,23 @@ static int init_cyclone(void)
 
 u32 pmtmr_ioport;
 
-/* Protected by platform_timer_lock. */
-static u64 pmtimer_counter64;
-static u32 pmtimer_stamp;
-static struct timer pmtimer_overflow_timer;
-
 /* ACPI PM timer ticks at 3.579545 MHz. */
 #define ACPI_PM_FREQUENCY 3579545
 
-/* Deltas are 24-bit unsigned values, as counter may be only 24 bits wide. */
-#define pmtimer_delta(c) ((u32)(((c) - pmtimer_stamp) & ((1U<<24)-1)))
-
-static void pmtimer_overflow(void *unused)
-{
-    u32 counter;
-
-    spin_lock_irq(&platform_timer_lock);
-    counter = inl(pmtmr_ioport);
-    pmtimer_counter64 += pmtimer_delta(counter);
-    pmtimer_stamp = counter;
-    spin_unlock_irq(&platform_timer_lock);
-
-    /* Trigger overflow avoidance roughly when counter increments 2^23. */
-    set_timer(&pmtimer_overflow_timer, NOW() + MILLISECS(2000));
-}
-
-static u64 read_pmtimer_count(void)
-{
-    return pmtimer_counter64 + pmtimer_delta(inl(pmtmr_ioport));
-}
-
-static int init_pmtimer(void)
+static u32 read_pmtimer_count(void)
+{
+    return inl(pmtmr_ioport);
+}
+
+static int init_pmtimer(struct platform_timesource *pts)
 {
     if ( pmtmr_ioport == 0 )
         return 0;
 
-    read_platform_count = read_pmtimer_count;
-
-    init_timer(&pmtimer_overflow_timer, pmtimer_overflow, NULL, 0);
-    pmtimer_overflow(NULL);
-    platform_timer_stamp = pmtimer_counter64;
-    set_time_scale(&platform_timer_scale, ACPI_PM_FREQUENCY);
-
-    printk("Platform timer is %s ACPI PM Timer\n",
-           freq_string(ACPI_PM_FREQUENCY));
+    pts->name = "ACPI PM Timer";
+    pts->frequency = ACPI_PM_FREQUENCY;
+    pts->read_counter = read_pmtimer_count;
+    pts->counter_bits = 24;
 
     return 1;
 }
@@ -558,21 +456,43 @@ static int init_pmtimer(void)
  * GENERIC PLATFORM TIMER INFRASTRUCTURE
  */
 
+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 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)
+{
+    u32 count;
+    unsigned long flags;
+
+    spin_lock_irqsave(&platform_timer_lock, flags);
+    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);
+}
+
 static s_time_t __read_platform_stime(u64 platform_time)
 {
     u64 diff = platform_time - platform_timer_stamp;
     ASSERT(spin_is_locked(&platform_timer_lock));
-    return (stime_platform_stamp + scale_delta(diff, &platform_timer_scale));
+    return (stime_platform_stamp + scale_delta(diff, &plt_scale));
 }
 
 static s_time_t read_platform_stime(void)
 {
-    u64 counter;
+    u64 count;
     s_time_t stime;
 
     spin_lock_irq(&platform_timer_lock);
-    counter = read_platform_count();
-    stime   = __read_platform_stime(counter);
+    count = plt_count64 + ((plt_src.read_counter() - plt_count) & plt_mask);
+    stime = __read_platform_stime(count);
     spin_unlock_irq(&platform_timer_lock);
 
     return stime;
@@ -580,42 +500,60 @@ static s_time_t read_platform_stime(void
 
 static void platform_time_calibration(void)
 {
-    u64 counter;
+    u64 count;
     s_time_t stamp;
 
     spin_lock_irq(&platform_timer_lock);
-    counter = read_platform_count();
-    stamp   = __read_platform_stime(counter);
+    count = plt_count64 + ((plt_src.read_counter() - plt_count) & plt_mask);
+    stamp = __read_platform_stime(count);
     stime_platform_stamp = stamp;
-    platform_timer_stamp = counter;
+    platform_timer_stamp = count;
     spin_unlock_irq(&platform_timer_lock);
 }
 
 static void init_platform_timer(void)
 {
+    struct platform_timesource *pts = &plt_src;
+    u64 overflow_period;
+    int rc = -1;
+
     if ( opt_clocksource[0] != '\0' )
     {
-        int rc = -1;
-
         if ( !strcmp(opt_clocksource, "pit") )
-            rc = (init_pit(), 1);
+            rc = (init_pit(pts), 1);
         else if ( !strcmp(opt_clocksource, "hpet") )
-            rc = init_hpet();
+            rc = init_hpet(pts);
         else if ( !strcmp(opt_clocksource, "cyclone") )
-            rc = init_cyclone();
+            rc = init_cyclone(pts);
         else if ( !strcmp(opt_clocksource, "acpi") )
-            rc = init_pmtimer();
-
-        if ( rc == 1 )
-            return;
-
-        printk("WARNING: %s clocksource '%s'.\n",
-               (rc == 0) ? "Could not initialise" : "Unrecognised",
-               opt_clocksource);
-    }
-
-    if ( !init_cyclone() && !init_hpet() && !init_pmtimer() )
-        init_pit();
+            rc = init_pmtimer(pts);
+
+        if ( rc <= 0 )
+            printk("WARNING: %s clocksource '%s'.\n",
+                   (rc == 0) ? "Could not initialise" : "Unrecognised",
+                   opt_clocksource);
+    }
+
+    if ( (rc <= 0) &&
+         !init_cyclone(pts) &&
+         !init_hpet(pts) &&
+         !init_pmtimer(pts) )
+        init_pit(pts);
+
+    plt_mask = (u32)~0u >> (32 - pts->counter_bits);
+
+    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;
+
+    printk("Platform timer is %s %s\n",
+           freq_string(pts->frequency), pts->name);
 }
 
 

_______________________________________________
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: Clean up interface to platform timers to extract more common code., Xen patchbot-unstable <=