All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 4/4] Enable ACPI sleep in XenLinux
@ 2007-07-19 10:04 Tian, Kevin
  2007-07-19 10:29 ` Keir Fraser
  0 siblings, 1 reply; 6+ messages in thread
From: Tian, Kevin @ 2007-07-19 10:04 UTC (permalink / raw)
  To: Keir Fraser; +Cc: xen-devel

[-- Attachment #1: Type: text/plain, Size: 14106 bytes --]

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 7c8ff2db2e59 arch/i386/Kconfig
--- a/arch/i386/Kconfig	Thu Jul 19 13:29:29 2007 +0800
+++ b/arch/i386/Kconfig	Thu Jul 19 13:29:29 2007 +0800
@@ -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 7c8ff2db2e59 arch/i386/kernel/acpi/sleep-xen.c
--- a/arch/i386/kernel/acpi/sleep-xen.c	Thu Jul 19 13:29:29 2007 +0800
+++ b/arch/i386/kernel/acpi/sleep-xen.c	Thu Jul 19 13:29:29 2007 +0800
@@ -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,30 @@ 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>
+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 7c8ff2db2e59 arch/i386/kernel/time-xen.c
--- a/arch/i386/kernel/time-xen.c	Thu Jul 19 13:29:29 2007 +0800
+++ b/arch/i386/kernel/time-xen.c	Thu Jul 19 13:29:29 2007 +0800
@@ -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 7c8ff2db2e59 arch/i386/power/cpu.c
--- a/arch/i386/power/cpu.c	Thu Jul 19 13:29:29 2007 +0800
+++ b/arch/i386/power/cpu.c	Thu Jul 19 13:29:29 2007 +0800
@@ -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(&current->active_mm->context);	/* This does lldt */
 
diff -r 7c8ff2db2e59 arch/x86_64/Kconfig
--- a/arch/x86_64/Kconfig	Thu Jul 19 13:29:29 2007 +0800
+++ b/arch/x86_64/Kconfig	Thu Jul 19 13:29:29 2007 +0800
@@ -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 7c8ff2db2e59 arch/x86_64/kernel/acpi/Makefile
--- a/arch/x86_64/kernel/acpi/Makefile	Thu Jul 19 13:29:29 2007 +0800
+++ b/arch/x86_64/kernel/acpi/Makefile	Thu Jul 19 13:29:29 2007 +0800
@@ -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 7c8ff2db2e59 arch/x86_64/kernel/acpi/sleep-xen.c
--- a/arch/x86_64/kernel/acpi/sleep-xen.c	Thu Jul 19 13:29:29 2007
+0800
+++ b/arch/x86_64/kernel/acpi/sleep-xen.c	Thu Jul 19 13:29:29 2007
+0800
@@ -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,37 @@ 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>
+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 */
 
diff -r 7c8ff2db2e59 arch/x86_64/kernel/head-xen.S
--- a/arch/x86_64/kernel/head-xen.S	Thu Jul 19 13:29:29 2007 +0800
+++ b/arch/x86_64/kernel/head-xen.S	Thu Jul 19 13:29:29 2007 +0800
@@ -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 7c8ff2db2e59 arch/x86_64/kernel/suspend.c
--- a/arch/x86_64/kernel/suspend.c	Thu Jul 19 13:29:29 2007 +0800
+++ b/arch/x86_64/kernel/suspend.c	Thu Jul 19 13:29:29 2007 +0800
@@ -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 7c8ff2db2e59 buildconfigs/linux-defconfig_xen_x86_32
--- a/buildconfigs/linux-defconfig_xen_x86_32	Thu Jul 19 13:29:29 2007
+0800
+++ b/buildconfigs/linux-defconfig_xen_x86_32	Thu Jul 19 13:29:29 2007
+0800
@@ -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 7c8ff2db2e59 buildconfigs/linux-defconfig_xen_x86_64
--- a/buildconfigs/linux-defconfig_xen_x86_64	Thu Jul 19 13:29:29 2007
+0800
+++ b/buildconfigs/linux-defconfig_xen_x86_64	Thu Jul 19 13:29:29 2007
+0800
@@ -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 7c8ff2db2e59 drivers/acpi/Kconfig
--- a/drivers/acpi/Kconfig	Thu Jul 19 13:29:29 2007 +0800
+++ b/drivers/acpi/Kconfig	Thu Jul 19 13:29:29 2007 +0800
@@ -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 7c8ff2db2e59 drivers/acpi/hardware/hwsleep.c
--- a/drivers/acpi/hardware/hwsleep.c	Thu Jul 19 13:29:29 2007 +0800
+++ b/drivers/acpi/hardware/hwsleep.c	Thu Jul 19 13:29:29 2007 +0800
@@ -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 7c8ff2db2e59 drivers/acpi/sleep/main.c
--- a/drivers/acpi/sleep/main.c	Thu Jul 19 13:29:29 2007 +0800
+++ b/drivers/acpi/sleep/main.c	Thu Jul 19 15:30:38 2007 +0800
@@ -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 7c8ff2db2e59 drivers/acpi/sleep/poweroff.c
--- a/drivers/acpi/sleep/poweroff.c	Thu Jul 19 13:29:29 2007 +0800
+++ b/drivers/acpi/sleep/poweroff.c	Thu Jul 19 15:31:45 2007 +0800
@@ -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 7c8ff2db2e59 include/asm-i386/acpi.h
--- a/include/asm-i386/acpi.h	Thu Jul 19 13:29:29 2007 +0800
+++ b/include/asm-i386/acpi.h	Thu Jul 19 13:29:29 2007 +0800
@@ -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 7c8ff2db2e59 include/asm-x86_64/acpi.h
--- a/include/asm-x86_64/acpi.h	Thu Jul 19 13:29:29 2007 +0800
+++ b/include/asm-x86_64/acpi.h	Thu Jul 19 13:29:29 2007 +0800
@@ -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 7c8ff2db2e59 include/xen/interface/platform.h
--- a/include/xen/interface/platform.h	Thu Jul 19 13:29:29 2007 +0800
+++ b/include/xen/interface/platform.h	Thu Jul 19 13:29:29 2007 +0800
@@ -153,6 +153,18 @@ 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;
+    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 +176,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;
 };

[-- Attachment #2: enable_linux_acpi_sleep.patch --]
[-- Type: application/octet-stream, Size: 14105 bytes --]

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 7c8ff2db2e59 arch/i386/Kconfig
--- a/arch/i386/Kconfig	Thu Jul 19 13:29:29 2007 +0800
+++ b/arch/i386/Kconfig	Thu Jul 19 13:29:29 2007 +0800
@@ -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 7c8ff2db2e59 arch/i386/kernel/acpi/sleep-xen.c
--- a/arch/i386/kernel/acpi/sleep-xen.c	Thu Jul 19 13:29:29 2007 +0800
+++ b/arch/i386/kernel/acpi/sleep-xen.c	Thu Jul 19 13:29:29 2007 +0800
@@ -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,30 @@ 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>
+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 7c8ff2db2e59 arch/i386/kernel/time-xen.c
--- a/arch/i386/kernel/time-xen.c	Thu Jul 19 13:29:29 2007 +0800
+++ b/arch/i386/kernel/time-xen.c	Thu Jul 19 13:29:29 2007 +0800
@@ -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 7c8ff2db2e59 arch/i386/power/cpu.c
--- a/arch/i386/power/cpu.c	Thu Jul 19 13:29:29 2007 +0800
+++ b/arch/i386/power/cpu.c	Thu Jul 19 13:29:29 2007 +0800
@@ -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(&current->active_mm->context);	/* This does lldt */
 
diff -r 7c8ff2db2e59 arch/x86_64/Kconfig
--- a/arch/x86_64/Kconfig	Thu Jul 19 13:29:29 2007 +0800
+++ b/arch/x86_64/Kconfig	Thu Jul 19 13:29:29 2007 +0800
@@ -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 7c8ff2db2e59 arch/x86_64/kernel/acpi/Makefile
--- a/arch/x86_64/kernel/acpi/Makefile	Thu Jul 19 13:29:29 2007 +0800
+++ b/arch/x86_64/kernel/acpi/Makefile	Thu Jul 19 13:29:29 2007 +0800
@@ -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 7c8ff2db2e59 arch/x86_64/kernel/acpi/sleep-xen.c
--- a/arch/x86_64/kernel/acpi/sleep-xen.c	Thu Jul 19 13:29:29 2007 +0800
+++ b/arch/x86_64/kernel/acpi/sleep-xen.c	Thu Jul 19 13:29:29 2007 +0800
@@ -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,37 @@ 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>
+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 */
 
diff -r 7c8ff2db2e59 arch/x86_64/kernel/head-xen.S
--- a/arch/x86_64/kernel/head-xen.S	Thu Jul 19 13:29:29 2007 +0800
+++ b/arch/x86_64/kernel/head-xen.S	Thu Jul 19 13:29:29 2007 +0800
@@ -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 7c8ff2db2e59 arch/x86_64/kernel/suspend.c
--- a/arch/x86_64/kernel/suspend.c	Thu Jul 19 13:29:29 2007 +0800
+++ b/arch/x86_64/kernel/suspend.c	Thu Jul 19 13:29:29 2007 +0800
@@ -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 7c8ff2db2e59 buildconfigs/linux-defconfig_xen_x86_32
--- a/buildconfigs/linux-defconfig_xen_x86_32	Thu Jul 19 13:29:29 2007 +0800
+++ b/buildconfigs/linux-defconfig_xen_x86_32	Thu Jul 19 13:29:29 2007 +0800
@@ -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 7c8ff2db2e59 buildconfigs/linux-defconfig_xen_x86_64
--- a/buildconfigs/linux-defconfig_xen_x86_64	Thu Jul 19 13:29:29 2007 +0800
+++ b/buildconfigs/linux-defconfig_xen_x86_64	Thu Jul 19 13:29:29 2007 +0800
@@ -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 7c8ff2db2e59 drivers/acpi/Kconfig
--- a/drivers/acpi/Kconfig	Thu Jul 19 13:29:29 2007 +0800
+++ b/drivers/acpi/Kconfig	Thu Jul 19 13:29:29 2007 +0800
@@ -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 7c8ff2db2e59 drivers/acpi/hardware/hwsleep.c
--- a/drivers/acpi/hardware/hwsleep.c	Thu Jul 19 13:29:29 2007 +0800
+++ b/drivers/acpi/hardware/hwsleep.c	Thu Jul 19 13:29:29 2007 +0800
@@ -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 7c8ff2db2e59 drivers/acpi/sleep/main.c
--- a/drivers/acpi/sleep/main.c	Thu Jul 19 13:29:29 2007 +0800
+++ b/drivers/acpi/sleep/main.c	Thu Jul 19 15:30:38 2007 +0800
@@ -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 7c8ff2db2e59 drivers/acpi/sleep/poweroff.c
--- a/drivers/acpi/sleep/poweroff.c	Thu Jul 19 13:29:29 2007 +0800
+++ b/drivers/acpi/sleep/poweroff.c	Thu Jul 19 15:31:45 2007 +0800
@@ -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 7c8ff2db2e59 include/asm-i386/acpi.h
--- a/include/asm-i386/acpi.h	Thu Jul 19 13:29:29 2007 +0800
+++ b/include/asm-i386/acpi.h	Thu Jul 19 13:29:29 2007 +0800
@@ -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 7c8ff2db2e59 include/asm-x86_64/acpi.h
--- a/include/asm-x86_64/acpi.h	Thu Jul 19 13:29:29 2007 +0800
+++ b/include/asm-x86_64/acpi.h	Thu Jul 19 13:29:29 2007 +0800
@@ -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 7c8ff2db2e59 include/xen/interface/platform.h
--- a/include/xen/interface/platform.h	Thu Jul 19 13:29:29 2007 +0800
+++ b/include/xen/interface/platform.h	Thu Jul 19 13:29:29 2007 +0800
@@ -153,6 +153,18 @@ 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;
+    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 +176,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;
 };

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2007-07-19 13:44 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-07-19 10:04 [PATCH 4/4] Enable ACPI sleep in XenLinux Tian, Kevin
2007-07-19 10:29 ` Keir Fraser
2007-07-19 13:12   ` Tian, Kevin
2007-07-19 13:17     ` Keir Fraser
2007-07-19 13:24       ` Tian, Kevin
2007-07-19 13:44       ` Alan Cox

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.