[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] x86: PIT broadcast to fix local APIC timer stop issue for Deep C state
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1216028612 -3600 # Node ID 79517ed2a1081120ed4490f34453c6161dc4a38b # Parent 39c2cab9e765ece9e7958ba08852f2340e7d537b x86: PIT broadcast to fix local APIC timer stop issue for Deep C state Local APIC timer may stop at deep C state (C3/C4...) entry. Initial HPET broadcast working in legacy replacing mode, broke RTC intr, so was bypassed. This patch add the logic that use platform timer (PIT) to reenable local APIC timer at C state entry/exit. Currently, only keep PIT enabled with 100Hz freq. The next step is trying to dynamically enable/disable PIT while needed, and give it lower freq. Signed-off-by: Yu Ke <ke.yu@xxxxxxxxx> Signed-off-by: Tian Kevin <kevin.tian@xxxxxxxxx> Signed-off-by: Wei Gang <gang.wei@xxxxxxxxx> Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx> --- xen/arch/x86/acpi/cpu_idle.c | 23 +++++++++++++++++---- xen/arch/x86/setup.c | 2 - xen/arch/x86/time.c | 47 ++++++++++++++++++++++++++++++++++++++++++- xen/include/asm-x86/time.h | 4 +++ 4 files changed, 70 insertions(+), 6 deletions(-) diff -r 39c2cab9e765 -r 79517ed2a108 xen/arch/x86/acpi/cpu_idle.c --- a/xen/arch/x86/acpi/cpu_idle.c Mon Jul 14 10:12:07 2008 +0100 +++ b/xen/arch/x86/acpi/cpu_idle.c Mon Jul 14 10:43:32 2008 +0100 @@ -56,6 +56,9 @@ #define ACPI_PROCESSOR_MAX_C2_LATENCY 100 #define ACPI_PROCESSOR_MAX_C3_LATENCY 1000 +static void (*lapic_timer_off)(void); +static void (*lapic_timer_on)(void); + extern u32 pmtmr_ioport; extern void (*pm_idle) (void); @@ -437,7 +440,7 @@ static void acpi_processor_idle(void) /* preparing TSC stop */ cstate_save_tsc(); /* preparing APIC stop */ - hpet_broadcast_enter(); + lapic_timer_off(); /* Get start time (ticks) */ t1 = inl(pmtmr_ioport); @@ -446,8 +449,6 @@ static void acpi_processor_idle(void) /* Get end time (ticks) */ t2 = inl(pmtmr_ioport); - /* recovering APIC */ - hpet_broadcast_exit(); /* recovering TSC */ cstate_restore_tsc(); @@ -460,6 +461,8 @@ static void acpi_processor_idle(void) /* Re-enable interrupts */ local_irq_enable(); + /* recovering APIC */ + lapic_timer_on(); /* Compute time (ticks) that we were actually asleep */ sleep_ticks = ticks_elapsed(t1, t2); /* Do not account our idle-switching overhead: */ @@ -752,8 +755,20 @@ static int check_cx(struct acpi_processo if ( cx->type == ACPI_STATE_C3 ) { /* We must be able to use HPET in place of LAPIC timers. */ - if ( !hpet_broadcast_is_available() ) + if ( hpet_broadcast_is_available() ) + { + lapic_timer_off = hpet_broadcast_enter; + lapic_timer_on = hpet_broadcast_exit; + } + else if ( pit_broadcast_is_available() ) + { + lapic_timer_off = pit_broadcast_enter; + lapic_timer_on = pit_broadcast_exit; + } + else + { return -EINVAL; + } /* All the logic here assumes flags.bm_check is same across all CPUs */ if ( !bm_check_flag ) diff -r 39c2cab9e765 -r 79517ed2a108 xen/arch/x86/setup.c --- a/xen/arch/x86/setup.c Mon Jul 14 10:12:07 2008 +0100 +++ b/xen/arch/x86/setup.c Mon Jul 14 10:43:32 2008 +0100 @@ -96,7 +96,7 @@ boolean_param("noapic", skip_ioapic_setu /* **** Linux config option: propagated to domain0. */ /* xen_cpuidle: xen control cstate. */ -static int xen_cpuidle; +/*static*/ int xen_cpuidle; boolean_param("cpuidle", xen_cpuidle); int early_boot = 1; diff -r 39c2cab9e765 -r 79517ed2a108 xen/arch/x86/time.c --- a/xen/arch/x86/time.c Mon Jul 14 10:12:07 2008 +0100 +++ b/xen/arch/x86/time.c Mon Jul 14 10:43:32 2008 +0100 @@ -147,6 +147,32 @@ static inline u64 scale_delta(u64 delta, return product; } +/* + * cpu_mask that denotes the CPUs that needs timer interrupt coming in as + * IPIs in place of local APIC timers + */ +extern int xen_cpuidle; +static cpumask_t pit_broadcast_mask; + +static void smp_send_timer_broadcast_ipi(void) +{ + int cpu = smp_processor_id(); + cpumask_t mask; + + cpus_and(mask, cpu_online_map, pit_broadcast_mask); + + if ( cpu_isset(cpu, mask) ) + { + cpu_clear(cpu, mask); + raise_softirq(TIMER_SOFTIRQ); + } + + if ( !cpus_empty(mask) ) + { + cpumask_raise_softirq(mask, TIMER_SOFTIRQ); + } +} + static void timer_interrupt(int irq, void *dev_id, struct cpu_user_regs *regs) { ASSERT(local_irq_is_enabled()); @@ -160,6 +186,9 @@ static void timer_interrupt(int irq, voi /* Rough hack to allow accurate timers to sort-of-work with no APIC. */ if ( !cpu_has_apic ) raise_softirq(TIMER_SOFTIRQ); + + if ( xen_cpuidle ) + smp_send_timer_broadcast_ipi(); /* Emulate a 32-bit PIT counter. */ if ( using_pit ) @@ -1006,9 +1035,10 @@ void __init early_time_init(void) setup_irq(0, &irq0); } +/* keep pit enabled for pit_broadcast working while cpuidle enabled */ static int disable_pit_irq(void) { - if ( !using_pit && cpu_has_apic ) + if ( !using_pit && cpu_has_apic && !xen_cpuidle ) { /* Disable PIT CH0 timer interrupt. */ outb_p(0x30, PIT_MODE); @@ -1025,6 +1055,21 @@ static int disable_pit_irq(void) return 0; } __initcall(disable_pit_irq); + +void pit_broadcast_enter(void) +{ + cpu_set(smp_processor_id(), pit_broadcast_mask); +} + +void pit_broadcast_exit(void) +{ + cpu_clear(smp_processor_id(), pit_broadcast_mask); +} + +int pit_broadcast_is_available(void) +{ + return xen_cpuidle; +} void send_timer_event(struct vcpu *v) { diff -r 39c2cab9e765 -r 79517ed2a108 xen/include/asm-x86/time.h --- a/xen/include/asm-x86/time.h Mon Jul 14 10:12:07 2008 +0100 +++ b/xen/include/asm-x86/time.h Mon Jul 14 10:43:32 2008 +0100 @@ -34,4 +34,8 @@ struct tm; struct tm; struct tm wallclock_time(void); +void pit_broadcast_enter(void); +void pit_broadcast_exit(void); +int pit_broadcast_is_available(void); + #endif /* __X86_TIME_H__ */ _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |