[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] x86: Conditionally disable PIT 100HZ timer interrupt
# 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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |