WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

[Xen-devel] [PATCH 4/12] PM interface between dom0 and Xen

To: "Keir Fraser" <Keir.Fraser@xxxxxxxxxxxx>, "Ian Pratt" <m+Ian.Pratt@xxxxxxxxxxxx>, <xen-devel@xxxxxxxxxxxxxxxxxxx>
Subject: [Xen-devel] [PATCH 4/12] PM interface between dom0 and Xen
From: "Tian, Kevin" <kevin.tian@xxxxxxxxx>
Date: Wed, 14 Feb 2007 17:14:45 +0800
Cc: "Yu, Ke" <ke.yu@xxxxxxxxx>
Delivery-date: Wed, 14 Feb 2007 01:14:24 -0800
Envelope-to: www-data@xxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
Thread-index: AcdQGJGL5R15b5kyT6WwnnI9EhO1Pg==
Thread-topic: [PATCH 4/12] 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 169fcd328fd9 xen/arch/x86/acpi/power.c
--- a/xen/arch/x86/acpi/power.c Tue Feb 13 17:30:14 2007 +0800
+++ b/xen/arch/x86/acpi/power.c Tue Feb 13 17:30:34 2007 +0800
@@ -27,6 +27,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] =
@@ -36,7 +46,7 @@ static char *acpi_states[ACPI_S_STATE_CO
     [ACPI_STATE_S4] = "disk",
 };
 
-/* Add suspend failure recover later */
+/* XXX: Add suspend failure recover later */
 static int device_power_down(void)
 {
     console_suspend();
@@ -65,6 +75,7 @@ static void device_power_up(void)
     console_resume();
 }
 
+/* Main interface to do xen specific suspend/resume */
 int enter_state(u32 state)
 {
     struct domain *d;
@@ -92,7 +103,6 @@ int enter_state(u32 state)
 
     ACPI_FLUSH_CPU_CACHE();
 
-    /* Do arch specific saving of state. */
     if (state > ACPI_STATE_S1) {
         error = acpi_save_state_mem();
         if (error)
@@ -105,7 +115,7 @@ int enter_state(u32 state)
             break;
         default:
             error = -EINVAL;
-            goto Powerup;
+            break;
     }
 
     printk("Back to C!\n");
@@ -125,6 +135,97 @@ 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)
+        printk(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)__pa(acpi_wakeup_address);
+
+    printk(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 (!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)) {
+        printk(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 169fcd328fd9 xen/arch/x86/platform_hypercall.c
--- a/xen/arch/x86/platform_hypercall.c Tue Feb 13 17:30:14 2007 +0800
+++ b/xen/arch/x86/platform_hypercall.c Tue Feb 13 17:30:21 2007 +0800
@@ -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/mtrr.h>
@@ -151,6 +152,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 169fcd328fd9 xen/include/public/platform.h
--- a/xen/include/public/platform.h     Tue Feb 13 17:30:14 2007 +0800
+++ b/xen/include/public/platform.h     Tue Feb 13 17:30:21 2007 +0800
@@ -114,6 +114,31 @@ typedef struct xenpf_platform_quirk xenp
 typedef struct xenpf_platform_quirk xenpf_platform_quirk_t;
 DEFINE_XEN_GUEST_HANDLE(xenpf_platform_quirk_t);
 
+#define XENPF_set_acpi_sleep      40
+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    41
+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 */
@@ -124,6 +149,8 @@ struct xen_platform_op {
         struct xenpf_read_memtype      read_memtype;
         struct xenpf_microcode_update  microcode;
         struct xenpf_platform_quirk    platform_quirk;
+        struct xenpf_set_acpi_sleep    set_acpi_sleep;
+        struct xenpf_enter_acpi_sleep  enter_acpi_sleep;
         uint8_t                        pad[128];
     } u;
 };
diff -r 169fcd328fd9 xen/include/xen/acpi.h
--- a/xen/include/xen/acpi.h    Tue Feb 13 17:30:14 2007 +0800
+++ b/xen/include/xen/acpi.h    Tue Feb 13 17:30:21 2007 +0800
@@ -535,4 +535,10 @@ static inline int acpi_get_pxm(acpi_hand
 
 extern int pnpacpi_disabled;
 
+#include <public/platform.h>
+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
<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-devel] [PATCH 4/12] PM interface between dom0 and Xen, Tian, Kevin <=