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