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@intel.com> Signed-off-by Kevin Tian <kevin.tian@intel.com> diff -r e1f74a5a09cb xen/arch/x86/acpi/boot.c --- a/xen/arch/x86/acpi/boot.c Wed Jul 18 13:56:21 2007 +0100 +++ b/xen/arch/x86/acpi/boot.c Thu Jul 19 14:35:45 2007 +0800 @@ -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 e1f74a5a09cb xen/arch/x86/acpi/power.c --- a/xen/arch/x86/acpi/power.c Wed Jul 18 13:56:21 2007 +0100 +++ b/xen/arch/x86/acpi/power.c Thu Jul 19 14:34:37 2007 +0800 @@ -31,15 +31,7 @@ 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; +struct acpi_sleep_info acpi_sinfo; extern void do_suspend_lowlevel(void); @@ -52,6 +44,7 @@ static char *acpi_states[ACPI_S_STATE_CO unsigned long acpi_video_flags; unsigned long saved_videomode; +void *wakeup_vector_va; /* XXX: Add suspend failure recover later */ static int device_power_down(void) @@ -100,6 +93,23 @@ static void thaw_domains(void) domain_unpause(d); } +static void acpi_sleep_prepare(u32 state) +{ + if (state == ACPI_STATE_S3) + { + 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) { @@ -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; } /* diff -r e1f74a5a09cb xen/arch/x86/platform_hypercall.c --- a/xen/arch/x86/platform_hypercall.c Wed Jul 18 13:56:21 2007 +0100 +++ b/xen/arch/x86/platform_hypercall.c Thu Jul 19 13:29:01 2007 +0800 @@ -248,21 +248,11 @@ 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 default: ret = -ENOSYS; diff -r e1f74a5a09cb xen/drivers/acpi/tables.c --- a/xen/drivers/acpi/tables.c Wed Jul 18 13:56:21 2007 +0100 +++ b/xen/drivers/acpi/tables.c Thu Jul 19 13:29:01 2007 +0800 @@ -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 e1f74a5a09cb xen/include/asm-x86/acpi.h --- a/xen/include/asm-x86/acpi.h Wed Jul 18 13:56:21 2007 +0100 +++ b/xen/include/asm-x86/acpi.h Thu Jul 19 13:29:01 2007 +0800 @@ -173,14 +173,29 @@ extern unsigned long acpi_wakeup_address /* early initialization routine */ extern void acpi_reserve_bootmem(void); +#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 struct acpi_sleep_info acpi_sinfo; extern unsigned long acpi_video_flags; extern unsigned long saved_videomode; -struct xenpf_set_acpi_sleep; 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); +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[]; diff -r e1f74a5a09cb xen/include/public/platform.h --- a/xen/include/public/platform.h Wed Jul 18 13:56:21 2007 +0100 +++ b/xen/include/public/platform.h Thu Jul 19 13:29:01 2007 +0800 @@ -153,20 +153,7 @@ 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; @@ -189,7 +176,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 e1f74a5a09cb xen/include/xen/acpi.h --- a/xen/include/xen/acpi.h Wed Jul 18 13:56:21 2007 +0100 +++ b/xen/include/xen/acpi.h Thu Jul 19 13:29:01 2007 +0800 @@ -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-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel