[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] x86: Clean up interface to platform timers to extract more common code.



# 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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.