diff options
author | Dexuan Cui <decui@microsoft.com> | 2019-09-05 19:01:16 -0400 |
---|---|---|
committer | Sasha Levin <sashal@kernel.org> | 2019-09-06 14:52:44 -0400 |
commit | 63ecc6d22ce46643165c391a9c90ba67e22e1c0f (patch) | |
tree | 3d0f5dacce230af9b863215332cf10bb55ca2b66 | |
parent | dba61cda30469a6c4fed0f8d5bf2b6001ca80a51 (diff) |
Drivers: hv: vmbus: Suspend/resume the synic for hibernation
This is needed when we resume the old kernel from the "current" kernel.
Note: when hv_synic_suspend() and hv_synic_resume() run, all the
non-boot CPUs have been offlined, and interrupts are disabled on CPU0.
Signed-off-by: Dexuan Cui <decui@microsoft.com>
Reviewed-by: Michael Kelley <mikelley@microsoft.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
-rw-r--r-- | drivers/hv/vmbus_drv.c | 46 |
1 files changed, 46 insertions, 0 deletions
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index ebd35fc35290..2ef375ce58ac 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/kdebug.h> | 30 | #include <linux/kdebug.h> |
31 | #include <linux/efi.h> | 31 | #include <linux/efi.h> |
32 | #include <linux/random.h> | 32 | #include <linux/random.h> |
33 | #include <linux/syscore_ops.h> | ||
33 | #include <clocksource/hyperv_timer.h> | 34 | #include <clocksource/hyperv_timer.h> |
34 | #include "hyperv_vmbus.h" | 35 | #include "hyperv_vmbus.h" |
35 | 36 | ||
@@ -2086,6 +2087,47 @@ static void hv_crash_handler(struct pt_regs *regs) | |||
2086 | hyperv_cleanup(); | 2087 | hyperv_cleanup(); |
2087 | }; | 2088 | }; |
2088 | 2089 | ||
2090 | static int hv_synic_suspend(void) | ||
2091 | { | ||
2092 | /* | ||
2093 | * When we reach here, all the non-boot CPUs have been offlined, and | ||
2094 | * the stimers on them have been unbound in hv_synic_cleanup() -> | ||
2095 | * hv_stimer_cleanup() -> clockevents_unbind_device(). | ||
2096 | * | ||
2097 | * hv_synic_suspend() only runs on CPU0 with interrupts disabled. Here | ||
2098 | * we do not unbind the stimer on CPU0 because: 1) it's unnecessary | ||
2099 | * because the interrupts remain disabled between syscore_suspend() | ||
2100 | * and syscore_resume(): see create_image() and resume_target_kernel(); | ||
2101 | * 2) the stimer on CPU0 is automatically disabled later by | ||
2102 | * syscore_suspend() -> timekeeping_suspend() -> tick_suspend() -> ... | ||
2103 | * -> clockevents_shutdown() -> ... -> hv_ce_shutdown(); 3) a warning | ||
2104 | * would be triggered if we call clockevents_unbind_device(), which | ||
2105 | * may sleep, in an interrupts-disabled context. So, we intentionally | ||
2106 | * don't call hv_stimer_cleanup(0) here. | ||
2107 | */ | ||
2108 | |||
2109 | hv_synic_disable_regs(0); | ||
2110 | |||
2111 | return 0; | ||
2112 | } | ||
2113 | |||
2114 | static void hv_synic_resume(void) | ||
2115 | { | ||
2116 | hv_synic_enable_regs(0); | ||
2117 | |||
2118 | /* | ||
2119 | * Note: we don't need to call hv_stimer_init(0), because the timer | ||
2120 | * on CPU0 is not unbound in hv_synic_suspend(), and the timer is | ||
2121 | * automatically re-enabled in timekeeping_resume(). | ||
2122 | */ | ||
2123 | } | ||
2124 | |||
2125 | /* The callbacks run only on CPU0, with irqs_disabled. */ | ||
2126 | static struct syscore_ops hv_synic_syscore_ops = { | ||
2127 | .suspend = hv_synic_suspend, | ||
2128 | .resume = hv_synic_resume, | ||
2129 | }; | ||
2130 | |||
2089 | static int __init hv_acpi_init(void) | 2131 | static int __init hv_acpi_init(void) |
2090 | { | 2132 | { |
2091 | int ret, t; | 2133 | int ret, t; |
@@ -2116,6 +2158,8 @@ static int __init hv_acpi_init(void) | |||
2116 | hv_setup_kexec_handler(hv_kexec_handler); | 2158 | hv_setup_kexec_handler(hv_kexec_handler); |
2117 | hv_setup_crash_handler(hv_crash_handler); | 2159 | hv_setup_crash_handler(hv_crash_handler); |
2118 | 2160 | ||
2161 | register_syscore_ops(&hv_synic_syscore_ops); | ||
2162 | |||
2119 | return 0; | 2163 | return 0; |
2120 | 2164 | ||
2121 | cleanup: | 2165 | cleanup: |
@@ -2128,6 +2172,8 @@ static void __exit vmbus_exit(void) | |||
2128 | { | 2172 | { |
2129 | int cpu; | 2173 | int cpu; |
2130 | 2174 | ||
2175 | unregister_syscore_ops(&hv_synic_syscore_ops); | ||
2176 | |||
2131 | hv_remove_kexec_handler(); | 2177 | hv_remove_kexec_handler(); |
2132 | hv_remove_crash_handler(); | 2178 | hv_remove_crash_handler(); |
2133 | vmbus_connection.conn_state = DISCONNECTED; | 2179 | vmbus_connection.conn_state = DISCONNECTED; |