WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

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

To: "Keir Fraser" <keir@xxxxxxxxxxxxx>
Subject: [Xen-devel] [PATCH 7/10] SMP support to Xen PM
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
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
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
<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-devel] [PATCH 7/10] SMP support to Xen PM, Tian, Kevin <=