xen: suspend and resume system devices when running PVHVM
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / xen / manage.c
blob24177272bcb84aed3ec51cb82f91535f0c034fc0
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>
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>
19 #include <asm/xen/hypercall.h>
20 #include <asm/xen/page.h>
21 #include <asm/xen/hypervisor.h>
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,
34 /* Ignore multiple shutdown requests. */
35 static enum shutdown_state shutting_down = SHUTDOWN_INVALID;
37 #ifdef CONFIG_PM_SLEEP
38 static int xen_hvm_suspend(void *data)
40 int err;
41 struct sched_shutdown r = { .reason = SHUTDOWN_suspend };
42 int *cancelled = data;
44 BUG_ON(!irqs_disabled());
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;
53 *cancelled = HYPERVISOR_sched_op(SCHEDOP_shutdown, &r);
55 xen_hvm_post_suspend(*cancelled);
56 gnttab_resume();
58 if (!*cancelled) {
59 xen_irq_resume();
60 xen_console_resume();
61 xen_timer_resume();
64 sysdev_resume();
66 return 0;
69 static int xen_suspend(void *data)
71 int err;
72 int *cancelled = data;
74 BUG_ON(!irqs_disabled());
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;
83 xen_mm_pin_all();
84 gnttab_suspend();
85 xen_pre_suspend();
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.
92 *cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info));
94 xen_post_suspend(*cancelled);
95 gnttab_resume();
96 xen_mm_unpin_all();
98 if (!*cancelled) {
99 xen_irq_resume();
100 xen_console_resume();
101 xen_timer_resume();
104 sysdev_resume();
106 return 0;
109 static void do_suspend(void)
111 int err;
112 int cancelled = 1;
114 shutting_down = SHUTDOWN_SUSPEND;
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;
125 #endif
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;
133 printk(KERN_DEBUG "suspending xenstore...\n");
134 xs_suspend();
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;
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));
147 dpm_resume_noirq(PMSG_RESUME);
149 if (err) {
150 printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
151 cancelled = 1;
154 out_resume:
155 if (!cancelled) {
156 xen_arch_resume();
157 xs_resume();
158 } else
159 xs_suspend_cancel();
161 dpm_resume_end(PMSG_RESUME);
163 /* Make sure timer events get retriggered on all CPUs */
164 clock_was_set();
166 out_thaw:
167 #ifdef CONFIG_PREEMPT
168 thaw_processes();
169 out:
170 #endif
171 shutting_down = SHUTDOWN_INVALID;
173 #endif /* CONFIG_PM_SLEEP */
175 static void shutdown_handler(struct xenbus_watch *watch,
176 const char **vec, unsigned int len)
178 char *str;
179 struct xenbus_transaction xbt;
180 int err;
182 if (shutting_down != SHUTDOWN_INVALID)
183 return;
185 again:
186 err = xenbus_transaction_start(&xbt);
187 if (err)
188 return;
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;
197 xenbus_write(xbt, "control", "shutdown", "");
199 err = xenbus_transaction_end(xbt, 0);
200 if (err == -EAGAIN) {
201 kfree(str);
202 goto again;
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;
221 kfree(str);
224 #ifdef CONFIG_MAGIC_SYSRQ
225 static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
226 unsigned int len)
228 char sysrq_key = '\0';
229 struct xenbus_transaction xbt;
230 int err;
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;
243 if (sysrq_key != '\0')
244 xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
246 err = xenbus_transaction_end(xbt, 0);
247 if (err == -EAGAIN)
248 goto again;
250 if (sysrq_key != '\0')
251 handle_sysrq(sysrq_key);
254 static struct xenbus_watch sysrq_watch = {
255 .node = "control/sysrq",
256 .callback = sysrq_handler
258 #endif
260 static struct xenbus_watch shutdown_watch = {
261 .node = "control/shutdown",
262 .callback = shutdown_handler
265 static int setup_shutdown_watcher(void)
267 int err;
269 err = register_xenbus_watch(&shutdown_watch);
270 if (err) {
271 printk(KERN_ERR "Failed to set shutdown watcher\n");
272 return err;
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;
281 #endif
283 return 0;
286 static int shutdown_event(struct notifier_block *notifier,
287 unsigned long event,
288 void *data)
290 setup_shutdown_watcher();
291 return NOTIFY_DONE;
294 static int __init __setup_shutdown_event(void)
296 /* Delay initialization in the PV on HVM case */
297 if (xen_hvm_domain())
298 return 0;
300 if (!xen_pv_domain())
301 return -ENODEV;
303 return xen_setup_shutdown_event();
306 int xen_setup_shutdown_event(void)
308 static struct notifier_block xenstore_notifier = {
309 .notifier_call = shutdown_event
311 register_xenstore_notifier(&xenstore_notifier);
313 return 0;
315 EXPORT_SYMBOL_GPL(xen_setup_shutdown_event);
317 subsys_initcall(__setup_shutdown_event);