Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
[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
12 #include <xen/xen.h>
13 #include <xen/xenbus.h>
14 #include <xen/grant_table.h>
15 #include <xen/events.h>
16 #include <xen/hvc-console.h>
17 #include <xen/xen-ops.h>
18
19 #include <asm/xen/hypercall.h>
20 #include <asm/xen/page.h>
21 #include <asm/xen/hypervisor.h>
22
23 enum 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 };
33
34 /* Ignore multiple shutdown requests. */
35 static enum shutdown_state shutting_down = SHUTDOWN_INVALID;
36
37 struct suspend_info {
38         int cancelled;
39         unsigned long arg; /* extra hypercall argument */
40         void (*pre)(void);
41         void (*post)(int cancelled);
42 };
43
44 static void xen_hvm_post_suspend(int cancelled)
45 {
46         xen_arch_hvm_post_suspend(cancelled);
47         gnttab_resume();
48 }
49
50 static void xen_pre_suspend(void)
51 {
52         xen_mm_pin_all();
53         gnttab_suspend();
54         xen_arch_pre_suspend();
55 }
56
57 static void xen_post_suspend(int cancelled)
58 {
59         xen_arch_post_suspend(cancelled);
60         gnttab_resume();
61         xen_mm_unpin_all();
62 }
63
64 #ifdef CONFIG_HIBERNATE_CALLBACKS
65 static int xen_suspend(void *data)
66 {
67         struct suspend_info *si = data;
68         int err;
69
70         BUG_ON(!irqs_disabled());
71
72         err = sysdev_suspend(PMSG_FREEZE);
73         if (err) {
74                 printk(KERN_ERR "xen_suspend: sysdev_suspend failed: %d\n",
75                         err);
76                 return err;
77         }
78
79         if (si->pre)
80                 si->pre();
81
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          */
87         si->cancelled = HYPERVISOR_suspend(si->arg);
88
89         if (si->post)
90                 si->post(si->cancelled);
91
92         if (!si->cancelled) {
93                 xen_irq_resume();
94                 xen_console_resume();
95                 xen_timer_resume();
96         }
97
98         sysdev_resume();
99
100         return 0;
101 }
102
103 static void do_suspend(void)
104 {
105         int err;
106         struct suspend_info si;
107
108         shutting_down = SHUTDOWN_SUSPEND;
109
110 #ifdef CONFIG_PREEMPT
111         /* If the kernel is preemptible, we need to freeze all the processes
112            to prevent them from being in the middle of a pagetable update
113            during suspend. */
114         err = freeze_processes();
115         if (err) {
116                 printk(KERN_ERR "xen suspend: freeze failed %d\n", err);
117                 goto out;
118         }
119 #endif
120
121         err = dpm_suspend_start(PMSG_FREEZE);
122         if (err) {
123                 printk(KERN_ERR "xen suspend: dpm_suspend_start %d\n", err);
124                 goto out_thaw;
125         }
126
127         printk(KERN_DEBUG "suspending xenstore...\n");
128         xs_suspend();
129
130         err = dpm_suspend_noirq(PMSG_FREEZE);
131         if (err) {
132                 printk(KERN_ERR "dpm_suspend_noirq failed: %d\n", err);
133                 goto out_resume;
134         }
135
136         si.cancelled = 1;
137
138         if (xen_hvm_domain()) {
139                 si.arg = 0UL;
140                 si.pre = NULL;
141                 si.post = &xen_hvm_post_suspend;
142         } else {
143                 si.arg = virt_to_mfn(xen_start_info);
144                 si.pre = &xen_pre_suspend;
145                 si.post = &xen_post_suspend;
146         }
147
148         err = stop_machine(xen_suspend, &si, cpumask_of(0));
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 #ifdef CONFIG_PREEMPT
171         thaw_processes();
172 out:
173 #endif
174         shutting_down = SHUTDOWN_INVALID;
175 }
176 #endif  /* CONFIG_HIBERNATE_CALLBACKS */
177
178 struct shutdown_handler {
179         const char *command;
180         void (*cb)(void);
181 };
182
183 static void do_poweroff(void)
184 {
185         shutting_down = SHUTDOWN_POWEROFF;
186         orderly_poweroff(false);
187 }
188
189 static void do_reboot(void)
190 {
191         shutting_down = SHUTDOWN_POWEROFF; /* ? */
192         ctrl_alt_del();
193 }
194
195 static void shutdown_handler(struct xenbus_watch *watch,
196                              const char **vec, unsigned int len)
197 {
198         char *str;
199         struct xenbus_transaction xbt;
200         int err;
201         static struct shutdown_handler handlers[] = {
202                 { "poweroff",   do_poweroff },
203                 { "halt",       do_poweroff },
204                 { "reboot",     do_reboot   },
205 #ifdef CONFIG_HIBERNATE_CALLBACKS
206                 { "suspend",    do_suspend  },
207 #endif
208                 {NULL, NULL},
209         };
210         static struct shutdown_handler *handler;
211
212         if (shutting_down != SHUTDOWN_INVALID)
213                 return;
214
215  again:
216         err = xenbus_transaction_start(&xbt);
217         if (err)
218                 return;
219
220         str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
221         /* Ignore read errors and empty reads. */
222         if (XENBUS_IS_ERR_READ(str)) {
223                 xenbus_transaction_end(xbt, 1);
224                 return;
225         }
226
227         for (handler = &handlers[0]; handler->command; handler++) {
228                 if (strcmp(str, handler->command) == 0)
229                         break;
230         }
231
232         /* Only acknowledge commands which we are prepared to handle. */
233         if (handler->cb)
234                 xenbus_write(xbt, "control", "shutdown", "");
235
236         err = xenbus_transaction_end(xbt, 0);
237         if (err == -EAGAIN) {
238                 kfree(str);
239                 goto again;
240         }
241
242         if (handler->cb) {
243                 handler->cb();
244         } else {
245                 printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
246                 shutting_down = SHUTDOWN_INVALID;
247         }
248
249         kfree(str);
250 }
251
252 #ifdef CONFIG_MAGIC_SYSRQ
253 static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
254                           unsigned int len)
255 {
256         char sysrq_key = '\0';
257         struct xenbus_transaction xbt;
258         int err;
259
260  again:
261         err = xenbus_transaction_start(&xbt);
262         if (err)
263                 return;
264         if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
265                 printk(KERN_ERR "Unable to read sysrq code in "
266                        "control/sysrq\n");
267                 xenbus_transaction_end(xbt, 1);
268                 return;
269         }
270
271         if (sysrq_key != '\0')
272                 xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
273
274         err = xenbus_transaction_end(xbt, 0);
275         if (err == -EAGAIN)
276                 goto again;
277
278         if (sysrq_key != '\0')
279                 handle_sysrq(sysrq_key);
280 }
281
282 static struct xenbus_watch sysrq_watch = {
283         .node = "control/sysrq",
284         .callback = sysrq_handler
285 };
286 #endif
287
288 static struct xenbus_watch shutdown_watch = {
289         .node = "control/shutdown",
290         .callback = shutdown_handler
291 };
292
293 static int setup_shutdown_watcher(void)
294 {
295         int err;
296
297         err = register_xenbus_watch(&shutdown_watch);
298         if (err) {
299                 printk(KERN_ERR "Failed to set shutdown watcher\n");
300                 return err;
301         }
302
303 #ifdef CONFIG_MAGIC_SYSRQ
304         err = register_xenbus_watch(&sysrq_watch);
305         if (err) {
306                 printk(KERN_ERR "Failed to set sysrq watcher\n");
307                 return err;
308         }
309 #endif
310
311         return 0;
312 }
313
314 static int shutdown_event(struct notifier_block *notifier,
315                           unsigned long event,
316                           void *data)
317 {
318         setup_shutdown_watcher();
319         return NOTIFY_DONE;
320 }
321
322 int xen_setup_shutdown_event(void)
323 {
324         static struct notifier_block xenstore_notifier = {
325                 .notifier_call = shutdown_event
326         };
327
328         if (!xen_domain())
329                 return -ENODEV;
330         register_xenstore_notifier(&xenstore_notifier);
331
332         return 0;
333 }
334 EXPORT_SYMBOL_GPL(xen_setup_shutdown_event);
335
336 subsys_initcall(xen_setup_shutdown_event);