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