Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Drivers: hv: vmbus: Fix Suspend-to-Idle for Generation-2 VM

Before the hibernation patchset (e.g. f53335e3289f), in a Generation-2
Linux VM on Hyper-V, the user can run "echo freeze > /sys/power/state" to
freeze the system, i.e. Suspend-to-Idle. The user can press the keyboard
or move the mouse to wake up the VM.

With the hibernation patchset, Linux VM on Hyper-V can hibernate to disk,
but Suspend-to-Idle is broken: when the synthetic keyboard/mouse are
suspended, there is no way to wake up the VM.

Fix the issue by not suspending and resuming the vmbus devices upon
Suspend-to-Idle.

Fixes: f53335e3289f ("Drivers: hv: vmbus: Suspend/resume the vmbus itself for hibernation")
Cc: stable@vger.kernel.org
Reviewed-by: Michael Kelley <mikelley@microsoft.com>
Signed-off-by: Dexuan Cui <decui@microsoft.com>
Link: https://lore.kernel.org/r/1586663435-36243-1-git-send-email-decui@microsoft.com
Signed-off-by: Wei Liu <wei.liu@kernel.org>

authored by

Dexuan Cui and committed by
Wei Liu
1a06d017 f3a99e76

+34 -9
+34 -9
drivers/hv/vmbus_drv.c
··· 978 978 979 979 return drv->resume(dev); 980 980 } 981 + #else 982 + #define vmbus_suspend NULL 983 + #define vmbus_resume NULL 981 984 #endif /* CONFIG_PM_SLEEP */ 982 985 983 986 /* ··· 1000 997 } 1001 998 1002 999 /* 1003 - * Note: we must use SET_NOIRQ_SYSTEM_SLEEP_PM_OPS rather than 1004 - * SET_SYSTEM_SLEEP_PM_OPS: see the comment before vmbus_bus_pm. 1000 + * Note: we must use the "noirq" ops: see the comment before vmbus_bus_pm. 1001 + * 1002 + * suspend_noirq/resume_noirq are set to NULL to support Suspend-to-Idle: we 1003 + * shouldn't suspend the vmbus devices upon Suspend-to-Idle, otherwise there 1004 + * is no way to wake up a Generation-2 VM. 1005 + * 1006 + * The other 4 ops are for hibernation. 1005 1007 */ 1008 + 1006 1009 static const struct dev_pm_ops vmbus_pm = { 1007 - SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(vmbus_suspend, vmbus_resume) 1010 + .suspend_noirq = NULL, 1011 + .resume_noirq = NULL, 1012 + .freeze_noirq = vmbus_suspend, 1013 + .thaw_noirq = vmbus_resume, 1014 + .poweroff_noirq = vmbus_suspend, 1015 + .restore_noirq = vmbus_resume, 1008 1016 }; 1009 1017 1010 1018 /* The one and only one */ ··· 2295 2281 2296 2282 return 0; 2297 2283 } 2284 + #else 2285 + #define vmbus_bus_suspend NULL 2286 + #define vmbus_bus_resume NULL 2298 2287 #endif /* CONFIG_PM_SLEEP */ 2299 2288 2300 2289 static const struct acpi_device_id vmbus_acpi_device_ids[] = { ··· 2308 2291 MODULE_DEVICE_TABLE(acpi, vmbus_acpi_device_ids); 2309 2292 2310 2293 /* 2311 - * Note: we must use SET_NOIRQ_SYSTEM_SLEEP_PM_OPS rather than 2312 - * SET_SYSTEM_SLEEP_PM_OPS, otherwise NIC SR-IOV can not work, because the 2313 - * "pci_dev_pm_ops" uses the "noirq" callbacks: in the resume path, the 2314 - * pci "noirq" restore callback runs before "non-noirq" callbacks (see 2294 + * Note: we must use the "no_irq" ops, otherwise hibernation can not work with 2295 + * PCI device assignment, because "pci_dev_pm_ops" uses the "noirq" ops: in 2296 + * the resume path, the pci "noirq" restore op runs before "non-noirq" op (see 2315 2297 * resume_target_kernel() -> dpm_resume_start(), and hibernation_restore() -> 2316 2298 * dpm_resume_end()). This means vmbus_bus_resume() and the pci-hyperv's 2317 - * resume callback must also run via the "noirq" callbacks. 2299 + * resume callback must also run via the "noirq" ops. 2300 + * 2301 + * Set suspend_noirq/resume_noirq to NULL for Suspend-to-Idle: see the comment 2302 + * earlier in this file before vmbus_pm. 2318 2303 */ 2304 + 2319 2305 static const struct dev_pm_ops vmbus_bus_pm = { 2320 - SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(vmbus_bus_suspend, vmbus_bus_resume) 2306 + .suspend_noirq = NULL, 2307 + .resume_noirq = NULL, 2308 + .freeze_noirq = vmbus_bus_suspend, 2309 + .thaw_noirq = vmbus_bus_resume, 2310 + .poweroff_noirq = vmbus_bus_suspend, 2311 + .restore_noirq = vmbus_bus_resume 2321 2312 }; 2322 2313 2323 2314 static struct acpi_driver vmbus_acpi_driver = {