[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH 2/10] PM interface between dom0 and Xen


  • To: "Keir Fraser" <keir@xxxxxxxxxxxxx>
  • From: "Tian, Kevin" <kevin.tian@xxxxxxxxx>
  • Date: Wed, 27 Jun 2007 21:30:52 +0800
  • Cc: xen-devel@xxxxxxxxxxxxxxxxxxx
  • Delivery-date: Wed, 27 Jun 2007 06:29:02 -0700
  • List-id: Xen developer discussion <xen-devel.lists.xensource.com>
  • Thread-index: Ace4v14xFx0B/3G7T4i9ErPfdBh/Eg==
  • Thread-topic: [PATCH 2/10] PM interface between dom0 and Xen

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*/

Attachment: acpi_sleep_interface.patch
Description: acpi_sleep_interface.patch

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

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.