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