Merge branches 'stable/ia64', 'stable/blkfront-cleanup' and 'stable/cleanup' of git...
[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 #ifdef CONFIG_PM_SLEEP
38 static int xen_hvm_suspend(void *data)
39 {
40         int err;
41         struct sched_shutdown r = { .reason = SHUTDOWN_suspend };
42         int *cancelled = data;
43
44         BUG_ON(!irqs_disabled());
45
46         err = sysdev_suspend(PMSG_SUSPEND);
47         if (err) {
48                 printk(KERN_ERR "xen_hvm_suspend: sysdev_suspend failed: %d\n",
49                        err);
50                 return err;
51         }
52
53         *cancelled = HYPERVISOR_sched_op(SCHEDOP_shutdown, &r);
54
55         xen_hvm_post_suspend(*cancelled);
56         gnttab_resume();
57
58         if (!*cancelled) {
59                 xen_irq_resume();
60                 xen_console_resume();
61                 xen_timer_resume();
62         }
63
64         sysdev_resume();
65
66         return 0;
67 }
68
69 static int xen_suspend(void *data)
70 {
71         int err;
72         int *cancelled = data;
73
74         BUG_ON(!irqs_disabled());
75
76         err = sysdev_suspend(PMSG_SUSPEND);
77         if (err) {
78                 printk(KERN_ERR "xen_suspend: sysdev_suspend failed: %d\n",
79                         err);
80                 return err;
81         }
82
83         xen_mm_pin_all();
84         gnttab_suspend();
85         xen_pre_suspend();
86
87         /*
88          * This hypercall returns 1 if suspend was cancelled
89          * or the domain was merely checkpointed, and 0 if it
90          * is resuming in a new domain.
91          */
92         *cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info));
93
94         xen_post_suspend(*cancelled);
95         gnttab_resume();
96         xen_mm_unpin_all();
97
98         if (!*cancelled) {
99                 xen_irq_resume();
100                 xen_console_resume();
101                 xen_timer_resume();
102         }
103
104         sysdev_resume();
105
106         return 0;
107 }
108
109 static void do_suspend(void)
110 {
111         int err;
112         int cancelled = 1;
113
114         shutting_down = SHUTDOWN_SUSPEND;
115
116 #ifdef CONFIG_PREEMPT
117         /* If the kernel is preemptible, we need to freeze all the processes
118            to prevent them from being in the middle of a pagetable update
119            during suspend. */
120         err = freeze_processes();
121         if (err) {
122                 printk(KERN_ERR "xen suspend: freeze failed %d\n", err);
123                 goto out;
124         }
125 #endif
126
127         err = dpm_suspend_start(PMSG_SUSPEND);
128         if (err) {
129                 printk(KERN_ERR "xen suspend: dpm_suspend_start %d\n", err);
130                 goto out_thaw;
131         }
132
133         printk(KERN_DEBUG "suspending xenstore...\n");
134         xs_suspend();
135
136         err = dpm_suspend_noirq(PMSG_SUSPEND);
137         if (err) {
138                 printk(KERN_ERR "dpm_suspend_noirq failed: %d\n", err);
139                 goto out_resume;
140         }
141
142         if (xen_hvm_domain())
143                 err = stop_machine(xen_hvm_suspend, &cancelled, cpumask_of(0));
144         else
145                 err = stop_machine(xen_suspend, &cancelled, cpumask_of(0));
146
147         dpm_resume_noirq(PMSG_RESUME);
148
149         if (err) {
150                 printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
151                 cancelled = 1;
152         }
153
154 out_resume:
155         if (!cancelled) {
156                 xen_arch_resume();
157                 xs_resume();
158         } else
159                 xs_suspend_cancel();
160
161         dpm_resume_end(PMSG_RESUME);
162
163         /* Make sure timer events get retriggered on all CPUs */
164         clock_was_set();
165
166 out_thaw:
167 #ifdef CONFIG_PREEMPT
168         thaw_processes();
169 out:
170 #endif
171         shutting_down = SHUTDOWN_INVALID;
172 }
173 #endif  /* CONFIG_PM_SLEEP */
174
175 static void shutdown_handler(struct xenbus_watch *watch,
176                              const char **vec, unsigned int len)
177 {
178         char *str;
179         struct xenbus_transaction xbt;
180         int err;
181
182         if (shutting_down != SHUTDOWN_INVALID)
183                 return;
184
185  again:
186         err = xenbus_transaction_start(&xbt);
187         if (err)
188                 return;
189
190         str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
191         /* Ignore read errors and empty reads. */
192         if (XENBUS_IS_ERR_READ(str)) {
193                 xenbus_transaction_end(xbt, 1);
194                 return;
195         }
196
197         xenbus_write(xbt, "control", "shutdown", "");
198
199         err = xenbus_transaction_end(xbt, 0);
200         if (err == -EAGAIN) {
201                 kfree(str);
202                 goto again;
203         }
204
205         if (strcmp(str, "poweroff") == 0 ||
206             strcmp(str, "halt") == 0) {
207                 shutting_down = SHUTDOWN_POWEROFF;
208                 orderly_poweroff(false);
209         } else if (strcmp(str, "reboot") == 0) {
210                 shutting_down = SHUTDOWN_POWEROFF; /* ? */
211                 ctrl_alt_del();
212 #ifdef CONFIG_PM_SLEEP
213         } else if (strcmp(str, "suspend") == 0) {
214                 do_suspend();
215 #endif
216         } else {
217                 printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
218                 shutting_down = SHUTDOWN_INVALID;
219         }
220
221         kfree(str);
222 }
223
224 #ifdef CONFIG_MAGIC_SYSRQ
225 static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
226                           unsigned int len)
227 {
228         char sysrq_key = '\0';
229         struct xenbus_transaction xbt;
230         int err;
231
232  again:
233         err = xenbus_transaction_start(&xbt);
234         if (err)
235                 return;
236         if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
237                 printk(KERN_ERR "Unable to read sysrq code in "
238                        "control/sysrq\n");
239                 xenbus_transaction_end(xbt, 1);
240                 return;
241         }
242
243         if (sysrq_key != '\0')
244                 xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
245
246         err = xenbus_transaction_end(xbt, 0);
247         if (err == -EAGAIN)
248                 goto again;
249
250         if (sysrq_key != '\0')
251                 handle_sysrq(sysrq_key);
252 }
253
254 static struct xenbus_watch sysrq_watch = {
255         .node = "control/sysrq",
256         .callback = sysrq_handler
257 };
258 #endif
259
260 static struct xenbus_watch shutdown_watch = {
261         .node = "control/shutdown",
262         .callback = shutdown_handler
263 };
264
265 static int setup_shutdown_watcher(void)
266 {
267         int err;
268
269         err = register_xenbus_watch(&shutdown_watch);
270         if (err) {
271                 printk(KERN_ERR "Failed to set shutdown watcher\n");
272                 return err;
273         }
274
275 #ifdef CONFIG_MAGIC_SYSRQ
276         err = register_xenbus_watch(&sysrq_watch);
277         if (err) {
278                 printk(KERN_ERR "Failed to set sysrq watcher\n");
279                 return err;
280         }
281 #endif
282
283         return 0;
284 }
285
286 static int shutdown_event(struct notifier_block *notifier,
287                           unsigned long event,
288                           void *data)
289 {
290         setup_shutdown_watcher();
291         return NOTIFY_DONE;
292 }
293
294 static int __init __setup_shutdown_event(void)
295 {
296         /* Delay initialization in the PV on HVM case */
297         if (xen_hvm_domain())
298                 return 0;
299
300         if (!xen_pv_domain())
301                 return -ENODEV;
302
303         return xen_setup_shutdown_event();
304 }
305
306 int xen_setup_shutdown_event(void)
307 {
308         static struct notifier_block xenstore_notifier = {
309                 .notifier_call = shutdown_event
310         };
311         register_xenstore_notifier(&xenstore_notifier);
312
313         return 0;
314 }
315 EXPORT_SYMBOL_GPL(xen_setup_shutdown_event);
316
317 subsys_initcall(__setup_shutdown_event);