[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [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 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |