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