xen: don't call dpm_resume_noirq() with interrupts disabled.
[deliverable/linux.git] / drivers / xen / manage.c
1 /*
2 * Handle extern requests for shutdown, reboot and sysrq
3 */
4 #include <linux/kernel.h>
5 #include <linux/err.h>
6 #include <linux/reboot.h>
7 #include <linux/sysrq.h>
8 #include <linux/stop_machine.h>
9 #include <linux/freezer.h>
10
11 #include <xen/xenbus.h>
12 #include <xen/grant_table.h>
13 #include <xen/events.h>
14 #include <xen/hvc-console.h>
15 #include <xen/xen-ops.h>
16
17 #include <asm/xen/hypercall.h>
18 #include <asm/xen/page.h>
19
20 enum shutdown_state {
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 };
30
31 /* Ignore multiple shutdown requests. */
32 static enum shutdown_state shutting_down = SHUTDOWN_INVALID;
33
34 #ifdef CONFIG_PM_SLEEP
35 static int xen_suspend(void *data)
36 {
37 int *cancelled = data;
38 int err;
39
40 BUG_ON(!irqs_disabled());
41
42 err = sysdev_suspend(PMSG_SUSPEND);
43 if (err) {
44 printk(KERN_ERR "xen_suspend: sysdev_suspend failed: %d\n",
45 err);
46 return err;
47 }
48
49 xen_mm_pin_all();
50 gnttab_suspend();
51 xen_pre_suspend();
52
53 /*
54 * This hypercall returns 1 if suspend was cancelled
55 * or the domain was merely checkpointed, and 0 if it
56 * is resuming in a new domain.
57 */
58 *cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info));
59
60 xen_post_suspend(*cancelled);
61 gnttab_resume();
62 xen_mm_unpin_all();
63
64 if (!*cancelled) {
65 xen_irq_resume();
66 xen_console_resume();
67 xen_timer_resume();
68 }
69
70 sysdev_resume();
71
72 return 0;
73 }
74
75 static void do_suspend(void)
76 {
77 int err;
78 int cancelled = 1;
79
80 shutting_down = SHUTDOWN_SUSPEND;
81
82 #ifdef CONFIG_PREEMPT
83 /* If the kernel is preemptible, we need to freeze all the processes
84 to prevent them from being in the middle of a pagetable update
85 during suspend. */
86 err = freeze_processes();
87 if (err) {
88 printk(KERN_ERR "xen suspend: freeze failed %d\n", err);
89 return;
90 }
91 #endif
92
93 err = dpm_suspend_start(PMSG_SUSPEND);
94 if (err) {
95 printk(KERN_ERR "xen suspend: dpm_suspend_start %d\n", err);
96 goto out;
97 }
98
99 printk(KERN_DEBUG "suspending xenstore...\n");
100 xs_suspend();
101
102 err = dpm_suspend_noirq(PMSG_SUSPEND);
103 if (err) {
104 printk(KERN_ERR "dpm_suspend_noirq failed: %d\n", err);
105 goto resume_devices;
106 }
107
108 err = stop_machine(xen_suspend, &cancelled, cpumask_of(0));
109
110 dpm_resume_noirq(PMSG_RESUME);
111
112 if (err) {
113 printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
114 goto out;
115 }
116
117 if (!cancelled) {
118 xen_arch_resume();
119 xs_resume();
120 } else
121 xs_suspend_cancel();
122
123 resume_devices:
124 dpm_resume_end(PMSG_RESUME);
125
126 /* Make sure timer events get retriggered on all CPUs */
127 clock_was_set();
128 out:
129 #ifdef CONFIG_PREEMPT
130 thaw_processes();
131 #endif
132 shutting_down = SHUTDOWN_INVALID;
133 }
134 #endif /* CONFIG_PM_SLEEP */
135
136 static void shutdown_handler(struct xenbus_watch *watch,
137 const char **vec, unsigned int len)
138 {
139 char *str;
140 struct xenbus_transaction xbt;
141 int err;
142
143 if (shutting_down != SHUTDOWN_INVALID)
144 return;
145
146 again:
147 err = xenbus_transaction_start(&xbt);
148 if (err)
149 return;
150
151 str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
152 /* Ignore read errors and empty reads. */
153 if (XENBUS_IS_ERR_READ(str)) {
154 xenbus_transaction_end(xbt, 1);
155 return;
156 }
157
158 xenbus_write(xbt, "control", "shutdown", "");
159
160 err = xenbus_transaction_end(xbt, 0);
161 if (err == -EAGAIN) {
162 kfree(str);
163 goto again;
164 }
165
166 if (strcmp(str, "poweroff") == 0 ||
167 strcmp(str, "halt") == 0) {
168 shutting_down = SHUTDOWN_POWEROFF;
169 orderly_poweroff(false);
170 } else if (strcmp(str, "reboot") == 0) {
171 shutting_down = SHUTDOWN_POWEROFF; /* ? */
172 ctrl_alt_del();
173 #ifdef CONFIG_PM_SLEEP
174 } else if (strcmp(str, "suspend") == 0) {
175 do_suspend();
176 #endif
177 } else {
178 printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
179 shutting_down = SHUTDOWN_INVALID;
180 }
181
182 kfree(str);
183 }
184
185 static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
186 unsigned int len)
187 {
188 char sysrq_key = '\0';
189 struct xenbus_transaction xbt;
190 int err;
191
192 again:
193 err = xenbus_transaction_start(&xbt);
194 if (err)
195 return;
196 if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
197 printk(KERN_ERR "Unable to read sysrq code in "
198 "control/sysrq\n");
199 xenbus_transaction_end(xbt, 1);
200 return;
201 }
202
203 if (sysrq_key != '\0')
204 xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
205
206 err = xenbus_transaction_end(xbt, 0);
207 if (err == -EAGAIN)
208 goto again;
209
210 if (sysrq_key != '\0')
211 handle_sysrq(sysrq_key, NULL);
212 }
213
214 static struct xenbus_watch shutdown_watch = {
215 .node = "control/shutdown",
216 .callback = shutdown_handler
217 };
218
219 static struct xenbus_watch sysrq_watch = {
220 .node = "control/sysrq",
221 .callback = sysrq_handler
222 };
223
224 static int setup_shutdown_watcher(void)
225 {
226 int err;
227
228 err = register_xenbus_watch(&shutdown_watch);
229 if (err) {
230 printk(KERN_ERR "Failed to set shutdown watcher\n");
231 return err;
232 }
233
234 err = register_xenbus_watch(&sysrq_watch);
235 if (err) {
236 printk(KERN_ERR "Failed to set sysrq watcher\n");
237 return err;
238 }
239
240 return 0;
241 }
242
243 static int shutdown_event(struct notifier_block *notifier,
244 unsigned long event,
245 void *data)
246 {
247 setup_shutdown_watcher();
248 return NOTIFY_DONE;
249 }
250
251 static int __init setup_shutdown_event(void)
252 {
253 static struct notifier_block xenstore_notifier = {
254 .notifier_call = shutdown_event
255 };
256 register_xenstore_notifier(&xenstore_notifier);
257
258 return 0;
259 }
260
261 subsys_initcall(setup_shutdown_event);
This page took 0.040661 seconds and 5 git commands to generate.