[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@intel.com>
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
This commit is contained in:
kfraser@localhost.localdomain committed 2007-07-19 12:53:32 +01:00
1 parent d17ac42f37
commit d3faf9badf
8 files changed
+174 -93

No files matched your search

+93
View File
@@ -369,6 +369,95 @@ static int __init acpi_parse_hpet(unsigned long phys, unsigned long size)
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;
@@ -413,6 +502,10 @@ static int __init acpi_parse_fadt(unsigned long phys, unsigned long size)
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;
}
+56 -52
View File
@@ -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);
static char opt_acpi_sleep[20];
string_param("acpi_sleep", opt_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;
} acpi_sinfo;
static u8 sleep_states[ACPI_S_STATE_COUNT];
static DEFINE_SPINLOCK(pm_lock);
extern void do_suspend_lowlevel(void);
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_COUNT] =
[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;
@@ -123,6 +133,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);
if ((error = device_power_down()))
@@ -152,6 +164,8 @@ int enter_state(u32 state)
Done:
local_irq_restore(flags);
acpi_sleep_post(state);
if ( !hvm_cpu_up() )
BUG();
@@ -160,30 +174,6 @@ int enter_state(u32 state)
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.
@@ -197,20 +187,23 @@ int set_acpi_sleep_info(struct xenpf_set_acpi_sleep *info)
*/
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_sleep *sleep)
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_state(u8 sleep_state)
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_state(u8 sleep_state)
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++)
for ( i = 0; i < ACPI_S_STATE_COUNT; i++ )
{
if (i == ACPI_STATE_S3)
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);
-3
View File
@@ -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) \
+1 -13
View File
@@ -248,21 +248,9 @@ ret_t do_platform_op(XEN_GUEST_HANDLE(xen_platform_op_t) u_xenpf_op)
}
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;
+3
View File
@@ -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,
+15 -5
View File
@@ -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
+5 -20
View File
@@ -153,27 +153,13 @@ struct xenpf_firmware_info {
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;
+1
View File
@@ -534,5 +534,6 @@ static inline int acpi_get_pxm(acpi_handle handle)
#endif
extern int pnpacpi_disabled;
extern unsigned char acpi_rsdp_rev;
#endif /*_LINUX_ACPI_H*/
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.