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