pm: S5: update the system shutdown logical in ACRN

For system S5, ACRN had assumption that SOS shutdown will trigger
system shutdown. So the system shutdown logical is:
   1. Trap SOS shutdown
   2. Wait for all other guest shutdown
   3. Shutdown system

The new logical is refined as:
   If all guest is shutdown, shutdown whole system

Tracked-On: #4270
Signed-off-by: Yin Fengwei <fengwei.yin@intel.com>
This commit is contained in:
Yin Fengwei 2019-12-12 15:06:20 +08:00 committed by wenlingz
parent 197e4a0620
commit bfa19e9104
4 changed files with 45 additions and 39 deletions

View File

@ -11,6 +11,7 @@
#include <logmsg.h>
#include <platform_acpi_info.h>
#include <guest_pm.h>
#include <per_cpu.h>
int32_t validate_pstate(const struct acrn_vm *vm, uint64_t perf_ctl)
{
@ -149,45 +150,18 @@ static bool pm1ab_io_read(struct acrn_vcpu *vcpu, uint16_t addr, size_t width)
return true;
}
#define POWEROFF_TIMEOUT (300U) /* default poweroff timeout is 5 minutes */
/* wait for other vm shutdown done. If POWEROFF_TIMEOUT passed and there are
* still some VMs active, we will force platform power off.
*
* TODO:
* - Let user configure whether we wait for ever till all VMs powered off or
* force shutdown once pre-defined timeout hit.
*/
static inline void wait_for_other_vm_shutdown(const struct acrn_vm *self_vm)
static inline void enter_s5(struct acrn_vm *vm, uint32_t pm1a_cnt_val, uint32_t pm1b_cnt_val)
{
uint16_t vm_id;
bool ready_for_s5;
uint32_t timeout = (uint32_t)POWEROFF_TIMEOUT;
struct acrn_vm *vm;
while (timeout != 0U) {
ready_for_s5 = true;
for (vm_id = 0U; vm_id < CONFIG_MAX_VM_NUM; vm_id++) {
vm = get_vm_from_vmid(vm_id);
if ((vm != self_vm) && (!is_poweroff_vm(vm))) {
ready_for_s5 = false;
}
}
if (ready_for_s5) {
break;
} else {
udelay(1000U * 1000U); /* delay 1s in each loop */
}
timeout--;
/*
* It's possible that ACRN come here from SOS and pre-launched VM. Currently, we
* assume SOS has full ACPI power management stack. That means the value from SOS
* should be saved and used to shutdown the system.
*/
if (is_sos_vm(vm)) {
save_s5_reg_val(pm1a_cnt_val, pm1b_cnt_val);
}
}
static inline void enter_s5(const struct acrn_vm *vm, uint32_t pm1a_cnt_val, uint32_t pm1b_cnt_val)
{
wait_for_other_vm_shutdown(vm);
host_enter_s5(vm->pm.sx_state_data, pm1a_cnt_val, pm1b_cnt_val);
(void)shutdown_vm(vm);
}
static inline void enter_s3(struct acrn_vm *vm, uint32_t pm1a_cnt_val, uint32_t pm1b_cnt_val)

View File

@ -580,6 +580,24 @@ int32_t create_vm(uint16_t vm_id, struct acrn_vm_config *vm_config, struct acrn_
return status;
}
static bool is_ready_for_system_shutdown(void)
{
bool ret = true;
uint16_t vm_id;
struct acrn_vm *vm;
for (vm_id = 0U; vm_id < CONFIG_MAX_VM_NUM; vm_id++) {
vm = get_vm_from_vmid(vm_id);
/* TODO: Update code to cover hybrid mode */
if (!is_poweroff_vm(vm)) {
ret = false;
break;
}
}
return ret;
}
/*
* @pre vm != NULL
*/
@ -648,6 +666,11 @@ int32_t shutdown_vm(struct acrn_vm *vm)
ret = -EINVAL;
}
if (is_ready_for_system_shutdown()) {
/* If no any guest running, shutdown system */
shutdown_system();
}
/* Return status to caller */
return ret;
}

View File

@ -148,9 +148,17 @@ void do_acpi_sx(const struct pm_s_state_data *sstate_data, uint32_t pm1a_cnt_val
} while ((s1 & (1U << BIT_WAK_STS)) == 0U);
}
void host_enter_s5(const struct pm_s_state_data *sstate_data, uint32_t pm1a_cnt_val, uint32_t pm1b_cnt_val)
static uint32_t system_pm1a_cnt_val, system_pm1b_cnt_val;
void save_s5_reg_val(uint32_t pm1a_cnt_val, uint32_t pm1b_cnt_val)
{
do_acpi_sx(sstate_data, pm1a_cnt_val, pm1b_cnt_val);
system_pm1a_cnt_val = pm1a_cnt_val;
system_pm1b_cnt_val = pm1b_cnt_val;
}
void shutdown_system(void)
{
struct pm_s_state_data *sx_data = get_host_sstate_data();
do_acpi_sx(sx_data, system_pm1a_cnt_val, system_pm1b_cnt_val);
}
static void suspend_tsc(__unused void *data)

View File

@ -31,7 +31,8 @@ struct acpi_reset_reg {
struct pm_s_state_data *get_host_sstate_data(void);
void host_enter_s3(const struct pm_s_state_data *sstate_data, uint32_t pm1a_cnt_val, uint32_t pm1b_cnt_val);
void host_enter_s5(const struct pm_s_state_data *sstate_data, uint32_t pm1a_cnt_val, uint32_t pm1b_cnt_val);
void shutdown_system(void);
void save_s5_reg_val(uint32_t pm1a_cnt_val, uint32_t pm1b_cnt_val);
void do_acpi_sx(const struct pm_s_state_data *sstate_data, uint32_t pm1a_cnt_val, uint32_t pm1b_cnt_val);
extern void asm_enter_s3(const struct pm_s_state_data *sstate_data, uint32_t pm1a_cnt_val, uint32_t pm1b_cnt_val);
extern void restore_s3_context(void);