# 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
|