Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[linux-2.6.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_console_resume();
97                 xen_timer_resume();
98         }
99
100         syscore_resume();
101
102         return 0;
103 }
104
105 static void do_suspend(void)
106 {
107         int err;
108         struct suspend_info si;
109
110         shutting_down = SHUTDOWN_SUSPEND;
111
112 #ifdef CONFIG_PREEMPT
113         /* If the kernel is preemptible, we need to freeze all the processes
114            to prevent them from being in the middle of a pagetable update
115            during suspend. */
116         err = freeze_processes();
117         if (err) {
118                 printk(KERN_ERR "xen suspend: freeze failed %d\n", err);
119                 goto out;
120         }
121 #endif
122
123         err = dpm_suspend_start(PMSG_FREEZE);
124         if (err) {
125                 printk(KERN_ERR "xen suspend: dpm_suspend_start %d\n", err);
126                 goto out_thaw;
127         }
128
129         printk(KERN_DEBUG "suspending xenstore...\n");
130         xs_suspend();
131
132         err = dpm_suspend_noirq(PMSG_FREEZE);
133         if (err) {
134                 printk(KERN_ERR "dpm_suspend_noirq failed: %d\n", err);
135                 goto out_resume;
136         }
137
138         si.cancelled = 1;
139
140         if (xen_hvm_domain()) {
141                 si.arg = 0UL;
142                 si.pre = NULL;
143                 si.post = &xen_hvm_post_suspend;
144         } else {
145                 si.arg = virt_to_mfn(xen_start_info);
146                 si.pre = &xen_pre_suspend;
147                 si.post = &xen_post_suspend;
148         }
149
150         err = stop_machine(xen_suspend, &si, cpumask_of(0));
151
152         dpm_resume_noirq(si.cancelled ? PMSG_THAW : PMSG_RESTORE);
153
154         if (err) {
155                 printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
156                 si.cancelled = 1;
157         }
158
159 out_resume:
160         if (!si.cancelled) {
161                 xen_arch_resume();
162                 xs_resume();
163         } else
164                 xs_suspend_cancel();
165
166         dpm_resume_end(si.cancelled ? PMSG_THAW : PMSG_RESTORE);
167
168         /* Make sure timer events get retriggered on all CPUs */
169         clock_was_set();
170
171 out_thaw:
172 #ifdef CONFIG_PREEMPT
173         thaw_processes();
174 out:
175 #endif
176         shutting_down = SHUTDOWN_INVALID;
177 }
178 #endif  /* CONFIG_HIBERNATE_CALLBACKS */
179
180 struct shutdown_handler {
181         const char *command;
182         void (*cb)(void);
183 };
184
185 static void do_poweroff(void)
186 {
187         shutting_down = SHUTDOWN_POWEROFF;
188         orderly_poweroff(false);
189 }
190
191 static void do_reboot(void)
192 {
193         shutting_down = SHUTDOWN_POWEROFF; /* ? */
194         ctrl_alt_del();
195 }
196
197 static void shutdown_handler(struct xenbus_watch *watch,
198                              const char **vec, unsigned int len)
199 {
200         char *str;
201         struct xenbus_transaction xbt;
202         int err;
203         static struct shutdown_handler handlers[] = {
204                 { "poweroff",   do_poweroff },
205                 { "halt",       do_poweroff },
206                 { "reboot",     do_reboot   },
207 #ifdef CONFIG_HIBERNATE_CALLBACKS
208                 { "suspend",    do_suspend  },
209 #endif
210                 {NULL, NULL},
211         };
212         static struct shutdown_handler *handler;
213
214         if (shutting_down != SHUTDOWN_INVALID)
215                 return;
216
217  again:
218         err = xenbus_transaction_start(&xbt);
219         if (err)
220                 return;
221
222         str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
223         /* Ignore read errors and empty reads. */
224         if (XENBUS_IS_ERR_READ(str)) {
225                 xenbus_transaction_end(xbt, 1);
226                 return;
227         }
228
229         for (handler = &handlers[0]; handler->command; handler++) {
230                 if (strcmp(str, handler->command) == 0)
231                         break;
232         }
233
234         /* Only acknowledge commands which we are prepared to handle. */
235         if (handler->cb)
236                 xenbus_write(xbt, "control", "shutdown", "");
237
238         err = xenbus_transaction_end(xbt, 0);
239         if (err == -EAGAIN) {
240                 kfree(str);
241                 goto again;
242         }
243
244         if (handler->cb) {
245                 handler->cb();
246         } else {
247                 printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
248                 shutting_down = SHUTDOWN_INVALID;
249         }
250
251         kfree(str);
252 }
253
254 #ifdef CONFIG_MAGIC_SYSRQ
255 static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
256                           unsigned int len)
257 {
258         char sysrq_key = '\0';
259         struct xenbus_transaction xbt;
260         int err;
261
262  again:
263         err = xenbus_transaction_start(&xbt);
264         if (err)
265                 return;
266         if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
267                 printk(KERN_ERR "Unable to read sysrq code in "
268                        "control/sysrq\n");
269                 xenbus_transaction_end(xbt, 1);
270                 return;
271         }
272
273         if (sysrq_key != '\0')
274                 xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
275
276         err = xenbus_transaction_end(xbt, 0);
277         if (err == -EAGAIN)
278                 goto again;
279
280         if (sysrq_key != '\0')
281                 handle_sysrq(sysrq_key);
282 }
283
284 static struct xenbus_watch sysrq_watch = {
285         .node = "control/sysrq",
286         .callback = sysrq_handler
287 };
288 #endif
289
290 static struct xenbus_watch shutdown_watch = {
291         .node = "control/shutdown",
292         .callback = shutdown_handler
293 };
294
295 static int setup_shutdown_watcher(void)
296 {
297         int err;
298
299         err = register_xenbus_watch(&shutdown_watch);
300         if (err) {
301                 printk(KERN_ERR "Failed to set shutdown watcher\n");
302                 return err;
303         }
304
305 #ifdef CONFIG_MAGIC_SYSRQ
306         err = register_xenbus_watch(&sysrq_watch);
307         if (err) {
308                 printk(KERN_ERR "Failed to set sysrq watcher\n");
309                 return err;
310         }
311 #endif
312
313         return 0;
314 }
315
316 static int shutdown_event(struct notifier_block *notifier,
317                           unsigned long event,
318                           void *data)
319 {
320         setup_shutdown_watcher();
321         return NOTIFY_DONE;
322 }
323
324 int xen_setup_shutdown_event(void)
325 {
326         static struct notifier_block xenstore_notifier = {
327                 .notifier_call = shutdown_event
328         };
329
330         if (!xen_domain())
331                 return -ENODEV;
332         register_xenstore_notifier(&xenstore_notifier);
333
334         return 0;
335 }
336 EXPORT_SYMBOL_GPL(xen_setup_shutdown_event);
337
338 subsys_initcall(xen_setup_shutdown_event);