[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH 12/12] SMP support to Xen PM



Utilize cpu hotplug infrastructure to pull down all other
cpus except cpu0, before starting suspend sequence. One
trick point is, cpu0 is a bit special and we'd better do
suspend on it. However vcpu0/dom0 is the one to trigger
power event which however may not bind to cpu0. So a new
softirq is introduced to switch flow to idle vcpu on cpu0
if such case happens.

Signed-off-by Kevin Tian <kevin.tian@xxxxxxxxx>

diff -r 308c4ef593e9 xen/arch/x86/acpi/power.c
--- a/xen/arch/x86/acpi/power.c Wed Feb 14 11:13:42 2007 +0800
+++ b/xen/arch/x86/acpi/power.c Wed Feb 14 14:59:23 2007 +0800
@@ -23,6 +23,7 @@
 #include <xen/sched.h>
 #include <xen/domain.h>
 #include <xen/console.h>
+#include <xen/softirq.h>
 
 u8 sleep_states[ACPI_S_STATE_COUNT];
 DEFINE_SPINLOCK(pm_lock);
@@ -75,26 +76,48 @@ static void device_power_up(void)
     console_resume();
 }
 
-/* Main interface to do xen specific suspend/resume */
-int enter_state(u32 state)
+static void freeze_domains(void)
 {
     struct domain *d;
-    unsigned long flags;
-    int error;
-
-    if (state <= ACPI_STATE_S0 || state > ACPI_S_STATES_MAX)
-        return -EINVAL;
-
-    if (!spin_trylock(&pm_lock))
-        return -EBUSY;
-    
+
     for_each_domain(d)
        if (d->domain_id != 0) {
            domain_pause(d);
            arch_domain_suspend(d);
     }
-
+}
+
+static void thaw_domains(void)
+{
+    struct domain *d;
+
+    for_each_domain(d)
+       if (d->domain_id != 0)
+           domain_unpause(d);
+}
+
+/* Main interface to do xen specific suspend/resume */
+int enter_state(u32 state)
+{
+    unsigned long flags;
+    int error;
+
+    if (smp_processor_id() != 0)
+        return -EPERM;
+
+    if (state <= ACPI_STATE_S0 || state > ACPI_S_STATES_MAX)
+        return -EINVAL;
+
+    if (!spin_trylock(&pm_lock))
+        return -EBUSY;
+    
     printk("PM: Preparing system for %s sleep\n", acpi_states[state]);
+
+    disable_nonboot_cpus();
+    if (num_online_cpus() != 1) {
+        error = -EBUSY;
+        goto Enable_cpu;
+    }
 
     local_irq_save(flags);
 
@@ -128,12 +151,10 @@ int enter_state(u32 state)
     device_power_up();
 
     printk("PM: Finishing wakeup.\n");
-    for_each_domain(d)
-       if (d->domain_id!=0)
-           domain_unpause(d);
-
  Done:
     local_irq_restore(flags);
+ Enable_cpu:
+    enable_nonboot_cpus();
     spin_unlock(&pm_lock);
     return error;
 
@@ -202,7 +223,22 @@ int acpi_enter_sleep(struct xenpf_enter_
     acpi_video_flags = sleep->video_flags;
     saved_videomode = sleep->video_mode;
 
-    return enter_state(acpi_sinfo.sleep_state);
+    freeze_domains();
+    if (current->processor == 0) {
+        int ret;
+
+        printk(XENLOG_INFO "vcpu0 on cpu0, sleep direclty\n");
+        ret = enter_state(acpi_sinfo.sleep_state);
+        thaw_domains();
+        return ret;
+    }
+
+    printk(XENLOG_INFO "vcpu0 on cpu%d, pause self and notify cpu0\n",
+        current->processor);
+    cpu_raise_softirq(0, PM_SOFTIRQ);
+    vcpu_pause_self();
+    /* return value doens't matter here. */
+    return 0;
 }
 
 static int acpi_get_wake_status(void)
@@ -228,6 +264,49 @@ acpi_status asmlinkage acpi_enter_sleep_
     /* Wait until we enter sleep state, and spin until we wake */
     while (!acpi_get_wake_status());
     return_ACPI_STATUS(AE_OK);
+}
+
+/*
+ * Power management related softirq, and cpu0 only.
+ *
+ * The reason for introducing this softirq is that cpu0 is a bit
+ * special as the last one to be pull down. However the sleep request
+ * is issued from vcpu0 of dom0 and this vcpu may not bind to cpu0.
+ *
+ * So if above case happens, the CPU receiving sleep request will
+ * raise a softirq to cpu0 and idle vcpu on cpu0 then execute this
+ * handler immediately.
+ *
+ * If vcpu0 is already running on cpu0, this softirq is not triggered
+ */
+static void pm_softirq(void)
+{
+    int cpu = smp_processor_id();
+    struct vcpu *v = dom0->vcpu[0];
+    struct cpu_user_regs *regs;
+
+    printk(XENLOG_DEBUG "In pm_softirq\n");
+    /* only cpu0 handles this irq for now */
+    if (cpu != 0)
+        return;
+
+    printk(XENLOG_DEBUG "handled by cpu0\n");
+    /* wait vcpu0/dom0 to pause itself */
+    while ( test_bit(_VCPUF_migrating, &v->vcpu_flags) )
+        cpu_relax();
+
+    while ( test_bit(_VCPUF_need_sync, &v->vcpu_flags) )
+        cpu_relax();
+
+    printk(XENLOG_INFO "vcpu0/dom0 has been paused\n");
+    /* now safe to suspend whole system from cpu 0 */
+    regs = &v->arch.guest_context.user_regs;
+    regs->eax = enter_state(acpi_sinfo.sleep_state);
+
+    /* Now unpause vcpu0/dom0 */
+    vcpu_unpause(v);
+
+    thaw_domains();
 }
 
 static int __init acpi_sleep_init(void)
@@ -247,6 +326,8 @@ static int __init acpi_sleep_init(void)
     printk(")\n");
 
     acpi_reserve_bootmem();
+
+    open_softirq(PM_SOFTIRQ, pm_softirq);
     return 0;
 }
 __initcall(acpi_sleep_init);
diff -r 308c4ef593e9 xen/include/asm-x86/smp.h
--- a/xen/include/asm-x86/smp.h Wed Feb 14 11:13:42 2007 +0800
+++ b/xen/include/asm-x86/smp.h Wed Feb 14 11:13:42 2007 +0800
@@ -70,6 +70,8 @@ extern void enable_nonboot_cpus(void);
 extern void enable_nonboot_cpus(void);
 #else
 static inline int cpu_is_offline(int cpu) {return 0;}
+static inline void disable_nonboot_cpus(void) {}
+static inline void enable_nonboot_cpus(void) {}
 #endif
 
 /*
diff -r 308c4ef593e9 xen/include/xen/softirq.h
--- a/xen/include/xen/softirq.h Wed Feb 14 11:13:42 2007 +0800
+++ b/xen/include/xen/softirq.h Wed Feb 14 11:13:42 2007 +0800
@@ -10,8 +10,9 @@
 #define PAGE_SCRUB_SOFTIRQ                5
 #define TRACE_SOFTIRQ                     6
 #define RCU_SOFTIRQ                       7
+#define PM_SOFTIRQ                        8
 
-#define NR_COMMON_SOFTIRQS                8
+#define NR_COMMON_SOFTIRQS                9
 
 #include <asm/softirq.h>

Attachment: xen_smp_pm_support.patch
Description: xen_smp_pm_support.patch

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.