Open CONFIG_ACPI_SLEEP in xenlinux, to enable ACPI based power management. Basically, user can trigger power event now by "echo *** > /sys/power/state". Also gear to pm interface defined between xenlinux and Xen. Signed-off-by Ke Yu Signed-off-by Kevin Tian diff -r ae6a502a5db4 buildconfigs/linux-defconfig_xen_x86_32 --- a/buildconfigs/linux-defconfig_xen_x86_32 Wed Apr 11 14:09:56 2007 -0400 +++ b/buildconfigs/linux-defconfig_xen_x86_32 Wed Apr 11 14:09:57 2007 -0400 @@ -205,6 +205,9 @@ CONFIG_PM=y # ACPI (Advanced Configuration and Power Interface) Support # CONFIG_ACPI=y +CONFIG_ACPI_SLEEP=y +ACPI_SLEEP_PROC_FS=y +CONFIG_ACPI_SLEEP_PROC_SLEEP=y CONFIG_ACPI_AC=m CONFIG_ACPI_BATTERY=m CONFIG_ACPI_BUTTON=m diff -r ae6a502a5db4 buildconfigs/linux-defconfig_xen_x86_64 --- a/buildconfigs/linux-defconfig_xen_x86_64 Wed Apr 11 14:09:56 2007 -0400 +++ b/buildconfigs/linux-defconfig_xen_x86_64 Wed Apr 11 14:09:57 2007 -0400 @@ -167,6 +167,9 @@ CONFIG_PM=y # ACPI (Advanced Configuration and Power Interface) Support # CONFIG_ACPI=y +CONFIG_ACPI_SLEEP=y +CONFIG_ACPI_SLEEP_PROC_FS=y +CONFIG_ACPI_SLEEP_PROC_SLEEP=y CONFIG_ACPI_AC=m CONFIG_ACPI_BATTERY=m CONFIG_ACPI_BUTTON=m diff -r ae6a502a5db4 linux-2.6-xen-sparse/arch/i386/Kconfig --- a/linux-2.6-xen-sparse/arch/i386/Kconfig Wed Apr 11 14:09:56 2007 -0400 +++ b/linux-2.6-xen-sparse/arch/i386/Kconfig Wed Apr 11 14:09:57 2007 -0400 @@ -810,6 +810,11 @@ config HOTPLUG_CPU Say Y here to experiment with turning CPUs off and on, and to enable suspend on SMP systems. CPUs can be controlled through /sys/devices/system/cpu. + +config SUSPEND_SMP + bool + depends on HOTPLUG_CPU && X86 && PM + default y config COMPAT_VDSO bool "Compat VDSO support" diff -r ae6a502a5db4 linux-2.6-xen-sparse/arch/i386/kernel/time-xen.c --- a/linux-2.6-xen-sparse/arch/i386/kernel/time-xen.c Wed Apr 11 14:09:56 2007 -0400 +++ b/linux-2.6-xen-sparse/arch/i386/kernel/time-xen.c Wed Apr 11 14:09:57 2007 -0400 @@ -849,9 +849,9 @@ static int timer_resume(struct sys_devic return 0; } +void time_resume(void); static struct sysdev_class timer_sysclass = { - .resume = timer_resume, - .suspend = timer_suspend, + .resume = time_resume, set_kset_name("timer"), }; diff -r ae6a502a5db4 linux-2.6-xen-sparse/arch/i386/power/Makefile --- a/linux-2.6-xen-sparse/arch/i386/power/Makefile Wed Apr 11 14:09:56 2007 -0400 +++ b/linux-2.6-xen-sparse/arch/i386/power/Makefile Wed Apr 11 14:09:57 2007 -0400 @@ -2,3 +2,8 @@ obj-$(CONFIG_SOFTWARE_SUSPEND) += cpu.o obj-$(CONFIG_SOFTWARE_SUSPEND) += cpu.o obj-$(CONFIG_ACPI_SLEEP) += cpu.o obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o + +ifdef CONFIG_XEN +include $(srctree)/scripts/Makefile.xen +obj-y := $(call cherrypickxen, $(obj-y)) +endif diff -r ae6a502a5db4 linux-2.6-xen-sparse/arch/i386/power/cpu-xen.c --- a/linux-2.6-xen-sparse/arch/i386/power/cpu-xen.c Wed Apr 11 14:09:56 2007 -0400 +++ b/linux-2.6-xen-sparse/arch/i386/power/cpu-xen.c Wed Apr 11 14:09:57 2007 -0400 @@ -62,11 +62,12 @@ static void do_fpu_end(void) static void fix_processor_context(void) { +#ifndef CONFIG_X86_NO_TSS int cpu = smp_processor_id(); struct tss_struct * t = &per_cpu(init_tss, cpu); set_tss_desc(cpu,t); /* This just modifies memory; should not be necessary. But... This is necessary, because 386 hardware has concept of busy TSS or some similar stupidity. */ - +#endif load_TR_desc(); /* This does ltr */ load_LDT(¤t->active_mm->context); /* This does lldt */ diff -r ae6a502a5db4 linux-2.6-xen-sparse/arch/x86_64/Kconfig --- a/linux-2.6-xen-sparse/arch/x86_64/Kconfig Wed Apr 11 14:09:56 2007 -0400 +++ b/linux-2.6-xen-sparse/arch/x86_64/Kconfig Wed Apr 11 14:09:57 2007 -0400 @@ -408,6 +408,11 @@ config HOTPLUG_CPU can be controlled through /sys/devices/system/cpu/cpu#. Say N if you want to disable CPU hotplug. +config SUSPEND_SMP + bool + depends on HOTPLUG_CPU && X86 && PM + default y + config ARCH_ENABLE_MEMORY_HOTPLUG def_bool y diff -r ae6a502a5db4 linux-2.6-xen-sparse/arch/x86_64/kernel/acpi/Makefile --- a/linux-2.6-xen-sparse/arch/x86_64/kernel/acpi/Makefile Wed Apr 11 14:09:56 2007 -0400 +++ b/linux-2.6-xen-sparse/arch/x86_64/kernel/acpi/Makefile Wed Apr 11 14:09:57 2007 -0400 @@ -8,3 +8,8 @@ endif endif boot-$(CONFIG_XEN) := ../../../i386/kernel/acpi/boot-xen.o + +ifdef CONFIG_XEN +include $(srctree)/scripts/Makefile.xen +obj-y := $(call cherrypickxen, $(obj-y)) +endif diff -r ae6a502a5db4 linux-2.6-xen-sparse/arch/x86_64/kernel/head-xen.S --- a/linux-2.6-xen-sparse/arch/x86_64/kernel/head-xen.S Wed Apr 11 14:09:56 2007 -0400 +++ b/linux-2.6-xen-sparse/arch/x86_64/kernel/head-xen.S Wed Apr 11 14:09:57 2007 -0400 @@ -43,6 +43,13 @@ ENTRY(_start) pushq $0 # fake return address jmp x86_64_start_kernel +#ifdef CONFIG_ACPI_SLEEP +.org 0xf00 + .globl pGDT32 +pGDT32: + .word gdt_end-cpu_gdt_table-1 + .long cpu_gdt_table-__START_KERNEL_map +#endif ENTRY(stext) ENTRY(_stext) @@ -102,6 +109,14 @@ NEXT_PAGE(hypercall_page) CFI_ENDPROC #undef NEXT_PAGE + + .data + +#ifdef CONFIG_ACPI_SLEEP + .align PAGE_SIZE +ENTRY(wakeup_level4_pgt) + .fill 512,8,0 +#endif .data diff -r ae6a502a5db4 linux-2.6-xen-sparse/arch/x86_64/kernel/suspend-xen.c --- a/linux-2.6-xen-sparse/arch/x86_64/kernel/suspend-xen.c Wed Apr 11 14:09:56 2007 -0400 +++ b/linux-2.6-xen-sparse/arch/x86_64/kernel/suspend-xen.c Wed Apr 11 14:09:57 2007 -0400 @@ -114,12 +114,14 @@ void restore_processor_state(void) void fix_processor_context(void) { +#ifndef CONFIG_X86_NO_TSS int cpu = smp_processor_id(); struct tss_struct *t = &per_cpu(init_tss, cpu); set_tss_desc(cpu,t); /* This just modifies memory; should not be neccessary. But... This is neccessary, because 386 hardware has concept of busy TSS or some similar stupidity. */ cpu_gdt(cpu)[GDT_ENTRY_TSS].type = 9; +#endif syscall_init(); /* This sets MSR_*STAR and related */ load_TR_desc(); /* This does ltr */ diff -r ae6a502a5db4 linux-2.6-xen-sparse/drivers/acpi/Kconfig --- a/linux-2.6-xen-sparse/drivers/acpi/Kconfig Wed Apr 11 14:09:56 2007 -0400 +++ b/linux-2.6-xen-sparse/drivers/acpi/Kconfig Wed Apr 11 14:09:57 2007 -0400 @@ -45,7 +45,7 @@ if ACPI config ACPI_SLEEP bool "Sleep States" - depends on X86 && (!SMP || SUSPEND_SMP) && !XEN + depends on X86 && (!SMP || SUSPEND_SMP) depends on PM default y ---help--- diff -r ae6a502a5db4 linux-2.6-xen-sparse/drivers/acpi/hardware/Makefile --- a/linux-2.6-xen-sparse/drivers/acpi/hardware/Makefile Wed Apr 11 14:09:56 2007 -0400 +++ b/linux-2.6-xen-sparse/drivers/acpi/hardware/Makefile Wed Apr 11 14:09:57 2007 -0400 @@ -7,3 +7,8 @@ obj-$(ACPI_FUTURE_USAGE) += hwtimer.o obj-$(ACPI_FUTURE_USAGE) += hwtimer.o EXTRA_CFLAGS += $(ACPI_CFLAGS) + +ifdef CONFIG_XEN +include $(srctree)/scripts/Makefile.xen +obj-y := $(call cherrypickxen, $(obj-y)) +endif diff -r ae6a502a5db4 linux-2.6-xen-sparse/drivers/acpi/hardware/hwsleep-xen.c --- a/linux-2.6-xen-sparse/drivers/acpi/hardware/hwsleep-xen.c Wed Apr 11 14:09:56 2007 -0400 +++ b/linux-2.6-xen-sparse/drivers/acpi/hardware/hwsleep-xen.c Wed Apr 11 14:09:57 2007 -0400 @@ -209,6 +209,37 @@ acpi_status acpi_enter_sleep_state_prep( ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state_prep) +#ifdef CONFIG_XEN +#include +#include +#ifdef CONFIG_X86_64 +#define saved_videomode saved_video_mode +#endif +extern unsigned long acpi_video_flags; +extern unsigned long saved_videomode; +static acpi_status acpi_notify_xen_state(u8 sleep_state, + u32 pm1a_cnt, u32 pm1b_cnt) +{ + struct xen_platform_op op = { + .cmd = XENPF_enter_acpi_sleep, + .interface_version = XENPF_INTERFACE_VERSION, + .u = { + .enter_acpi_sleep = { + .pm1a_cnt_val = (u16)pm1a_cnt, + .pm1b_cnt_val = (u16)pm1b_cnt, + .sleep_state = sleep_state, + }, + }, + }; + +#ifdef CONFIG_X86 + op.u.enter_acpi_sleep.video_flags = acpi_video_flags; + op.u.enter_acpi_sleep.video_mode = saved_videomode; +#endif + + return HYPERVISOR_platform_op(&op); +} +#endif /*********************************************************************** ******** * * FUNCTION: acpi_enter_sleep_state @@ -327,6 +358,7 @@ acpi_status asmlinkage acpi_enter_sleep_ ACPI_FLUSH_CPU_CACHE(); +#ifndef CONFIG_XEN status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1A_CONTROL, PM1Acontrol); @@ -337,6 +369,10 @@ acpi_status asmlinkage acpi_enter_sleep_ status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1B_CONTROL, PM1Bcontrol); +#else + status = acpi_notify_xen_state(sleep_state, + PM1Acontrol, PM1Bcontrol); +#endif if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } diff -r ae6a502a5db4 linux-2.6-xen-sparse/drivers/acpi/sleep/Makefile --- a/linux-2.6-xen-sparse/drivers/acpi/sleep/Makefile Wed Apr 11 14:09:56 2007 -0400 +++ b/linux-2.6-xen-sparse/drivers/acpi/sleep/Makefile Wed Apr 11 14:09:57 2007 -0400 @@ -3,3 +3,8 @@ obj-$(CONFIG_ACPI_SLEEP_PROC_FS) += proc obj-$(CONFIG_ACPI_SLEEP_PROC_FS) += proc.o EXTRA_CFLAGS += $(ACPI_CFLAGS) + +ifdef CONFIG_XEN +include $(srctree)/scripts/Makefile.xen +obj-y := $(call cherrypickxen, $(obj-y)) +endif diff -r ae6a502a5db4 linux-2.6-xen-sparse/drivers/acpi/sleep/main-xen.c --- a/linux-2.6-xen-sparse/drivers/acpi/sleep/main-xen.c Wed Apr 11 14:09:56 2007 -0400 +++ b/linux-2.6-xen-sparse/drivers/acpi/sleep/main-xen.c Wed Apr 11 14:09:57 2007 -0400 @@ -75,12 +75,15 @@ static int acpi_pm_enter(suspend_state_t ACPI_FLUSH_CPU_CACHE(); +#ifndef CONFIG_XEN + /* Covered by Xen */ /* Do arch specific saving of state. */ if (pm_state > PM_SUSPEND_STANDBY) { int error = acpi_save_state_mem(); if (error) return error; } +#endif local_irq_save(flags); acpi_enable_wakeup_device(acpi_state); @@ -91,7 +94,14 @@ static int acpi_pm_enter(suspend_state_t break; case PM_SUSPEND_MEM: +#ifdef CONFIG_XEN + /* XEN hyperviosr will save and restore CPU context + * and then we can skip low level housekeeping here. + */ + acpi_enter_sleep_state(acpi_state); +#else do_suspend_lowlevel(); +#endif break; case PM_SUSPEND_DISK: @@ -121,8 +131,10 @@ static int acpi_pm_enter(suspend_state_t * And, in the case of the latter, the memory image should have already * been loaded from disk. */ +#ifndef CONFIG_XEN if (pm_state > PM_SUSPEND_STANDBY) acpi_restore_state_mem(); +#endif return ACPI_SUCCESS(status) ? 0 : -EFAULT; } @@ -145,10 +157,12 @@ static int acpi_pm_finish(suspend_state_ /* reset firmware waking vector */ acpi_set_firmware_waking_vector((acpi_physical_address) 0); +#ifndef CONFIG_XEN if (init_8259A_after_S1) { printk("Broken toshiba laptop -> kicking interrupts\n"); init_8259A(0); } +#endif return 0; } @@ -199,6 +213,46 @@ static struct dmi_system_id __initdata a }, {}, }; + +#ifdef CONFIG_XEN +#include +#include +/* Register sleep info to xen hypervisor which does real work later */ +static acpi_status acpi_register_sleep_info(void) +{ + struct xen_platform_op op; + acpi_status status; + + if (acpi_gbl_FADT == NULL) { + printk(KERN_WARNING "%s: ACPI FADT not existed\n", + __FUNCTION__); + return AE_NO_ACPI_TABLES; + } + + op.cmd = XENPF_set_acpi_sleep; + op.interface_version = XENPF_INTERFACE_VERSION; + op.u.set_acpi_sleep.pm1a_cnt_port = + (u16)acpi_gbl_FADT->xpm1a_cnt_blk.address; + op.u.set_acpi_sleep.pm1b_cnt_port = + (u16)acpi_gbl_FADT->xpm1b_cnt_blk.address; + op.u.set_acpi_sleep.pm1a_evt_port = + (u16)acpi_gbl_FADT->xpm1a_evt_blk.address; + op.u.set_acpi_sleep.pm1b_evt_port = + (u16)acpi_gbl_FADT->xpm1b_evt_blk.address; + + status = HYPERVISOR_platform_op(&op); + + if (ACPI_FAILURE(status)){ + printk(KERN_WARNING "%s: Fail to register acpi sleep info," + "Xen sleep will not work\n", __FUNCTION__); + return (status); + } + + acpi_wakeup_address = (unsigned long) + op.u.set_acpi_sleep.xen_waking_vec; + return status; +} +#endif /* CONFIG_XEN */ static int __init acpi_sleep_init(void) { @@ -226,6 +280,10 @@ static int __init acpi_sleep_init(void) printk(")\n"); pm_set_ops(&acpi_pm_ops); + +#ifdef CONFIG_XEN + acpi_register_sleep_info(); +#endif return 0; } diff -r ae6a502a5db4 linux-2.6-xen-sparse/drivers/acpi/sleep/poweroff-xen.c --- a/linux-2.6-xen-sparse/drivers/acpi/sleep/poweroff-xen.c Wed Apr 11 14:09:56 2007 -0400 +++ b/linux-2.6-xen-sparse/drivers/acpi/sleep/poweroff-xen.c Wed Apr 11 14:09:57 2007 -0400 @@ -25,9 +25,14 @@ int acpi_sleep_prepare(u32 acpi_state) if (!acpi_wakeup_address) { return -EFAULT; } +#ifndef CONFIG_XEN acpi_set_firmware_waking_vector((acpi_physical_address) virt_to_phys((void *) acpi_wakeup_address)); +#else + acpi_set_firmware_waking_vector((acpi_physical_address) + acpi_wakeup_address); +#endif } ACPI_FLUSH_CPU_CACHE();