Define pm interfaces between dom0 and Xen, with one
to register sleep info and the other for triggering
sleep state. "acpi_sleep=s3_mode/s3_bios" option is
also supported by piggybacking video flag/mode to
xen at trigger point.
Signed-off-by Ke Yu <ke.yu@xxxxxxxxx>
Signed-off-by Kevin Tian <kevin.tian@xxxxxxxxx>
diff -r 50e0cc2aee5e xen/arch/x86/acpi/power.c
--- a/xen/arch/x86/acpi/power.c Tue Jun 26 20:28:13 2007 -0400
+++ b/xen/arch/x86/acpi/power.c Tue Jun 26 20:37:48 2007 -0400
@@ -10,6 +10,7 @@
* Slimmed with Xen specific support.
*/
+#include <xen/config.h>
#include <asm/io.h>
#define CONFIG_ACPI_SLEEP
#include <asm/acpi.h>
@@ -28,6 +29,16 @@ u8 sleep_states[ACPI_S_STATE_COUNT];
u8 sleep_states[ACPI_S_STATE_COUNT];
DEFINE_SPINLOCK(pm_lock);
+struct acpi_sleep_info {
+ uint16_t pm1a_cnt;
+ uint16_t pm1b_cnt;
+ uint16_t pm1a_evt;
+ uint16_t pm1b_evt;
+ uint16_t pm1a_cnt_val;
+ uint16_t pm1b_cnt_val;
+ uint32_t sleep_state;
+} acpi_sinfo;
+
extern void do_suspend_lowlevel(void);
static char *acpi_states[ACPI_S_STATE_COUNT] =
@@ -129,6 +140,99 @@ int enter_state(u32 state)
spin_unlock(&pm_lock);
return error;
+}
+
+/*
+ * Xen just requires address of pm1x_cnt, and ACPI interpreter
+ * is still kept in dom0. Address of xen wakeup stub will be
+ * returned, and then dom0 writes that address to FACS.
+ */
+int set_acpi_sleep_info(struct xenpf_set_acpi_sleep *info)
+{
+ if (acpi_sinfo.pm1a_cnt)
+ pmprintk(XENLOG_WARNING, "Multiple setting on acpi sleep
info\n");
+
+ acpi_sinfo.pm1a_cnt = info->pm1a_cnt_port;
+ acpi_sinfo.pm1b_cnt = info->pm1b_cnt_port;
+ acpi_sinfo.pm1a_evt = info->pm1a_evt_port;
+ acpi_sinfo.pm1b_evt = info->pm1b_evt_port;
+ info->xen_waking_vec = (uint64_t)bootsym_phys(wakeup_start);
+
+ pmprintk(XENLOG_INFO, "pm1a[%x],pm1b[%x],pm1a_e[%x],pm1b_e[%x]"
+ "wake[%"PRIx64"]",
+ acpi_sinfo.pm1a_cnt, acpi_sinfo.pm1b_cnt,
+ acpi_sinfo.pm1a_evt, acpi_sinfo.pm1b_evt,
+ info->xen_waking_vec);
+ return 0;
+}
+
+/*
+ * Dom0 issues this hypercall in place of writing pm1a_cnt. Xen then
+ * takes over the control and put the system into sleep state really.
+ * Also video flags and mode are passed here, in case user may use
+ * "acpi_sleep=***" for video resume.
+ *
+ * Guest may issue a two-phases write to PM1x_CNT, to work
+ * around poorly implemented hardware. It's better to keep
+ * this logic here. Two writes can be differentiated by
+ * enable bit setting.
+ */
+int acpi_enter_sleep(struct xenpf_enter_acpi_sleep *sleep)
+{
+ if (!IS_PRIV(current->domain) || !acpi_sinfo.pm1a_cnt)
+ return -EPERM;
+
+ /* Sanity check */
+ if (acpi_sinfo.pm1b_cnt_val &&
+ ((sleep->pm1a_cnt_val ^ sleep->pm1b_cnt_val) &
+ ACPI_BITMASK_SLEEP_ENABLE))
+ {
+ pmprintk(XENLOG_ERR, "Mismatched pm1a/pm1b setting\n");
+ return -EINVAL;
+ }
+
+ /* Write #1 */
+ if (!(sleep->pm1a_cnt_val & ACPI_BITMASK_SLEEP_ENABLE))
+ {
+ outw((u16)sleep->pm1a_cnt_val, acpi_sinfo.pm1a_cnt);
+ if (acpi_sinfo.pm1b_cnt)
+ outw((u16)sleep->pm1b_cnt_val, acpi_sinfo.pm1b_cnt);
+ return 0;
+ }
+
+ /* Write #2 */
+ acpi_sinfo.pm1a_cnt_val = sleep->pm1a_cnt_val;
+ acpi_sinfo.pm1b_cnt_val = sleep->pm1b_cnt_val;
+ acpi_sinfo.sleep_state = sleep->sleep_state;
+ acpi_video_flags = sleep->video_flags;
+ saved_videomode = sleep->video_mode;
+
+ return enter_state(acpi_sinfo.sleep_state);
+}
+
+static int acpi_get_wake_status(void)
+{
+ uint16_t val;
+
+ /* Wake status is the 15th bit of PM1 status register. (ACPI spec
3.0) */
+ val = inw(acpi_sinfo.pm1a_evt) | inw(acpi_sinfo.pm1b_evt);
+ val &= ACPI_BITMASK_WAKE_STATUS;
+ val >>= ACPI_BITPOSITION_WAKE_STATUS;
+ return val;
+}
+
+/* System is really put into sleep state by this stub */
+acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
+{
+ ACPI_FLUSH_CPU_CACHE();
+
+ outw((u16)acpi_sinfo.pm1a_cnt_val, acpi_sinfo.pm1a_cnt);
+ if (acpi_sinfo.pm1b_cnt)
+ outw((u16)acpi_sinfo.pm1b_cnt_val, acpi_sinfo.pm1b_cnt);
+
+ /* Wait until we enter sleep state, and spin until we wake */
+ while (!acpi_get_wake_status());
+ return_ACPI_STATUS(AE_OK);
}
static int __init acpi_sleep_init(void)
diff -r 50e0cc2aee5e xen/arch/x86/acpi/suspend.c
--- a/xen/arch/x86/acpi/suspend.c Tue Jun 26 20:28:13 2007 -0400
+++ b/xen/arch/x86/acpi/suspend.c Tue Jun 26 20:37:48 2007 -0400
@@ -35,6 +35,9 @@ void save_rest_processor_state(void)
rdmsrl(MSR_CSTAR, saved_cstar);
rdmsrl(MSR_LSTAR, saved_lstar);
#endif
+
+ bootsym(video_flags) = acpi_video_flags;
+ bootsym(video_mode) = saved_videomode;
}
#define loaddebug(_v,_reg) \
diff -r 50e0cc2aee5e xen/arch/x86/platform_hypercall.c
--- a/xen/arch/x86/platform_hypercall.c Tue Jun 26 20:28:13 2007 -0400
+++ b/xen/arch/x86/platform_hypercall.c Tue Jun 26 20:37:48 2007 -0400
@@ -18,6 +18,7 @@
#include <xen/console.h>
#include <xen/iocap.h>
#include <xen/guest_access.h>
+#include <xen/acpi.h>
#include <asm/current.h>
#include <public/platform.h>
#include <asm/edd.h>
@@ -247,6 +248,20 @@ ret_t do_platform_op(XEN_GUEST_HANDLE(xe
}
break;
+ case XENPF_set_acpi_sleep:
+ {
+ ret = set_acpi_sleep_info(&op->u.set_acpi_sleep);
+ if (!ret && copy_to_guest(u_xenpf_op, op, 1))
+ ret = -EFAULT;
+ }
+ break;
+
+ case XENPF_enter_acpi_sleep:
+ {
+ ret = acpi_enter_sleep(&op->u.enter_acpi_sleep);
+ }
+ break;
+
default:
ret = -ENOSYS;
break;
diff -r 50e0cc2aee5e xen/include/asm-x86/config.h
--- a/xen/include/asm-x86/config.h Tue Jun 26 20:28:13 2007 -0400
+++ b/xen/include/asm-x86/config.h Tue Jun 26 20:37:48 2007 -0400
@@ -96,6 +96,8 @@ extern char trampoline_realmode_entry[];
extern char trampoline_realmode_entry[];
extern unsigned int trampoline_xen_phys_start;
extern unsigned char trampoline_cpu_started;
+extern char wakeup_start[];
+extern unsigned int video_mode, video_flags;
#endif
#if defined(__x86_64__)
diff -r 50e0cc2aee5e xen/include/public/platform.h
--- a/xen/include/public/platform.h Tue Jun 26 20:28:13 2007 -0400
+++ b/xen/include/public/platform.h Tue Jun 26 20:38:34 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;
};
diff -r 50e0cc2aee5e xen/include/xen/acpi.h
--- a/xen/include/xen/acpi.h Tue Jun 26 20:28:13 2007 -0400
+++ b/xen/include/xen/acpi.h Tue Jun 26 20:37:48 2007 -0400
@@ -535,4 +535,15 @@ static inline int acpi_get_pxm(acpi_hand
extern int pnpacpi_disabled;
+#include <public/platform.h>
+#ifdef COMPAT
+#define xenpf_set_acpi_sleep compat_pf_set_acpi_sleep
+#define xenpf_enter_acpi_sleep compat_pf_enter_acpi_sleep
+#endif /* COMPAT */
+
+extern unsigned long acpi_video_flags;
+extern unsigned long saved_videomode;
+extern int set_acpi_sleep_info(struct xenpf_set_acpi_sleep *info);
+extern int acpi_enter_sleep(struct xenpf_enter_acpi_sleep *sleep);
+extern int acpi_enter_state(u32 state);
#endif /*_LINUX_ACPI_H*/
acpi_sleep_interface.patch
Description: acpi_sleep_interface.patch
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|