On Wed, Nov 26, 2025 at 03:49:52PM -0600, Praveen K Paladugu wrote: > Configure sleep state information in mshv hypervisor. This sleep state > information from ACPI will be used by hypervisor to poweroff the host. >
Acked-by: Stanislav Kinsburskii <[email protected]> > Signed-off-by: Praveen K Paladugu <[email protected]> > Co-developed-by: Anatol Belski <[email protected]> > Signed-off-by: Anatol Belski <[email protected]> > Reviewed-by: Easwar Hariharan <[email protected]> > --- > arch/x86/hyperv/hv_init.c | 1 + > arch/x86/include/asm/mshyperv.h | 2 + > drivers/hv/mshv_common.c | 80 +++++++++++++++++++++++++++++++++ > 3 files changed, 83 insertions(+) > > diff --git a/arch/x86/hyperv/hv_init.c b/arch/x86/hyperv/hv_init.c > index e28737ec7054..daf97a984b78 100644 > --- a/arch/x86/hyperv/hv_init.c > +++ b/arch/x86/hyperv/hv_init.c > @@ -555,6 +555,7 @@ void __init hyperv_init(void) > > hv_remap_tsc_clocksource(); > hv_root_crash_init(); > + hv_sleep_notifiers_register(); > } else { > hypercall_msr.guest_physical_address = > vmalloc_to_pfn(hv_hypercall_pg); > wrmsrq(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64); > diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h > index 10037125099a..166053df0484 100644 > --- a/arch/x86/include/asm/mshyperv.h > +++ b/arch/x86/include/asm/mshyperv.h > @@ -182,8 +182,10 @@ int hyperv_fill_flush_guest_mapping_list( > void hv_apic_init(void); > void __init hv_init_spinlocks(void); > bool hv_vcpu_is_preempted(int vcpu); > +void hv_sleep_notifiers_register(void); > #else > static inline void hv_apic_init(void) {} > +static inline void hv_sleep_notifiers_register(void) {}; > #endif > > struct irq_domain *hv_create_pci_msi_domain(void); > diff --git a/drivers/hv/mshv_common.c b/drivers/hv/mshv_common.c > index aa2be51979fd..f1d4e81107ee 100644 > --- a/drivers/hv/mshv_common.c > +++ b/drivers/hv/mshv_common.c > @@ -14,6 +14,9 @@ > #include <asm/mshyperv.h> > #include <linux/resume_user_mode.h> > #include <linux/export.h> > +#include <linux/acpi.h> > +#include <linux/notifier.h> > +#include <linux/reboot.h> > > #include "mshv.h" > > @@ -138,3 +141,80 @@ int hv_call_get_partition_property(u64 partition_id, > return 0; > } > EXPORT_SYMBOL_GPL(hv_call_get_partition_property); > + > +#ifdef CONFIG_X86_64 > +/* > + * Corresponding sleep states have to be initialized in order for a > subsequent > + * HVCALL_ENTER_SLEEP_STATE call to succeed. Currently only S5 state as per > + * ACPI 6.4 chapter 7.4.2 is relevant, while S1, S2 and S3 can be supported. > + * > + * In order to pass proper PM values to mshv, ACPI should be initialized and > + * should support S5 sleep state when this method is invoked. > + */ > +static int hv_initialize_sleep_states(void) > +{ > + u64 status; > + unsigned long flags; > + struct hv_input_set_system_property *in; > + acpi_status acpi_status; > + u8 sleep_type_a, sleep_type_b; > + > + if (!acpi_sleep_state_supported(ACPI_STATE_S5)) { > + pr_err("%s: S5 sleep state not supported.\n", __func__); > + return -ENODEV; > + } > + > + acpi_status = acpi_get_sleep_type_data(ACPI_STATE_S5, &sleep_type_a, > + &sleep_type_b); > + if (ACPI_FAILURE(acpi_status)) > + return -ENODEV; > + > + local_irq_save(flags); > + in = *this_cpu_ptr(hyperv_pcpu_input_arg); > + memset(in, 0, sizeof(*in)); > + > + in->property_id = HV_SYSTEM_PROPERTY_SLEEP_STATE; > + in->set_sleep_state_info.sleep_state = HV_SLEEP_STATE_S5; > + in->set_sleep_state_info.pm1a_slp_typ = sleep_type_a; > + in->set_sleep_state_info.pm1b_slp_typ = sleep_type_b; > + > + status = hv_do_hypercall(HVCALL_SET_SYSTEM_PROPERTY, in, NULL); > + local_irq_restore(flags); > + > + if (!hv_result_success(status)) { > + hv_status_err(status, "\n"); > + return hv_result_to_errno(status); > + } > + > + return 0; > +} > + > +/* > + * This notifier initializes sleep states in mshv hypervisor which will be > + * used during power off. > + */ > +static int hv_reboot_notifier_handler(struct notifier_block *this, > + unsigned long code, void *another) > +{ > + int ret = 0; > + > + if (code == SYS_HALT || code == SYS_POWER_OFF) > + ret = hv_initialize_sleep_states(); > + > + return ret ? NOTIFY_DONE : NOTIFY_OK; > +} > + > +static struct notifier_block hv_reboot_notifier = { > + .notifier_call = hv_reboot_notifier_handler, > +}; > + > +void hv_sleep_notifiers_register(void) > +{ > + int ret; > + > + ret = register_reboot_notifier(&hv_reboot_notifier); > + if (ret) > + pr_err("%s: cannot register reboot notifier %d\n", __func__, > + ret); > +} > +#endif > -- > 2.51.0
