]> xenbits.xensource.com Git - xen.git/commitdiff
CPUIDLE: re-implement mwait wakeup process
authorKeir Fraser <keir.fraser@citrix.com>
Tue, 4 May 2010 11:48:28 +0000 (12:48 +0100)
committerKeir Fraser <keir.fraser@citrix.com>
Tue, 4 May 2010 11:48:28 +0000 (12:48 +0100)
It MWAITs on a completely new flag field, avoiding the IPI-avoidance
semantics of softirq_pending. It also does wakeup-waiting checks on
timer_deadline_start, that being the field that initiates wakeup via
the MONITORed memory region.

Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
Signed-off-by: Wei Gang <gang.wei@intel.com>
xen/arch/x86/acpi/cpu_idle.c
xen/include/asm-x86/hardirq.h
xen/include/xen/irq_cpustat.h

index 304d424532a57d66377b811d7a611b637215305e..3b52c5469bd85ee079b384ee202dee0dd78aa426 100644 (file)
@@ -153,40 +153,45 @@ static void acpi_safe_halt(void)
 /*
  * 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
+ * by writing to specific memory address, instead of sending an IPI.
  */
 static cpumask_t cpuidle_mwait_flags;
 
 void cpuidle_wakeup_mwait(cpumask_t *mask)
 {
     cpumask_t target;
-    int cpu;
+    unsigned int cpu;
 
     cpus_and(target, *mask, cpuidle_mwait_flags);
 
-    /* cpu is 'mwait'ing at softirq_pending,
-       writing to it will wake up CPU */
+    /* CPU is MWAITing on the cpuidle_mwait_wakeup flag. */
     for_each_cpu_mask(cpu, target)
-        set_bit(TIMER_SOFTIRQ, &softirq_pending(cpu));
+        mwait_wakeup(cpu) = 0;
 
-    cpus_andnot(*mask, *mask, cpuidle_mwait_flags);
+    cpus_andnot(*mask, *mask, target);
 }
 
 static void mwait_idle_with_hints(unsigned long eax, unsigned long ecx)
 {
-    int cpu = smp_processor_id();
-
-    __monitor((void *)&softirq_pending(cpu), 0, 0);
+    unsigned int cpu = smp_processor_id();
+    s_time_t expires = per_cpu(timer_deadline_start, cpu);
 
+    __monitor((void *)&mwait_wakeup(cpu), 0, 0);
     smp_mb();
-    if (!softirq_pending(cpu))
+
+    /*
+     * Timer deadline passing is the event on which we will be woken via
+     * cpuidle_mwait_wakeup. So check it now that the location is armed.
+     */
+    if ( expires > NOW() || expires == 0 )
     {
         cpu_set(cpu, cpuidle_mwait_flags);
-
         __mwait(eax, ecx);
-
         cpu_clear(cpu, cpuidle_mwait_flags);
     }
+
+    if ( expires <= NOW() && expires > 0 )
+        raise_softirq(TIMER_SOFTIRQ);
 }
 
 static void acpi_processor_ffh_cstate_enter(struct acpi_processor_cx *cx)
index c426fdea07b70fd41c2e59220848b00f8976f90d..5b9d18b8754565083d253806167bc4309fb75777 100644 (file)
@@ -8,6 +8,7 @@ typedef struct {
        unsigned long __softirq_pending;
        unsigned int __local_irq_count;
        unsigned int __nmi_count;
+       bool_t __mwait_wakeup;
 } __cacheline_aligned irq_cpustat_t;
 
 #include <xen/irq_cpustat.h>   /* Standard mappings for irq_cpustat_t above */
index 6465c8a0fee0aa198639e59f265304bf6d210a36..94957996bb517bf17afe269fa1ec0f8c1b311cb8 100644 (file)
@@ -26,5 +26,6 @@ extern irq_cpustat_t irq_stat[];
 #define softirq_pending(cpu)   __IRQ_STAT((cpu), __softirq_pending)
 #define local_irq_count(cpu)   __IRQ_STAT((cpu), __local_irq_count)
 #define nmi_count(cpu)         __IRQ_STAT((cpu), __nmi_count)
+#define mwait_wakeup(cpu)      __IRQ_STAT((cpu), __mwait_wakeup)
 
 #endif /* __irq_cpustat_h */