mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-07-29 22:47:21 +00:00
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:
parent
197e4a0620
commit
bfa19e9104
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user