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

[Xen-devel] [PATCH 7/10] SMP support to Xen PM


  • To: "Keir Fraser" <keir@xxxxxxxxxxxxx>
  • From: "Tian, Kevin" <kevin.tian@xxxxxxxxx>
  • Date: Wed, 27 Jun 2007 21:37:51 +0800
  • Cc: xen-devel@xxxxxxxxxxxxxxxxxxx
  • Delivery-date: Wed, 27 Jun 2007 06:36:17 -0700
  • List-id: Xen developer discussion <xen-devel.lists.xensource.com>
  • Thread-index: Ace4wFuH3nJSNHEYR9yKmJR1pv8uDA==
  • Thread-topic: [PATCH 7/10] SMP support to Xen PM

Add SMP support to Xen host S3

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

diff -r 1539f5a2b3ba xen/arch/x86/acpi/power.c
--- a/xen/arch/x86/acpi/power.c Tue Jun 26 18:05:22 2007 -0400
+++ b/xen/arch/x86/acpi/power.c Tue Jun 26 19:44:36 2007 -0400
@@ -25,6 +25,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);
@@ -80,37 +81,77 @@ static void device_power_up(void)
     console_resume();
 }
 
-/* Main interface to do xen specific suspend/resume */
-int enter_state(u32 state)
-{
-    struct domain *d, *pd = NULL;
-    unsigned long flags;
-    int error;
-
-    if (state <= ACPI_STATE_S0 || state > ACPI_S_STATES_MAX)
-        return -EINVAL;
-
-    /* Sync lazy state on ths cpu */
-    __sync_lazy_execstate();
-    pmprintk(XENLOG_INFO, "Flush lazy state\n");
-
-    if (!spin_trylock(&pm_lock))
-        return -EBUSY;
-    
+/* Record the last paused domain at freeze phase */
+static struct domain *pd;
+static int freeze_domains(void)
+{
+    struct domain *d;
+
+    pd = NULL;
     for_each_domain(d)
         if (d->domain_id != 0)
         {
             domain_pause(d);
             if (is_hvm_domain(d) && !hvm_suspend_domain(d))
             {
-                error = -EINVAL;
-                goto Unpause;
+                domain_unpause(d);
+                return 0;
             }
             pd = d;
         }
-
+    return 1;
+}
+
+static void thaw_domains(void)
+{
+    struct domain *d;
+
+    if (pd)
+    {
+       for_each_domain(d)
+       {
+           if (d->domain_id != 0)
+               domain_unpause(d);
+
+           /* Unpause until recorded last paused domain */
+           if (d == pd)
+               break;
+       }
+    }
+}
+
+/* Main interface to do xen specific suspend/resume */
+int enter_state(u32 state)
+{
+    unsigned long flags;
+    cpumask_t mask = cpu_online_map;
+    int error;
+
+    if (state <= ACPI_STATE_S0 || state > ACPI_S_STATES_MAX)
+        return -EINVAL;
+
+    /* Sync lazy state on ths cpu */
+    __sync_lazy_execstate();
+    pmprintk(XENLOG_INFO, "Flush lazy state\n");
+
+    if (!spin_trylock(&pm_lock))
+        return -EBUSY;
+    
     pmprintk(XENLOG_INFO, "PM: Preparing system for %s sleep\n",
         acpi_states[state]);
+
+    /* Sync all lazy states on other cpus, since APs will be
+     * re-intialized like fresh boot and stale context loses
+     */
+    cpu_clear(0, mask);
+    flush_tlb_mask(mask);
+    pmprintk(XENLOG_INFO, "Finish lazy state sync\n");
+
+    disable_nonboot_cpus();
+    if (num_online_cpus() != 1) {
+        error = -EBUSY;
+        goto Enable_cpu;
+    }
 
     local_irq_save(flags);
 
@@ -141,20 +182,8 @@ int enter_state(u32 state)
  Done:
     local_irq_restore(flags);
 
- Unpause:
-    if (pd)
-    {
-       for_each_domain(d)
-       {
-           /* Unpause until recorded last paused domain */
-           if (d == pd)
-               break;
-
-           if (d->domain_id != 0)
-               domain_unpause(d);
-       }
-    }
-
+ Enable_cpu:
+    enable_nonboot_cpus();
     spin_unlock(&pm_lock);
     return error;
 }
@@ -181,6 +210,14 @@ int set_acpi_sleep_info(struct xenpf_set
                        acpi_sinfo.pm1a_evt, acpi_sinfo.pm1b_evt,
                        info->xen_waking_vec);
     return 0;
+}
+
+static void acpi_power_off(void)
+{
+    pmprintk(XENLOG_INFO, "%s called\n", __FUNCTION__);
+    local_irq_disable();
+    /* Some SMP machines only can poweroff in boot CPU */
+    acpi_enter_sleep_state(ACPI_STATE_S5);
 }
 
 /*
@@ -224,7 +261,34 @@ 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);
+    /* acpi power off method */
+    if (acpi_sinfo.sleep_state == ACPI_STATE_S5) {
+        acpi_power_off();
+        /* Shouldn't return */
+        while(1);
+    }
+
+    if (!freeze_domains())
+    {
+        pmprintk(XENLOG_ERR, "Failed to freeze domains\n");
+        return -EINVAL;
+    }
+
+    if (current->processor == 0) {
+        int ret;
+
+        pmprintk(XENLOG_INFO, "vcpu0 on cpu0, sleep direclty\n");
+        ret = enter_state(acpi_sinfo.sleep_state);
+        thaw_domains();
+        return ret;
+    }
+
+    pmprintk(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)
@@ -250,6 +314,51 @@ 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;
+
+    pmprintk(XENLOG_DEBUG, "In pm_softirq\n");
+    /* only cpu0 handles this irq for now */
+    if (cpu != 0)
+        return;
+
+    pmprintk(XENLOG_DEBUG, "handled by cpu0\n");
+    /* Wait vcpu0/dom0 to be paused */
+    while ( !atomic_read(&v->pause_count) )
+        cpu_relax();
+
+    /* Then wait for context of vcpu/dom0 to be sync-ed */
+    while ( test_bit(_VPF_need_sync, &v->pause_flags) )
+        cpu_relax();
+
+    pmprintk(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)
@@ -268,6 +377,8 @@ static int __init acpi_sleep_init(void)
             sleep_states[i] = 0;
     }
     printk(")\n");
+
+    open_softirq(PM_SOFTIRQ, pm_softirq);
     return 0;
 }
 __initcall(acpi_sleep_init);
diff -r 1539f5a2b3ba xen/include/asm-x86/smp.h
--- a/xen/include/asm-x86/smp.h Tue Jun 26 18:05:22 2007 -0400
+++ b/xen/include/asm-x86/smp.h Tue Jun 26 18:05:22 2007 -0400
@@ -69,6 +69,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 1539f5a2b3ba xen/include/xen/softirq.h
--- a/xen/include/xen/softirq.h Tue Jun 26 18:05:22 2007 -0400
+++ b/xen/include/xen/softirq.h Tue Jun 26 18:05:22 2007 -0400
@@ -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®.