]> err.no Git - linux-2.6/blob - drivers/xen/manage.c
Merge branch 'core/topology' of git://git.kernel.org/pub/scm/linux/kernel/git/tip...
[linux-2.6] / 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/reboot.h>
7 #include <linux/sysrq.h>
8 #include <linux/stop_machine.h>
9 #include <linux/freezer.h>
10
11 #include <xen/xenbus.h>
12 #include <xen/grant_table.h>
13 #include <xen/events.h>
14 #include <xen/hvc-console.h>
15 #include <xen/xen-ops.h>
16
17 #include <asm/xen/hypercall.h>
18 #include <asm/xen/page.h>
19
20 enum shutdown_state {
21         SHUTDOWN_INVALID = -1,
22         SHUTDOWN_POWEROFF = 0,
23         SHUTDOWN_SUSPEND = 2,
24         /* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only
25            report a crash, not be instructed to crash!
26            HALT is the same as POWEROFF, as far as we're concerned.  The tools use
27            the distinction when we return the reason code to them.  */
28          SHUTDOWN_HALT = 4,
29 };
30
31 /* Ignore multiple shutdown requests. */
32 static enum shutdown_state shutting_down = SHUTDOWN_INVALID;
33
34 #ifdef CONFIG_PM_SLEEP
35 static int xen_suspend(void *data)
36 {
37         int *cancelled = data;
38         int err;
39
40         BUG_ON(!irqs_disabled());
41
42         load_cr3(swapper_pg_dir);
43
44         err = device_power_down(PMSG_SUSPEND);
45         if (err) {
46                 printk(KERN_ERR "xen_suspend: device_power_down failed: %d\n",
47                        err);
48                 return err;
49         }
50
51         xen_mm_pin_all();
52         gnttab_suspend();
53         xen_pre_suspend();
54
55         /*
56          * This hypercall returns 1 if suspend was cancelled
57          * or the domain was merely checkpointed, and 0 if it
58          * is resuming in a new domain.
59          */
60         *cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info));
61
62         xen_post_suspend(*cancelled);
63         gnttab_resume();
64         xen_mm_unpin_all();
65
66         device_power_up();
67
68         if (!*cancelled) {
69                 xen_irq_resume();
70                 xen_console_resume();
71         }
72
73         return 0;
74 }
75
76 static void do_suspend(void)
77 {
78         int err;
79         int cancelled = 1;
80
81         shutting_down = SHUTDOWN_SUSPEND;
82
83 #ifdef CONFIG_PREEMPT
84         /* If the kernel is preemptible, we need to freeze all the processes
85            to prevent them from being in the middle of a pagetable update
86            during suspend. */
87         err = freeze_processes();
88         if (err) {
89                 printk(KERN_ERR "xen suspend: freeze failed %d\n", err);
90                 return;
91         }
92 #endif
93
94         err = device_suspend(PMSG_SUSPEND);
95         if (err) {
96                 printk(KERN_ERR "xen suspend: device_suspend %d\n", err);
97                 goto out;
98         }
99
100         printk("suspending xenbus...\n");
101         /* XXX use normal device tree? */
102         xenbus_suspend();
103
104         err = stop_machine_run(xen_suspend, &cancelled, 0);
105         if (err) {
106                 printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
107                 goto out;
108         }
109
110         if (!cancelled)
111                 xenbus_resume();
112         else
113                 xenbus_suspend_cancel();
114
115         device_resume();
116
117         /* Make sure timer events get retriggered on all CPUs */
118         clock_was_set();
119 out:
120 #ifdef CONFIG_PREEMPT
121         thaw_processes();
122 #endif
123         shutting_down = SHUTDOWN_INVALID;
124 }
125 #endif  /* CONFIG_PM_SLEEP */
126
127 static void shutdown_handler(struct xenbus_watch *watch,
128                              const char **vec, unsigned int len)
129 {
130         char *str;
131         struct xenbus_transaction xbt;
132         int err;
133
134         if (shutting_down != SHUTDOWN_INVALID)
135                 return;
136
137  again:
138         err = xenbus_transaction_start(&xbt);
139         if (err)
140                 return;
141
142         str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
143         /* Ignore read errors and empty reads. */
144         if (XENBUS_IS_ERR_READ(str)) {
145                 xenbus_transaction_end(xbt, 1);
146                 return;
147         }
148
149         xenbus_write(xbt, "control", "shutdown", "");
150
151         err = xenbus_transaction_end(xbt, 0);
152         if (err == -EAGAIN) {
153                 kfree(str);
154                 goto again;
155         }
156
157         if (strcmp(str, "poweroff") == 0 ||
158             strcmp(str, "halt") == 0) {
159                 shutting_down = SHUTDOWN_POWEROFF;
160                 orderly_poweroff(false);
161         } else if (strcmp(str, "reboot") == 0) {
162                 shutting_down = SHUTDOWN_POWEROFF; /* ? */
163                 ctrl_alt_del();
164 #ifdef CONFIG_PM_SLEEP
165         } else if (strcmp(str, "suspend") == 0) {
166                 do_suspend();
167 #endif
168         } else {
169                 printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
170                 shutting_down = SHUTDOWN_INVALID;
171         }
172
173         kfree(str);
174 }
175
176 static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
177                           unsigned int len)
178 {
179         char sysrq_key = '\0';
180         struct xenbus_transaction xbt;
181         int err;
182
183  again:
184         err = xenbus_transaction_start(&xbt);
185         if (err)
186                 return;
187         if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
188                 printk(KERN_ERR "Unable to read sysrq code in "
189                        "control/sysrq\n");
190                 xenbus_transaction_end(xbt, 1);
191                 return;
192         }
193
194         if (sysrq_key != '\0')
195                 xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
196
197         err = xenbus_transaction_end(xbt, 0);
198         if (err == -EAGAIN)
199                 goto again;
200
201         if (sysrq_key != '\0')
202                 handle_sysrq(sysrq_key, NULL);
203 }
204
205 static struct xenbus_watch shutdown_watch = {
206         .node = "control/shutdown",
207         .callback = shutdown_handler
208 };
209
210 static struct xenbus_watch sysrq_watch = {
211         .node = "control/sysrq",
212         .callback = sysrq_handler
213 };
214
215 static int setup_shutdown_watcher(void)
216 {
217         int err;
218
219         err = register_xenbus_watch(&shutdown_watch);
220         if (err) {
221                 printk(KERN_ERR "Failed to set shutdown watcher\n");
222                 return err;
223         }
224
225         err = register_xenbus_watch(&sysrq_watch);
226         if (err) {
227                 printk(KERN_ERR "Failed to set sysrq watcher\n");
228                 return err;
229         }
230
231         return 0;
232 }
233
234 static int shutdown_event(struct notifier_block *notifier,
235                           unsigned long event,
236                           void *data)
237 {
238         setup_shutdown_watcher();
239         return NOTIFY_DONE;
240 }
241
242 static int __init setup_shutdown_event(void)
243 {
244         static struct notifier_block xenstore_notifier = {
245                 .notifier_call = shutdown_event
246         };
247         register_xenstore_notifier(&xenstore_notifier);
248
249         return 0;
250 }
251
252 subsys_initcall(setup_shutdown_event);