From bfa19e910475a778ead7f0872c277641c4e8b153 Mon Sep 17 00:00:00 2001 From: Yin Fengwei Date: Thu, 12 Dec 2019 15:06:20 +0800 Subject: [PATCH] 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 --- hypervisor/arch/x86/guest/pm.c | 46 ++++++--------------------- hypervisor/arch/x86/guest/vm.c | 23 ++++++++++++++ hypervisor/arch/x86/pm.c | 12 +++++-- hypervisor/include/arch/x86/host_pm.h | 3 +- 4 files changed, 45 insertions(+), 39 deletions(-) diff --git a/hypervisor/arch/x86/guest/pm.c b/hypervisor/arch/x86/guest/pm.c index dd8f64dcc..4827513e7 100644 --- a/hypervisor/arch/x86/guest/pm.c +++ b/hypervisor/arch/x86/guest/pm.c @@ -11,6 +11,7 @@ #include #include #include +#include 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) diff --git a/hypervisor/arch/x86/guest/vm.c b/hypervisor/arch/x86/guest/vm.c index 0be4d12a4..64c1e159d 100644 --- a/hypervisor/arch/x86/guest/vm.c +++ b/hypervisor/arch/x86/guest/vm.c @@ -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; } diff --git a/hypervisor/arch/x86/pm.c b/hypervisor/arch/x86/pm.c index bbce3c895..017be8c91 100644 --- a/hypervisor/arch/x86/pm.c +++ b/hypervisor/arch/x86/pm.c @@ -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) diff --git a/hypervisor/include/arch/x86/host_pm.h b/hypervisor/include/arch/x86/host_pm.h index 40422b3a4..5bf80847e 100644 --- a/hypervisor/include/arch/x86/host_pm.h +++ b/hypervisor/include/arch/x86/host_pm.h @@ -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);