# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Date 1184848094 -3600
# Node ID c68699484a654681a2912e70411286f13119c01f
# Parent ff0ef25ec2042cb3975d789700d34148f6a8d14f
Enable ACPI sleep in XenLinux
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@xxxxxxxxx>
Signed-off-by Kevin Tian <kevin.tian@xxxxxxxxx>
---
arch/i386/Kconfig | 4 +---
arch/i386/kernel/acpi/sleep-xen.c | 25 ++++++++++++++++++++++++-
arch/i386/kernel/time-xen.c | 4 ++--
arch/i386/power/cpu.c | 3 ++-
arch/x86_64/Kconfig | 4 +---
arch/x86_64/kernel/acpi/Makefile | 4 ++++
arch/x86_64/kernel/acpi/sleep-xen.c | 28 +++++++++++++++++++++++++++-
arch/x86_64/kernel/head-xen.S | 15 +++++++++++++++
arch/x86_64/kernel/suspend.c | 2 ++
buildconfigs/linux-defconfig_xen_x86_32 | 7 +++++++
buildconfigs/linux-defconfig_xen_x86_64 | 7 +++++++
drivers/acpi/Kconfig | 6 +++++-
drivers/acpi/hardware/hwsleep.c | 5 +++++
drivers/acpi/sleep/main.c | 9 +++++++++
drivers/acpi/sleep/poweroff.c | 2 ++
include/asm-i386/acpi.h | 4 ++++
include/asm-x86_64/acpi.h | 4 ++++
include/xen/interface/platform.h | 12 ++++++++++++
18 files changed, 133 insertions(+), 12 deletions(-)
diff -r ff0ef25ec204 -r c68699484a65 arch/i386/Kconfig
--- a/arch/i386/Kconfig Thu Jul 19 13:24:44 2007 +0100
+++ b/arch/i386/Kconfig Thu Jul 19 13:28:14 2007 +0100
@@ -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 ff0ef25ec204 -r c68699484a65 arch/i386/kernel/acpi/sleep-xen.c
--- a/arch/i386/kernel/acpi/sleep-xen.c Thu Jul 19 13:24:44 2007 +0100
+++ b/arch/i386/kernel/acpi/sleep-xen.c Thu Jul 19 13:28:14 2007 +0100
@@ -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,25 @@ 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>
+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,
+ },
+ },
+ };
+
+ return HYPERVISOR_platform_op(&op);
+}
+#endif /* CONFIG_ACPI_PV_SLEEP */
diff -r ff0ef25ec204 -r c68699484a65 arch/i386/kernel/time-xen.c
--- a/arch/i386/kernel/time-xen.c Thu Jul 19 13:24:44 2007 +0100
+++ b/arch/i386/kernel/time-xen.c Thu Jul 19 13:28:14 2007 +0100
@@ -867,9 +867,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 ff0ef25ec204 -r c68699484a65 arch/i386/power/cpu.c
--- a/arch/i386/power/cpu.c Thu Jul 19 13:24:44 2007 +0100
+++ b/arch/i386/power/cpu.c Thu Jul 19 13:28:14 2007 +0100
@@ -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 ff0ef25ec204 -r c68699484a65 arch/x86_64/Kconfig
--- a/arch/x86_64/Kconfig Thu Jul 19 13:24:44 2007 +0100
+++ b/arch/x86_64/Kconfig Thu Jul 19 13:28:14 2007 +0100
@@ -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 ff0ef25ec204 -r c68699484a65 arch/x86_64/kernel/acpi/Makefile
--- a/arch/x86_64/kernel/acpi/Makefile Thu Jul 19 13:24:44 2007 +0100
+++ b/arch/x86_64/kernel/acpi/Makefile Thu Jul 19 13:28:14 2007 +0100
@@ -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 ff0ef25ec204 -r c68699484a65 arch/x86_64/kernel/acpi/sleep-xen.c
--- a/arch/x86_64/kernel/acpi/sleep-xen.c Thu Jul 19 13:24:44 2007 +0100
+++ b/arch/x86_64/kernel/acpi/sleep-xen.c Thu Jul 19 13:28:14 2007 +0100
@@ -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,10 +127,33 @@ 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>
+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,
+ },
+ },
+ };
+
+ return HYPERVISOR_platform_op(&op);
+}
+#endif /* CONFIG_ACPI_PV_SLEEP */
#endif /*CONFIG_ACPI_SLEEP */
diff -r ff0ef25ec204 -r c68699484a65 arch/x86_64/kernel/head-xen.S
--- a/arch/x86_64/kernel/head-xen.S Thu Jul 19 13:24:44 2007 +0100
+++ b/arch/x86_64/kernel/head-xen.S Thu Jul 19 13:28:14 2007 +0100
@@ -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 ff0ef25ec204 -r c68699484a65 arch/x86_64/kernel/suspend.c
--- a/arch/x86_64/kernel/suspend.c Thu Jul 19 13:24:44 2007 +0100
+++ b/arch/x86_64/kernel/suspend.c Thu Jul 19 13:28:14 2007 +0100
@@ -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 ff0ef25ec204 -r c68699484a65 buildconfigs/linux-defconfig_xen_x86_32
--- a/buildconfigs/linux-defconfig_xen_x86_32 Thu Jul 19 13:24:44 2007 +0100
+++ b/buildconfigs/linux-defconfig_xen_x86_32 Thu Jul 19 13:28:14 2007 +0100
@@ -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 ff0ef25ec204 -r c68699484a65 buildconfigs/linux-defconfig_xen_x86_64
--- a/buildconfigs/linux-defconfig_xen_x86_64 Thu Jul 19 13:24:44 2007 +0100
+++ b/buildconfigs/linux-defconfig_xen_x86_64 Thu Jul 19 13:28:14 2007 +0100
@@ -161,11 +161,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 ff0ef25ec204 -r c68699484a65 drivers/acpi/Kconfig
--- a/drivers/acpi/Kconfig Thu Jul 19 13:24:44 2007 +0100
+++ b/drivers/acpi/Kconfig Thu Jul 19 13:28:14 2007 +0100
@@ -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 ff0ef25ec204 -r c68699484a65 drivers/acpi/hardware/hwsleep.c
--- a/drivers/acpi/hardware/hwsleep.c Thu Jul 19 13:24:44 2007 +0100
+++ b/drivers/acpi/hardware/hwsleep.c Thu Jul 19 13:28:14 2007 +0100
@@ -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 ff0ef25ec204 -r c68699484a65 drivers/acpi/sleep/main.c
--- a/drivers/acpi/sleep/main.c Thu Jul 19 13:24:44 2007 +0100
+++ b/drivers/acpi/sleep/main.c Thu Jul 19 13:28:14 2007 +0100
@@ -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;
}
diff -r ff0ef25ec204 -r c68699484a65 drivers/acpi/sleep/poweroff.c
--- a/drivers/acpi/sleep/poweroff.c Thu Jul 19 13:24:44 2007 +0100
+++ b/drivers/acpi/sleep/poweroff.c Thu Jul 19 13:28:14 2007 +0100
@@ -20,6 +20,7 @@ int acpi_sleep_prepare(u32 acpi_state)
int acpi_sleep_prepare(u32 acpi_state)
{
#ifdef CONFIG_ACPI_SLEEP
+#ifndef CONFIG_ACPI_PV_SLEEP
/* do we have a wakeup address for S2 and S3? */
if (acpi_state == ACPI_STATE_S3) {
if (!acpi_wakeup_address) {
@@ -30,6 +31,7 @@ int acpi_sleep_prepare(u32 acpi_state)
acpi_wakeup_address));
}
+#endif
ACPI_FLUSH_CPU_CACHE();
acpi_enable_wakeup_device_prep(acpi_state);
#endif
diff -r ff0ef25ec204 -r c68699484a65 include/asm-i386/acpi.h
--- a/include/asm-i386/acpi.h Thu Jul 19 13:24:44 2007 +0100
+++ b/include/asm-i386/acpi.h Thu Jul 19 13:28:14 2007 +0100
@@ -177,6 +177,10 @@ 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);
+#endif /* CONFIG_ACPI_PV_SLEEP */
#endif /*CONFIG_ACPI_SLEEP*/
extern u8 x86_acpiid_to_apicid[];
diff -r ff0ef25ec204 -r c68699484a65 include/asm-x86_64/acpi.h
--- a/include/asm-x86_64/acpi.h Thu Jul 19 13:24:44 2007 +0100
+++ b/include/asm-x86_64/acpi.h Thu Jul 19 13:28:14 2007 +0100
@@ -153,6 +153,10 @@ 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);
+#endif /* CONFIG_ACPI_PV_SLEEP */
#endif /*CONFIG_ACPI_SLEEP*/
#define boot_cpu_physical_apicid boot_cpu_id
diff -r ff0ef25ec204 -r c68699484a65 include/xen/interface/platform.h
--- a/include/xen/interface/platform.h Thu Jul 19 13:24:44 2007 +0100
+++ b/include/xen/interface/platform.h Thu Jul 19 13:28:14 2007 +0100
@@ -153,6 +153,17 @@ 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_enter_acpi_sleep 51
+struct xenpf_enter_acpi_sleep {
+ /* IN variables */
+ uint16_t pm1a_cnt_val; /* PM1a control value. */
+ uint16_t pm1b_cnt_val; /* PM1b control value. */
+ uint32_t sleep_state; /* Which state to enter (Sn). */
+ uint32_t flags; /* Must be zero. */
+};
+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 +175,7 @@ struct xen_platform_op {
struct xenpf_microcode_update microcode;
struct xenpf_platform_quirk platform_quirk;
struct xenpf_firmware_info firmware_info;
+ struct xenpf_enter_acpi_sleep enter_acpi_sleep;
uint8_t pad[128];
} u;
};
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|