# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Date 1184846012 -3600
# Node ID 0d291a7c8c1f4a77a01c49f2e8cc90271ed19d37
# Parent f191aa8ac8ea52c3858202993b15f89dedc2e90c
[host s3] Retrieve necessary sleep information from plain-text ACPI
tables (FADT/FACS), and keep one hypercall remained for sleep
notification.
Signed-off-by: Ke Yu <ke.yu@xxxxxxxxx>
Signed-off-by: Kevin Tian <kevin.tian@xxxxxxxxx>
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
xen/arch/x86/acpi/boot.c | 93 +++++++++++++++++++++++++++++++
xen/arch/x86/acpi/power.c | 114 +++++++++++++++++++-------------------
xen/arch/x86/acpi/suspend.c | 3 -
xen/arch/x86/platform_hypercall.c | 14 ----
xen/drivers/acpi/tables.c | 3 +
xen/include/asm-x86/acpi.h | 20 +++++-
xen/include/public/platform.h | 25 +-------
xen/include/xen/acpi.h | 1
8 files changed, 177 insertions(+), 96 deletions(-)
diff -r f191aa8ac8ea -r 0d291a7c8c1f xen/arch/x86/acpi/boot.c
--- a/xen/arch/x86/acpi/boot.c Thu Jul 19 10:59:05 2007 +0100
+++ b/xen/arch/x86/acpi/boot.c Thu Jul 19 12:53:32 2007 +0100
@@ -369,6 +369,95 @@ extern u32 pmtmr_ioport;
extern u32 pmtmr_ioport;
#endif
+#ifdef CONFIG_ACPI_SLEEP
+/* Get pm1x_cnt and pm1x_evt information for ACPI sleep */
+static int __init
+acpi_fadt_parse_sleep_info(struct fadt_descriptor_rev2 *fadt)
+{
+ struct facs_descriptor_rev2 *facs = NULL;
+ uint64_t facs_pa;
+
+ if (fadt->revision >= FADT2_REVISION_ID) {
+ /* Sanity check on FADT Rev. 2 */
+ if ((fadt->xpm1a_cnt_blk.address_space_id !=
+ ACPI_ADR_SPACE_SYSTEM_IO) ||
+ (fadt->xpm1b_cnt_blk.address_space_id !=
+ ACPI_ADR_SPACE_SYSTEM_IO) ||
+ (fadt->xpm1a_evt_blk.address_space_id !=
+ ACPI_ADR_SPACE_SYSTEM_IO) ||
+ (fadt->xpm1b_evt_blk.address_space_id !=
+ ACPI_ADR_SPACE_SYSTEM_IO))
+ goto bad;
+
+ acpi_sinfo.pm1a_cnt = (uint16_t)fadt->xpm1a_cnt_blk.address;
+ acpi_sinfo.pm1b_cnt = (uint16_t)fadt->xpm1b_cnt_blk.address;
+ acpi_sinfo.pm1a_evt = (uint16_t)fadt->xpm1a_evt_blk.address;
+ acpi_sinfo.pm1b_evt = (uint16_t)fadt->xpm1b_evt_blk.address;
+ }
+
+ if (!acpi_sinfo.pm1a_cnt)
+ acpi_sinfo.pm1a_cnt = (uint16_t)fadt->V1_pm1a_cnt_blk;
+ if (!acpi_sinfo.pm1b_cnt)
+ acpi_sinfo.pm1b_cnt = (uint16_t)fadt->V1_pm1b_cnt_blk;
+ if (!acpi_sinfo.pm1a_evt)
+ acpi_sinfo.pm1a_evt = (uint16_t)fadt->V1_pm1a_evt_blk;
+ if (!acpi_sinfo.pm1b_evt)
+ acpi_sinfo.pm1b_evt = (uint16_t)fadt->V1_pm1b_evt_blk;
+
+ /* Now FACS... */
+ if (fadt->revision >= FADT2_REVISION_ID)
+ facs_pa = fadt->xfirmware_ctrl;
+ else
+ facs_pa = (uint64_t)fadt->V1_firmware_ctrl;
+
+ facs = (struct facs_descriptor_rev2 *)
+ __acpi_map_table(facs_pa, sizeof(struct facs_descriptor_rev2));
+ if (!facs)
+ goto bad;
+
+ if (strncmp(facs->signature, "FACS", 4)) {
+ printk(KERN_ERR PREFIX "Invalid FACS signature %s\n",
+ facs->signature);
+ goto bad;
+ }
+
+ if (facs->length < 24) {
+ printk(KERN_ERR PREFIX "Invalid FACS table length: 0x%x",
+ facs->length);
+ goto bad;
+ }
+
+ if (facs->length < 64)
+ printk(KERN_WARNING PREFIX
+ "FACS is shorter than ACPI spec allow: 0x%x",
+ facs->length);
+
+ if ((acpi_rsdp_rev < 2) ||
+ (facs->length < 32)) {
+ acpi_sinfo.wakeup_vector = facs_pa +
+ offsetof(struct facs_descriptor_rev2,
+ firmware_waking_vector);
+ acpi_sinfo.vector_width = 32;
+ } else {
+ acpi_sinfo.wakeup_vector = facs_pa +
+ offsetof(struct facs_descriptor_rev2,
+ xfirmware_waking_vector);
+ acpi_sinfo.vector_width = 64;
+ }
+
+ printk (KERN_INFO PREFIX
+ "ACPI SLEEP INFO: pm1x_cnt[%x,%x], pm1x_evt[%x,%x]\n"
+ " wakeup_vec[%"PRIx64"], vec_size[%x]\n",
+ acpi_sinfo.pm1a_cnt, acpi_sinfo.pm1b_cnt,
+ acpi_sinfo.pm1a_evt, acpi_sinfo.pm1b_cnt,
+ acpi_sinfo.wakeup_vector, acpi_sinfo.vector_width);
+ return 0;
+bad:
+ memset(&acpi_sinfo, 0, sizeof(acpi_sinfo));
+ return 0;
+}
+#endif
+
static int __init acpi_parse_fadt(unsigned long phys, unsigned long size)
{
struct fadt_descriptor_rev2 *fadt = NULL;
@@ -412,6 +501,10 @@ static int __init acpi_parse_fadt(unsign
if (pmtmr_ioport)
printk(KERN_INFO PREFIX "PM-Timer IO Port: %#x\n",
pmtmr_ioport);
+#endif
+
+#ifdef CONFIG_ACPI_SLEEP
+ acpi_fadt_parse_sleep_info(fadt);
#endif
return 0;
}
diff -r f191aa8ac8ea -r 0d291a7c8c1f xen/arch/x86/acpi/power.c
--- a/xen/arch/x86/acpi/power.c Thu Jul 19 10:59:05 2007 +0100
+++ b/xen/arch/x86/acpi/power.c Thu Jul 19 12:53:32 2007 +0100
@@ -28,20 +28,15 @@
#define pmprintk(_l, _f, _a...) printk(_l "<PM>" _f, ## _a )
-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 opt_acpi_sleep[20];
+string_param("acpi_sleep", opt_acpi_sleep);
+
+static u8 sleep_states[ACPI_S_STATE_COUNT];
+static DEFINE_SPINLOCK(pm_lock);
+
+struct acpi_sleep_info acpi_sinfo;
+
+void do_suspend_lowlevel(void);
static char *acpi_states[ACPI_S_STATE_COUNT] =
{
@@ -50,10 +45,6 @@ static char *acpi_states[ACPI_S_STATE_CO
[ACPI_STATE_S4] = "disk",
};
-unsigned long acpi_video_flags;
-unsigned long saved_videomode;
-
-/* XXX: Add suspend failure recover later */
static int device_power_down(void)
{
console_suspend();
@@ -100,8 +91,27 @@ static void thaw_domains(void)
domain_unpause(d);
}
+static void acpi_sleep_prepare(u32 state)
+{
+ void *wakeup_vector_va;
+
+ if ( state != ACPI_STATE_S3 )
+ return;
+
+ wakeup_vector_va = __acpi_map_table(
+ acpi_sinfo.wakeup_vector, sizeof(uint64_t));
+ if (acpi_sinfo.vector_width == 32)
+ *(uint32_t *)wakeup_vector_va =
+ (uint32_t)bootsym_phys(wakeup_start);
+ else
+ *(uint64_t *)wakeup_vector_va =
+ (uint64_t)bootsym_phys(wakeup_start);
+}
+
+static void acpi_sleep_post(u32 state) {}
+
/* Main interface to do xen specific suspend/resume */
-int enter_state(u32 state)
+static int enter_state(u32 state)
{
unsigned long flags;
int error;
@@ -122,6 +132,8 @@ int enter_state(u32 state)
pmprintk(XENLOG_INFO, "PM: Preparing system for %s sleep\n",
acpi_states[state]);
+
+ acpi_sleep_prepare(state);
local_irq_save(flags);
@@ -152,36 +164,14 @@ int enter_state(u32 state)
Done:
local_irq_restore(flags);
+ acpi_sleep_post(state);
+
if ( !hvm_cpu_up() )
BUG();
thaw_domains();
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;
}
/*
@@ -197,20 +187,23 @@ int set_acpi_sleep_info(struct xenpf_set
*/
int acpi_enter_sleep(struct xenpf_enter_acpi_sleep *sleep)
{
- if (!IS_PRIV(current->domain) || !acpi_sinfo.pm1a_cnt)
+ 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))
+ 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;
}
+ if ( sleep->flags )
+ return -EINVAL;
+
/* Write #1 */
- if (!(sleep->pm1a_cnt_val & ACPI_BITMASK_SLEEP_ENABLE))
+ if ( !(sleep->pm1a_cnt_val & ACPI_BITMASK_SLEEP_ENABLE) )
{
outw((u16)sleep->pm1a_cnt_val, acpi_sinfo.pm1a_cnt);
if (acpi_sinfo.pm1b_cnt)
@@ -222,8 +215,6 @@ int acpi_enter_sleep(struct xenpf_enter_
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);
}
@@ -247,7 +238,7 @@ acpi_status asmlinkage acpi_enter_sleep_
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);
@@ -255,12 +246,24 @@ acpi_status asmlinkage acpi_enter_sleep_
static int __init acpi_sleep_init(void)
{
- int i = 0;
+ int i;
+ char *p = opt_acpi_sleep;
+
+ while ( (p != NULL) && (*p != '\0') )
+ {
+ if ( !strncmp(p, "s3_bios", 7) )
+ acpi_video_flags |= 1;
+ if ( !strncmp(p, "s3_mode", 7) )
+ acpi_video_flags |= 2;
+ p = strchr(p, ',');
+ if ( p != NULL )
+ p += strspn(p, ", \t");
+ }
pmprintk(XENLOG_INFO, "ACPI (supports");
- for (i = 0; i < ACPI_S_STATE_COUNT; i++)
- {
- if (i == ACPI_STATE_S3)
+ for ( i = 0; i < ACPI_S_STATE_COUNT; i++ )
+ {
+ if ( i == ACPI_STATE_S3 )
{
sleep_states[i] = 1;
printk(" S%d", i);
@@ -269,6 +272,7 @@ static int __init acpi_sleep_init(void)
sleep_states[i] = 0;
}
printk(")\n");
+
return 0;
}
__initcall(acpi_sleep_init);
diff -r f191aa8ac8ea -r 0d291a7c8c1f xen/arch/x86/acpi/suspend.c
--- a/xen/arch/x86/acpi/suspend.c Thu Jul 19 10:59:05 2007 +0100
+++ b/xen/arch/x86/acpi/suspend.c Thu Jul 19 12:53:32 2007 +0100
@@ -35,9 +35,6 @@ 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 f191aa8ac8ea -r 0d291a7c8c1f xen/arch/x86/platform_hypercall.c
--- a/xen/arch/x86/platform_hypercall.c Thu Jul 19 10:59:05 2007 +0100
+++ b/xen/arch/x86/platform_hypercall.c Thu Jul 19 12:53:32 2007 +0100
@@ -248,21 +248,9 @@ ret_t do_platform_op(XEN_GUEST_HANDLE(xe
}
break;
-#if 0
- 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;
-#endif
+ break;
default:
ret = -ENOSYS;
diff -r f191aa8ac8ea -r 0d291a7c8c1f xen/drivers/acpi/tables.c
--- a/xen/drivers/acpi/tables.c Thu Jul 19 10:59:05 2007 +0100
+++ b/xen/drivers/acpi/tables.c Thu Jul 19 12:53:32 2007 +0100
@@ -73,6 +73,7 @@ struct acpi_table_sdt {
static unsigned long sdt_pa; /* Physical Address */
static unsigned long sdt_count; /* Table count */
+unsigned char acpi_rsdp_rev;
static struct acpi_table_sdt sdt_entry[ACPI_MAX_TABLES] __initdata;
@@ -598,6 +599,8 @@ int __init acpi_table_init(void)
"RSDP (v%3.3d %6.6s ) @ 0x%p\n",
rsdp->revision, rsdp->oem_id, (void *)rsdp_phys);
+ acpi_rsdp_rev = rsdp->revision;
+
if (rsdp->revision < 2)
result =
acpi_table_compute_checksum(rsdp,
diff -r f191aa8ac8ea -r 0d291a7c8c1f xen/include/asm-x86/acpi.h
--- a/xen/include/asm-x86/acpi.h Thu Jul 19 10:59:05 2007 +0100
+++ b/xen/include/asm-x86/acpi.h Thu Jul 19 12:53:32 2007 +0100
@@ -173,15 +173,25 @@ extern unsigned long acpi_wakeup_address
/* early initialization routine */
extern void acpi_reserve_bootmem(void);
-extern unsigned long acpi_video_flags;
-extern unsigned long saved_videomode;
-struct xenpf_set_acpi_sleep;
+extern struct acpi_sleep_info acpi_sinfo;
+#define acpi_video_flags bootsym(video_flags)
struct xenpf_enter_acpi_sleep;
-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 /*CONFIG_ACPI_SLEEP*/
+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;
+ uint64_t wakeup_vector;
+ uint32_t vector_width;
+};
+
+#endif /* CONFIG_ACPI_SLEEP */
extern u8 x86_acpiid_to_apicid[];
#define MAX_LOCAL_APIC 256
diff -r f191aa8ac8ea -r 0d291a7c8c1f xen/include/public/platform.h
--- a/xen/include/public/platform.h Thu Jul 19 10:59:05 2007 +0100
+++ b/xen/include/public/platform.h Thu Jul 19 12:53:32 2007 +0100
@@ -153,27 +153,13 @@ 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
+#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 */
+ 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);
@@ -189,7 +175,6 @@ 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 f191aa8ac8ea -r 0d291a7c8c1f xen/include/xen/acpi.h
--- a/xen/include/xen/acpi.h Thu Jul 19 10:59:05 2007 +0100
+++ b/xen/include/xen/acpi.h Thu Jul 19 12:53:32 2007 +0100
@@ -534,5 +534,6 @@ static inline int acpi_get_pxm(acpi_hand
#endif
extern int pnpacpi_disabled;
+extern unsigned char acpi_rsdp_rev;
#endif /*_LINUX_ACPI_H*/
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|