aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/xen/manage.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/xen/manage.c')
-rw-r--r--drivers/xen/manage.c126
1 files changed, 112 insertions, 14 deletions
diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c
index aa7af9e6abc0..ba85fa2cff33 100644
--- a/drivers/xen/manage.c
+++ b/drivers/xen/manage.c
@@ -5,21 +5,113 @@
5#include <linux/err.h> 5#include <linux/err.h>
6#include <linux/reboot.h> 6#include <linux/reboot.h>
7#include <linux/sysrq.h> 7#include <linux/sysrq.h>
8#include <linux/stop_machine.h>
9#include <linux/freezer.h>
8 10
9#include <xen/xenbus.h> 11#include <xen/xenbus.h>
10 12#include <xen/grant_table.h>
11#define SHUTDOWN_INVALID -1 13#include <xen/events.h>
12#define SHUTDOWN_POWEROFF 0 14#include <xen/hvc-console.h>
13#define SHUTDOWN_SUSPEND 2 15#include <xen/xen-ops.h>
14/* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only 16
15 * report a crash, not be instructed to crash! 17#include <asm/xen/hypercall.h>
16 * HALT is the same as POWEROFF, as far as we're concerned. The tools use 18#include <asm/xen/page.h>
17 * the distinction when we return the reason code to them. 19
18 */ 20enum shutdown_state {
19#define SHUTDOWN_HALT 4 21 SHUTDOWN_INVALID = -1,
22 SHUTDOWN_POWEROFF = 0,
23 SHUTDOWN_SUSPEND = 2,
24 /* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only
25 report a crash, not be instructed to crash!
26 HALT is the same as POWEROFF, as far as we're concerned. The tools use
27 the distinction when we return the reason code to them. */
28 SHUTDOWN_HALT = 4,
29};
20 30
21/* Ignore multiple shutdown requests. */ 31/* Ignore multiple shutdown requests. */
22static int shutting_down = SHUTDOWN_INVALID; 32static enum shutdown_state shutting_down = SHUTDOWN_INVALID;
33
34static int xen_suspend(void *data)
35{
36 int *cancelled = data;
37
38 BUG_ON(!irqs_disabled());
39
40 load_cr3(swapper_pg_dir);
41
42 xen_mm_pin_all();
43 gnttab_suspend();
44 xen_time_suspend();
45 xen_pre_suspend();
46
47 /*
48 * This hypercall returns 1 if suspend was cancelled
49 * or the domain was merely checkpointed, and 0 if it
50 * is resuming in a new domain.
51 */
52 *cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info));
53
54 xen_post_suspend(*cancelled);
55 xen_time_resume();
56 gnttab_resume();
57 xen_mm_unpin_all();
58
59 if (!*cancelled) {
60 xen_irq_resume();
61 xen_console_resume();
62 }
63
64 return 0;
65}
66
67static void do_suspend(void)
68{
69 int err;
70 int cancelled = 1;
71
72 shutting_down = SHUTDOWN_SUSPEND;
73
74#ifdef CONFIG_PREEMPT
75 /* If the kernel is preemptible, we need to freeze all the processes
76 to prevent them from being in the middle of a pagetable update
77 during suspend. */
78 err = freeze_processes();
79 if (err) {
80 printk(KERN_ERR "xen suspend: freeze failed %d\n", err);
81 return;
82 }
83#endif
84
85 err = device_suspend(PMSG_SUSPEND);
86 if (err) {
87 printk(KERN_ERR "xen suspend: device_suspend %d\n", err);
88 goto out;
89 }
90
91 printk("suspending xenbus...\n");
92 /* XXX use normal device tree? */
93 xenbus_suspend();
94
95 err = stop_machine_run(xen_suspend, &cancelled, 0);
96 if (err) {
97 printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
98 goto out;
99 }
100
101 if (!cancelled)
102 xenbus_resume();
103 else
104 xenbus_suspend_cancel();
105
106 device_resume();
107
108
109out:
110#ifdef CONFIG_PREEMPT
111 thaw_processes();
112#endif
113 shutting_down = SHUTDOWN_INVALID;
114}
23 115
24static void shutdown_handler(struct xenbus_watch *watch, 116static void shutdown_handler(struct xenbus_watch *watch,
25 const char **vec, unsigned int len) 117 const char **vec, unsigned int len)
@@ -52,11 +144,17 @@ static void shutdown_handler(struct xenbus_watch *watch,
52 } 144 }
53 145
54 if (strcmp(str, "poweroff") == 0 || 146 if (strcmp(str, "poweroff") == 0 ||
55 strcmp(str, "halt") == 0) 147 strcmp(str, "halt") == 0) {
148 shutting_down = SHUTDOWN_POWEROFF;
56 orderly_poweroff(false); 149 orderly_poweroff(false);
57 else if (strcmp(str, "reboot") == 0) 150 } else if (strcmp(str, "reboot") == 0) {
151 shutting_down = SHUTDOWN_POWEROFF; /* ? */
58 ctrl_alt_del(); 152 ctrl_alt_del();
59 else { 153#ifdef CONFIG_PM_SLEEP
154 } else if (strcmp(str, "suspend") == 0) {
155 do_suspend();
156#endif
157 } else {
60 printk(KERN_INFO "Ignoring shutdown request: %s\n", str); 158 printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
61 shutting_down = SHUTDOWN_INVALID; 159 shutting_down = SHUTDOWN_INVALID;
62 } 160 }