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. Also sync to xen interface headers consequently Signed-off-by Ke Yu <ke.yu@intel.com> Signed-off-by Kevin Tian <kevin.tian@intel.com> diff -r 713e909c27d2 arch/i386/Kconfig --- a/arch/i386/Kconfig Tue Jun 26 20:41:35 2007 -0400 +++ b/arch/i386/Kconfig Tue Jun 26 20:42:22 2007 -0400 @@ -832,9 +832,7 @@ menu "Power management options (ACPI, AP menu "Power management options (ACPI, APM)" depends on !(X86_VOYAGER || XEN_UNPRIVILEGED_GUEST) -if !X86_XEN -source kernel/power/Kconfig -endif +source "kernel/power/Kconfig" source "drivers/acpi/Kconfig" diff -r 713e909c27d2 arch/i386/kernel/acpi/sleep-xen.c --- a/arch/i386/kernel/acpi/sleep-xen.c Tue Jun 26 20:41:35 2007 -0400 +++ b/arch/i386/kernel/acpi/sleep-xen.c Tue Jun 26 20:42:22 2007 -0400 @@ -27,12 +27,13 @@ extern unsigned long FASTCALL(acpi_copy_ */ int acpi_save_state_mem(void) { +#ifndef CONFIG_ACPI_PV_SLEEP if (!acpi_wakeup_address) return 1; memcpy((void *)acpi_wakeup_address, &wakeup_start, &wakeup_end - &wakeup_start); acpi_copy_wakeup_routine(acpi_wakeup_address); - +#endif return 0; } @@ -104,3 +105,66 @@ static int __init acpisleep_dmi_init(voi } core_initcall(acpisleep_dmi_init); + +#ifdef CONFIG_ACPI_PV_SLEEP +#include <asm/hypervisor.h> +#include <xen/interface/platform.h> +/* Register sleep info to xen hypervisor which does real work later */ +int acpi_register_sleep_info(void) +{ + struct xen_platform_op op; + int ret; + + if (acpi_gbl_FADT == NULL) { + printk(KERN_WARNING "%s: ACPI FADT not existed\n", + __FUNCTION__); + return -1; + } + + 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; + + ret = HYPERVISOR_platform_op(&op); + + if (ret){ + printk(KERN_WARNING "%s: Fail to register acpi sleep info," + "Xen sleep will not work\n", __FUNCTION__); + return (ret); + } + + acpi_wakeup_address = (unsigned long) + op.u.set_acpi_sleep.xen_waking_vec; + return ret; +} + +extern unsigned long acpi_video_flags; +extern unsigned long saved_videomode; +int acpi_notify_hypervisor_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, + }, + }, + }; + + op.u.enter_acpi_sleep.video_flags = acpi_video_flags; + op.u.enter_acpi_sleep.video_mode = saved_videomode; + + return HYPERVISOR_platform_op(&op); +} +#endif /* CONFIG_ACPI_PV_SLEEP */ diff -r 713e909c27d2 arch/i386/kernel/time-xen.c --- a/arch/i386/kernel/time-xen.c Tue Jun 26 20:41:35 2007 -0400 +++ b/arch/i386/kernel/time-xen.c Tue Jun 26 20:42:22 2007 -0400 @@ -861,9 +861,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 713e909c27d2 arch/i386/power/cpu.c --- a/arch/i386/power/cpu.c Tue Jun 26 20:41:35 2007 -0400 +++ b/arch/i386/power/cpu.c Tue Jun 26 20:42:22 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 713e909c27d2 arch/x86_64/Kconfig --- a/arch/x86_64/Kconfig Tue Jun 26 20:41:35 2007 -0400 +++ b/arch/x86_64/Kconfig Tue Jun 26 20:42:22 2007 -0400 @@ -594,9 +594,7 @@ menu "Power management options" menu "Power management options" depends on !XEN_UNPRIVILEGED_GUEST -if !X86_64_XEN -source kernel/power/Kconfig -endif +source "kernel/power/Kconfig" source "drivers/acpi/Kconfig" diff -r 713e909c27d2 arch/x86_64/kernel/acpi/Makefile --- a/arch/x86_64/kernel/acpi/Makefile Tue Jun 26 20:41:35 2007 -0400 +++ b/arch/x86_64/kernel/acpi/Makefile Tue Jun 26 20:42:22 2007 -0400 @@ -8,3 +8,7 @@ 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 713e909c27d2 arch/x86_64/kernel/acpi/sleep-xen.c --- a/arch/x86_64/kernel/acpi/sleep-xen.c Tue Jun 26 20:41:35 2007 -0400 +++ b/arch/x86_64/kernel/acpi/sleep-xen.c Tue Jun 26 20:42:22 2007 -0400 @@ -79,12 +79,13 @@ static void init_low_mapping(void) */ int acpi_save_state_mem(void) { +#ifndef CONFIG_ACPI_PV_SLEEP init_low_mapping(); memcpy((void *)acpi_wakeup_address, &wakeup_start, &wakeup_end - &wakeup_start); acpi_copy_wakeup_routine(acpi_wakeup_address); - +#endif return 0; } @@ -93,8 +94,10 @@ int acpi_save_state_mem(void) */ void acpi_restore_state_mem(void) { +#ifndef CONFIG_ACPI_PV_SLEEP set_pgd(pgd_offset(current->mm, 0UL), low_ptr); local_flush_tlb(); +#endif } /** @@ -124,11 +127,74 @@ static int __init acpi_sleep_setup(char if (str != NULL) str += strspn(str, ", \t"); } + return 1; } __setup("acpi_sleep=", acpi_sleep_setup); +#ifdef CONFIG_ACPI_PV_SLEEP +#include <asm/hypervisor.h> +#include <xen/interface/platform.h> +/* Register sleep info to xen hypervisor which does real work later */ +int acpi_register_sleep_info(void) +{ + struct xen_platform_op op; + int ret; + + if (acpi_gbl_FADT == NULL) { + printk(KERN_WARNING "%s: ACPI FADT not existed\n", + __FUNCTION__); + return -1; + } + + 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; + + ret = HYPERVISOR_platform_op(&op); + + if (ret){ + printk(KERN_WARNING "%s: Fail to register acpi sleep info," + "Xen sleep will not work\n", __FUNCTION__); + return ret; + } + + acpi_wakeup_address = (unsigned long) + op.u.set_acpi_sleep.xen_waking_vec; + return ret; +} + +extern unsigned long saved_video_mode; +int acpi_notify_hypervisor_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, + }, + }, + }; + + op.u.enter_acpi_sleep.video_flags = acpi_video_flags; + op.u.enter_acpi_sleep.video_mode = saved_video_mode; + + return HYPERVISOR_platform_op(&op); +} +#endif /* CONFIG_ACPI_PV_SLEEP */ + #endif /*CONFIG_ACPI_SLEEP */ void acpi_pci_link_exit(void) diff -r 713e909c27d2 arch/x86_64/kernel/head-xen.S --- a/arch/x86_64/kernel/head-xen.S Tue Jun 26 20:41:35 2007 -0400 +++ b/arch/x86_64/kernel/head-xen.S Tue Jun 26 20:42:22 2007 -0400 @@ -37,6 +37,13 @@ startup_64: 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) @@ -95,6 +102,14 @@ NEXT_PAGE(hypercall_page) CFI_ENDPROC #undef NEXT_PAGE + + .data +/* Just dummy symbol to allow compilation. Not used in sleep path */ +#ifdef CONFIG_ACPI_SLEEP + .align PAGE_SIZE +ENTRY(wakeup_level4_pgt) + .fill 512,8,0 +#endif .data diff -r 713e909c27d2 arch/x86_64/kernel/suspend.c --- a/arch/x86_64/kernel/suspend.c Tue Jun 26 20:41:35 2007 -0400 +++ b/arch/x86_64/kernel/suspend.c Tue Jun 26 20:42:22 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 713e909c27d2 buildconfigs/linux-defconfig_xen_x86_32 --- a/buildconfigs/linux-defconfig_xen_x86_32 Tue Jun 26 20:41:35 2007 -0400 +++ b/buildconfigs/linux-defconfig_xen_x86_32 Tue Jun 26 20:42:22 2007 -0400 @@ -202,11 +202,18 @@ CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y # Power management options (ACPI, APM) # CONFIG_PM=y +# CONFIG_PM_LEGACY is not set +CONFIG_PM_DEBUG=y +# CONFIG_SOFTWARE_SUSPEND is not set +CONFIG_SUSPEND_SMP=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 is not set CONFIG_ACPI_AC=m CONFIG_ACPI_BATTERY=m CONFIG_ACPI_BUTTON=m diff -r 713e909c27d2 buildconfigs/linux-defconfig_xen_x86_64 --- a/buildconfigs/linux-defconfig_xen_x86_64 Tue Jun 26 20:41:35 2007 -0400 +++ b/buildconfigs/linux-defconfig_xen_x86_64 Tue Jun 26 20:42:22 2007 -0400 @@ -162,11 +162,18 @@ CONFIG_GENERIC_PENDING_IRQ=y # Power management options # CONFIG_PM=y +# CONFIG_PM_LEGACY is not set +CONFIG_PM_DEBUG=y +# CONFIG_SOFTWARE_SUSPEND is not set +CONFIG_SUSPEND_SMP=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 is not set CONFIG_ACPI_AC=m CONFIG_ACPI_BATTERY=m CONFIG_ACPI_BUTTON=m diff -r 713e909c27d2 drivers/acpi/Kconfig --- a/drivers/acpi/Kconfig Tue Jun 26 20:41:35 2007 -0400 +++ b/drivers/acpi/Kconfig Tue Jun 26 20:42:22 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--- @@ -363,6 +363,10 @@ config ACPI_SBS A "Smart Battery" is quite old and quite rare compared to today''s ACPI "Control Method" battery. +config ACPI_PV_SLEEP + bool + depends on X86 && XEN + default y endif # ACPI endmenu diff -r 713e909c27d2 drivers/acpi/hardware/hwsleep.c --- a/drivers/acpi/hardware/hwsleep.c Tue Jun 26 20:41:35 2007 -0400 +++ b/drivers/acpi/hardware/hwsleep.c Tue Jun 26 20:42:22 2007 -0400 @@ -327,6 +327,7 @@ acpi_status asmlinkage acpi_enter_sleep_ ACPI_FLUSH_CPU_CACHE(); +#ifndef CONFIG_ACPI_PV_SLEEP status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1A_CONTROL, PM1Acontrol); @@ -337,6 +338,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_hypervisor_state(sleep_state, + PM1Acontrol, PM1Bcontrol); +#endif if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } diff -r 713e909c27d2 drivers/acpi/sleep/main.c --- a/drivers/acpi/sleep/main.c Tue Jun 26 20:41:35 2007 -0400 +++ b/drivers/acpi/sleep/main.c Tue Jun 26 20:42:22 2007 -0400 @@ -91,7 +91,14 @@ static int acpi_pm_enter(suspend_state_t break; case PM_SUSPEND_MEM: +#ifdef CONFIG_ACPI_PV_SLEEP + /* 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: @@ -145,10 +152,12 @@ static int acpi_pm_finish(suspend_state_ /* reset firmware waking vector */ acpi_set_firmware_waking_vector((acpi_physical_address) 0); +#ifndef CONFIG_ACPI_PV_SLEEP if (init_8259A_after_S1) { printk("Broken toshiba laptop -> kicking interrupts\n"); init_8259A(0); } +#endif return 0; } @@ -226,6 +235,10 @@ static int __init acpi_sleep_init(void) printk(")\n"); pm_set_ops(&acpi_pm_ops); + +#ifdef CONFIG_ACPI_PV_SLEEP + acpi_register_sleep_info(); +#endif return 0; } diff -r 713e909c27d2 drivers/acpi/sleep/poweroff.c --- a/drivers/acpi/sleep/poweroff.c Tue Jun 26 20:41:35 2007 -0400 +++ b/drivers/acpi/sleep/poweroff.c Tue Jun 26 20:42:22 2007 -0400 @@ -25,9 +25,15 @@ int acpi_sleep_prepare(u32 acpi_state) if (!acpi_wakeup_address) { return -EFAULT; } +#ifndef CONFIG_ACPI_PV_SLEEP acpi_set_firmware_waking_vector((acpi_physical_address) virt_to_phys((void *) acpi_wakeup_address)); +#else + /* physical address of hypervisor wakeup vector */ + acpi_set_firmware_waking_vector((acpi_physical_address) + acpi_wakeup_address); +#endif } ACPI_FLUSH_CPU_CACHE(); diff -r 713e909c27d2 include/asm-i386/acpi.h --- a/include/asm-i386/acpi.h Tue Jun 26 20:41:35 2007 -0400 +++ b/include/asm-i386/acpi.h Tue Jun 26 20:42:22 2007 -0400 @@ -177,6 +177,11 @@ extern unsigned long acpi_wakeup_address /* early initialization routine */ extern void acpi_reserve_bootmem(void); +#ifdef CONFIG_ACPI_PV_SLEEP +extern int acpi_notify_hypervisor_state(u8 sleep_state, + u32 pm1a_cnt, u32 pm1b_cnt); +extern int acpi_register_sleep_info(void); +#endif /* CONFIG_ACPI_PV_SLEEP */ #endif /*CONFIG_ACPI_SLEEP*/ extern u8 x86_acpiid_to_apicid[]; diff -r 713e909c27d2 include/asm-x86_64/acpi.h --- a/include/asm-x86_64/acpi.h Tue Jun 26 20:41:35 2007 -0400 +++ b/include/asm-x86_64/acpi.h Tue Jun 26 20:42:22 2007 -0400 @@ -153,6 +153,11 @@ extern unsigned long acpi_wakeup_address /* early initialization routine */ extern void acpi_reserve_bootmem(void); +#ifdef CONFIG_ACPI_PV_SLEEP +extern int acpi_notify_hypervisor_state(u8 sleep_state, + u32 pm1a_cnt, u32 pm1b_cnt); +extern int acpi_register_sleep_info(void); +#endif /* CONFIG_ACPI_PV_SLEEP */ #endif /*CONFIG_ACPI_SLEEP*/ #define boot_cpu_physical_apicid boot_cpu_id diff -r 713e909c27d2 include/xen/interface/platform.h --- a/include/xen/interface/platform.h Tue Jun 26 20:41:35 2007 -0400 +++ b/include/xen/interface/platform.h Tue Jun 26 20:38:40 2007 -0400 @@ -153,6 +153,31 @@ typedef struct xenpf_firmware_info xenpf typedef struct xenpf_firmware_info xenpf_firmware_info_t; DEFINE_XEN_GUEST_HANDLE(xenpf_firmware_info_t); +#define XENPF_set_acpi_sleep 51 +struct xenpf_set_acpi_sleep { + /* IN variables. */ + uint16_t pm1a_cnt_port; + uint16_t pm1b_cnt_port; + uint16_t pm1a_evt_port; + uint16_t pm1b_evt_port; + /* OUT variables */ + uint64_t xen_waking_vec; /* Tell dom0 to set FACS waking vector */ +}; +typedef struct xenpf_set_acpi_sleep xenpf_set_acpi_sleep_t; +DEFINE_XEN_GUEST_HANDLE(xenpf_set_acpi_sleep_t); + +#define XENPF_enter_acpi_sleep 52 +struct xenpf_enter_acpi_sleep { + /* IN variables */ + uint16_t pm1a_cnt_val; + uint16_t pm1b_cnt_val; + uint32_t sleep_state; /* Which state to enter */ + uint32_t video_flags; /* S3_bios or s3_mode */ + uint32_t video_mode; /* Mode setting for s3_mode */ +}; +typedef struct xenpf_enter_acpi_sleep xenpf_enter_acpi_sleep_t; +DEFINE_XEN_GUEST_HANDLE(xenpf_enter_acpi_sleep_t); + struct xen_platform_op { uint32_t cmd; uint32_t interface_version; /* XENPF_INTERFACE_VERSION */ @@ -164,6 +189,8 @@ struct xen_platform_op { struct xenpf_microcode_update microcode; struct xenpf_platform_quirk platform_quirk; struct xenpf_firmware_info firmware_info; + struct xenpf_set_acpi_sleep set_acpi_sleep; + struct xenpf_enter_acpi_sleep enter_acpi_sleep; uint8_t pad[128]; } u; }; _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel