Wei, Gang
2010-Apr-01 12:38 UTC
[Xen-devel] [PATCH]cpuidle: mwait on softirq_pending & remove wakeup ipis
cpuidle: mwait on softirq_pending & remove wakeup ipis For cpu which enter deep C state via monitor/mwait, wakeup can be done by writing to the monitored memory. So once monitor softirq_pending, we can remove the redundant ipis. Signed-off-by: Yu Ke <ke.yu@intel.com> Signed-off-by: Wei Gang <gang.wei@intel.com> diff -r 132ac04cbdba xen/arch/x86/acpi/cpu_idle.c --- a/xen/arch/x86/acpi/cpu_idle.c Tue Mar 09 18:18:19 2010 +0000 +++ b/xen/arch/x86/acpi/cpu_idle.c Thu Mar 11 14:07:54 2010 +0800 @@ -69,6 +69,14 @@ boolean_param("lapic_timer_c2_ok", local static struct acpi_processor_power *__read_mostly processor_powers[NR_CPUS]; +static char* acpi_cstate_method_name[] +{ + "NONE", + "SYSIO", + "FFH", + "HALT" +}; + static void print_acpi_power(uint32_t cpu, struct acpi_processor_power *power) { uint32_t i, idle_usage = 0; @@ -92,6 +100,7 @@ static void print_acpi_power(uint32_t cp printk("type[C%d] ", power->states[i].type); printk("latency[%03d] ", power->states[i].latency); printk("usage[%08d] ", power->states[i].usage); + printk("method[%5s] ", acpi_cstate_method_name[power->states[i].entry_method]); printk("duration[%"PRId64"]\n", res); } printk(" C0:\tusage[%08d] duration[%"PRId64"]\n", @@ -140,11 +149,43 @@ static void acpi_safe_halt(void) #define MWAIT_ECX_INTERRUPT_BREAK (0x1) +/* + * The bit is set iff cpu use monitor/mwait to enter C state + * with this flag set, CPU can be waken up from C state + * by writing to specific memory address, instead of sending IPI + */ +static cpumask_t cpuidle_mwait_flags; + +void cpuidle_wakeup_mwait(cpumask_t *mask) +{ + cpumask_t target; + int cpu; + + cpus_and(target, *mask, cpuidle_mwait_flags); + + /* cpu is ''mwait''ing at softirq_pending, + writing to it will wake up CPU */ + for_each_cpu_mask(cpu, target) + set_bit(TIMER_SOFTIRQ, &softirq_pending(cpu)); + + cpus_andnot(*mask, *mask, cpuidle_mwait_flags); +} + static void mwait_idle_with_hints(unsigned long eax, unsigned long ecx) { - __monitor((void *)current, 0, 0); + int cpu = smp_processor_id(); + + __monitor((void *)&softirq_pending(cpu), 0, 0); + smp_mb(); - __mwait(eax, ecx); + if (!softirq_pending(cpu)) + { + cpu_set(cpu, cpuidle_mwait_flags); + + __mwait(eax, ecx); + + cpu_clear(cpu, cpuidle_mwait_flags); + } } static void acpi_processor_ffh_cstate_enter(struct acpi_processor_cx *cx) diff -r 132ac04cbdba xen/arch/x86/hpet.c --- a/xen/arch/x86/hpet.c Tue Mar 09 18:18:19 2010 +0000 +++ b/xen/arch/x86/hpet.c Thu Mar 11 14:07:54 2010 +0800 @@ -165,6 +165,8 @@ static int evt_do_broadcast(cpumask_t ma raise_softirq(TIMER_SOFTIRQ); ret = 1; } + + cpuidle_wakeup_mwait(&mask); if ( !cpus_empty(mask) ) { diff -r 132ac04cbdba xen/include/xen/cpuidle.h --- a/xen/include/xen/cpuidle.h Tue Mar 09 18:18:19 2010 +0000 +++ b/xen/include/xen/cpuidle.h Thu Mar 11 14:07:54 2010 +0800 @@ -86,6 +86,8 @@ extern struct cpuidle_governor *cpuidle_ extern struct cpuidle_governor *cpuidle_current_governor; void cpuidle_disable_deep_cstate(void); +extern void cpuidle_wakeup_mwait(cpumask_t *mask); + #define CPUIDLE_DRIVER_STATE_START 1 #endif /* _XEN_CPUIDLE_H */ _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel