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@xxxxxxxxx>
Signed-off-by: Wei Gang <gang.wei@xxxxxxxxx>
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 */
cpuidle_mwait_fix_v2.patch
Description: cpuidle_mwait_fix_v2.patch
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|