]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - drivers/xen/manage.c
xen: suspend: pull pre/post suspend hooks out into suspend_info
[mirror_ubuntu-bionic-kernel.git] / drivers / xen / manage.c
CommitLineData
3e2b8fbe
JF
1/*
2 * Handle extern requests for shutdown, reboot and sysrq
3 */
4#include <linux/kernel.h>
5#include <linux/err.h>
5a0e3ad6 6#include <linux/slab.h>
3e2b8fbe
JF
7#include <linux/reboot.h>
8#include <linux/sysrq.h>
0e91398f
JF
9#include <linux/stop_machine.h>
10#include <linux/freezer.h>
3e2b8fbe 11
016b6f5f 12#include <xen/xen.h>
3e2b8fbe 13#include <xen/xenbus.h>
0e91398f
JF
14#include <xen/grant_table.h>
15#include <xen/events.h>
16#include <xen/hvc-console.h>
17#include <xen/xen-ops.h>
3e2b8fbe 18
0e91398f
JF
19#include <asm/xen/hypercall.h>
20#include <asm/xen/page.h>
016b6f5f 21#include <asm/xen/hypervisor.h>
0e91398f
JF
22
23enum shutdown_state {
24 SHUTDOWN_INVALID = -1,
25 SHUTDOWN_POWEROFF = 0,
26 SHUTDOWN_SUSPEND = 2,
27 /* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only
28 report a crash, not be instructed to crash!
29 HALT is the same as POWEROFF, as far as we're concerned. The tools use
30 the distinction when we return the reason code to them. */
31 SHUTDOWN_HALT = 4,
32};
3e2b8fbe
JF
33
34/* Ignore multiple shutdown requests. */
0e91398f
JF
35static enum shutdown_state shutting_down = SHUTDOWN_INVALID;
36
ceb18029
IC
37struct suspend_info {
38 int cancelled;
36b401e2 39 unsigned long arg; /* extra hypercall argument */
55fb4ace
IC
40 void (*pre)(void);
41 void (*post)(int cancelled);
ceb18029
IC
42};
43
07af3810 44static void xen_hvm_post_suspend(int cancelled)
82043bb6 45{
07af3810 46 xen_arch_hvm_post_suspend(cancelled);
82043bb6
IC
47 gnttab_resume();
48}
49
50static void xen_pre_suspend(void)
51{
52 xen_mm_pin_all();
53 gnttab_suspend();
07af3810 54 xen_arch_pre_suspend();
82043bb6
IC
55}
56
07af3810 57static void xen_post_suspend(int cancelled)
82043bb6 58{
07af3810 59 xen_arch_post_suspend(cancelled);
82043bb6
IC
60 gnttab_resume();
61 xen_mm_unpin_all();
62}
63
c7827728 64#ifdef CONFIG_PM_SLEEP
016b6f5f 65static int xen_hvm_suspend(void *data)
0e91398f 66{
ceb18029 67 struct suspend_info *si = data;
8dd38383 68 int err;
016b6f5f
SS
69
70 BUG_ON(!irqs_disabled());
71
8dd38383
IC
72 err = sysdev_suspend(PMSG_SUSPEND);
73 if (err) {
74 printk(KERN_ERR "xen_hvm_suspend: sysdev_suspend failed: %d\n",
75 err);
76 return err;
77 }
78
55fb4ace
IC
79 if (si->pre)
80 si->pre();
81
bd1c0ad2
IC
82 /*
83 * This hypercall returns 1 if suspend was cancelled
84 * or the domain was merely checkpointed, and 0 if it
85 * is resuming in a new domain.
86 */
36b401e2 87 si->cancelled = HYPERVISOR_suspend(si->arg);
016b6f5f 88
55fb4ace
IC
89 if (si->post)
90 si->post(si->cancelled);
016b6f5f 91
ceb18029 92 if (!si->cancelled) {
016b6f5f 93 xen_irq_resume();
6411fe69 94 xen_console_resume();
016b6f5f
SS
95 xen_timer_resume();
96 }
97
8dd38383
IC
98 sysdev_resume();
99
016b6f5f
SS
100 return 0;
101}
102
103static int xen_suspend(void *data)
104{
ceb18029 105 struct suspend_info *si = data;
359cdd3f 106 int err;
0e91398f
JF
107
108 BUG_ON(!irqs_disabled());
109
770824bd
RW
110 err = sysdev_suspend(PMSG_SUSPEND);
111 if (err) {
112 printk(KERN_ERR "xen_suspend: sysdev_suspend failed: %d\n",
113 err);
770824bd
RW
114 return err;
115 }
359cdd3f 116
55fb4ace
IC
117 if (si->pre)
118 si->pre();
0e91398f
JF
119
120 /*
121 * This hypercall returns 1 if suspend was cancelled
122 * or the domain was merely checkpointed, and 0 if it
123 * is resuming in a new domain.
124 */
36b401e2 125 si->cancelled = HYPERVISOR_suspend(si->arg);
0e91398f 126
55fb4ace
IC
127 if (si->post)
128 si->post(si->cancelled);
0e91398f 129
ceb18029 130 if (!si->cancelled) {
0e91398f
JF
131 xen_irq_resume();
132 xen_console_resume();
ad55db9f 133 xen_timer_resume();
0e91398f
JF
134 }
135
1e6fcf84 136 sysdev_resume();
1e6fcf84 137
0e91398f
JF
138 return 0;
139}
140
141static void do_suspend(void)
142{
143 int err;
ceb18029 144 struct suspend_info si;
0e91398f
JF
145
146 shutting_down = SHUTDOWN_SUSPEND;
147
148#ifdef CONFIG_PREEMPT
149 /* If the kernel is preemptible, we need to freeze all the processes
150 to prevent them from being in the middle of a pagetable update
151 during suspend. */
152 err = freeze_processes();
153 if (err) {
154 printk(KERN_ERR "xen suspend: freeze failed %d\n", err);
3fc1f1e2 155 goto out;
0e91398f
JF
156 }
157#endif
158
d1616302 159 err = dpm_suspend_start(PMSG_SUSPEND);
0e91398f 160 if (err) {
d1616302 161 printk(KERN_ERR "xen suspend: dpm_suspend_start %d\n", err);
65f63384 162 goto out_thaw;
0e91398f
JF
163 }
164
c5cae661
IC
165 printk(KERN_DEBUG "suspending xenstore...\n");
166 xs_suspend();
167
d1616302 168 err = dpm_suspend_noirq(PMSG_SUSPEND);
2ed8d2b3 169 if (err) {
d1616302 170 printk(KERN_ERR "dpm_suspend_noirq failed: %d\n", err);
65f63384 171 goto out_resume;
2ed8d2b3
RW
172 }
173
ceb18029
IC
174 si.cancelled = 1;
175
55fb4ace 176 if (xen_hvm_domain()) {
36b401e2 177 si.arg = 0UL;
55fb4ace
IC
178 si.pre = NULL;
179 si.post = &xen_hvm_post_suspend;
180 } else {
36b401e2 181 si.arg = virt_to_mfn(xen_start_info);
55fb4ace
IC
182 si.pre = &xen_pre_suspend;
183 si.post = &xen_post_suspend;
184 }
36b401e2 185
016b6f5f 186 if (xen_hvm_domain())
ceb18029 187 err = stop_machine(xen_hvm_suspend, &si, cpumask_of(0));
016b6f5f 188 else
ceb18029 189 err = stop_machine(xen_suspend, &si, cpumask_of(0));
922cc38a
JF
190
191 dpm_resume_noirq(PMSG_RESUME);
192
0e91398f
JF
193 if (err) {
194 printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
ceb18029 195 si.cancelled = 1;
0e91398f
JF
196 }
197
c5cae661 198out_resume:
ceb18029 199 if (!si.cancelled) {
ad55db9f 200 xen_arch_resume();
de5b31bd 201 xs_resume();
ad55db9f 202 } else
de5b31bd 203 xs_suspend_cancel();
0e91398f 204
d1616302 205 dpm_resume_end(PMSG_RESUME);
0e91398f 206
359cdd3f
JF
207 /* Make sure timer events get retriggered on all CPUs */
208 clock_was_set();
65f63384
IC
209
210out_thaw:
0e91398f
JF
211#ifdef CONFIG_PREEMPT
212 thaw_processes();
65f63384 213out:
3fc1f1e2 214#endif
0e91398f
JF
215 shutting_down = SHUTDOWN_INVALID;
216}
c7827728 217#endif /* CONFIG_PM_SLEEP */
3e2b8fbe 218
55271723
IC
219struct shutdown_handler {
220 const char *command;
221 void (*cb)(void);
222};
223
224static void do_poweroff(void)
225{
226 shutting_down = SHUTDOWN_POWEROFF;
227 orderly_poweroff(false);
228}
229
230static void do_reboot(void)
231{
232 shutting_down = SHUTDOWN_POWEROFF; /* ? */
233 ctrl_alt_del();
234}
235
3e2b8fbe
JF
236static void shutdown_handler(struct xenbus_watch *watch,
237 const char **vec, unsigned int len)
238{
239 char *str;
240 struct xenbus_transaction xbt;
241 int err;
55271723
IC
242 static struct shutdown_handler handlers[] = {
243 { "poweroff", do_poweroff },
244 { "halt", do_poweroff },
245 { "reboot", do_reboot },
246#ifdef CONFIG_PM_SLEEP
247 { "suspend", do_suspend },
248#endif
249 {NULL, NULL},
250 };
251 static struct shutdown_handler *handler;
3e2b8fbe
JF
252
253 if (shutting_down != SHUTDOWN_INVALID)
254 return;
255
256 again:
257 err = xenbus_transaction_start(&xbt);
258 if (err)
259 return;
260
261 str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
262 /* Ignore read errors and empty reads. */
263 if (XENBUS_IS_ERR_READ(str)) {
264 xenbus_transaction_end(xbt, 1);
265 return;
266 }
267
55271723
IC
268 for (handler = &handlers[0]; handler->command; handler++) {
269 if (strcmp(str, handler->command) == 0)
270 break;
271 }
272
273 /* Only acknowledge commands which we are prepared to handle. */
274 if (handler->cb)
275 xenbus_write(xbt, "control", "shutdown", "");
3e2b8fbe
JF
276
277 err = xenbus_transaction_end(xbt, 0);
278 if (err == -EAGAIN) {
279 kfree(str);
280 goto again;
281 }
282
55271723
IC
283 if (handler->cb) {
284 handler->cb();
0e91398f 285 } else {
3e2b8fbe
JF
286 printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
287 shutting_down = SHUTDOWN_INVALID;
288 }
289
290 kfree(str);
291}
292
f3bc3189 293#ifdef CONFIG_MAGIC_SYSRQ
3e2b8fbe
JF
294static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
295 unsigned int len)
296{
297 char sysrq_key = '\0';
298 struct xenbus_transaction xbt;
299 int err;
300
301 again:
302 err = xenbus_transaction_start(&xbt);
303 if (err)
304 return;
305 if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
306 printk(KERN_ERR "Unable to read sysrq code in "
307 "control/sysrq\n");
308 xenbus_transaction_end(xbt, 1);
309 return;
310 }
311
312 if (sysrq_key != '\0')
313 xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
314
315 err = xenbus_transaction_end(xbt, 0);
316 if (err == -EAGAIN)
317 goto again;
318
319 if (sysrq_key != '\0')
f335397d 320 handle_sysrq(sysrq_key);
3e2b8fbe
JF
321}
322
3e2b8fbe
JF
323static struct xenbus_watch sysrq_watch = {
324 .node = "control/sysrq",
325 .callback = sysrq_handler
326};
f3bc3189
RD
327#endif
328
329static struct xenbus_watch shutdown_watch = {
330 .node = "control/shutdown",
331 .callback = shutdown_handler
332};
3e2b8fbe
JF
333
334static int setup_shutdown_watcher(void)
335{
336 int err;
337
338 err = register_xenbus_watch(&shutdown_watch);
339 if (err) {
340 printk(KERN_ERR "Failed to set shutdown watcher\n");
341 return err;
342 }
343
f3bc3189 344#ifdef CONFIG_MAGIC_SYSRQ
3e2b8fbe
JF
345 err = register_xenbus_watch(&sysrq_watch);
346 if (err) {
347 printk(KERN_ERR "Failed to set sysrq watcher\n");
348 return err;
349 }
f3bc3189 350#endif
3e2b8fbe
JF
351
352 return 0;
353}
354
355static int shutdown_event(struct notifier_block *notifier,
356 unsigned long event,
357 void *data)
358{
359 setup_shutdown_watcher();
360 return NOTIFY_DONE;
361}
362
016b6f5f 363int xen_setup_shutdown_event(void)
3e2b8fbe
JF
364{
365 static struct notifier_block xenstore_notifier = {
366 .notifier_call = shutdown_event
367 };
702d4eb9
SS
368
369 if (!xen_domain())
370 return -ENODEV;
3e2b8fbe
JF
371 register_xenstore_notifier(&xenstore_notifier);
372
373 return 0;
374}
183d03cc 375EXPORT_SYMBOL_GPL(xen_setup_shutdown_event);
3e2b8fbe 376
702d4eb9 377subsys_initcall(xen_setup_shutdown_event);