Merge branch 'drm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied...
[linux-2.6/zen-sources.git] / drivers / xen / manage.c
blob9b91617b9582d320b67ce6c1984663d48659e03d
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>
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>
17 #include <asm/xen/hypercall.h>
18 #include <asm/xen/page.h>
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,
31 /* Ignore multiple shutdown requests. */
32 static enum shutdown_state shutting_down = SHUTDOWN_INVALID;
34 #ifdef CONFIG_PM_SLEEP
35 static int xen_suspend(void *data)
37 int *cancelled = data;
38 int err;
40 BUG_ON(!irqs_disabled());
42 err = device_power_down(PMSG_SUSPEND);
43 if (err) {
44 printk(KERN_ERR "xen_suspend: device_power_down failed: %d\n",
45 err);
46 return err;
49 xen_mm_pin_all();
50 gnttab_suspend();
51 xen_pre_suspend();
54 * This hypercall returns 1 if suspend was cancelled
55 * or the domain was merely checkpointed, and 0 if it
56 * is resuming in a new domain.
58 *cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info));
60 xen_post_suspend(*cancelled);
61 gnttab_resume();
62 xen_mm_unpin_all();
64 device_power_up(PMSG_RESUME);
66 if (!*cancelled) {
67 xen_irq_resume();
68 xen_console_resume();
69 xen_timer_resume();
72 return 0;
75 static void do_suspend(void)
77 int err;
78 int cancelled = 1;
80 shutting_down = SHUTDOWN_SUSPEND;
82 #ifdef CONFIG_PREEMPT
83 /* If the kernel is preemptible, we need to freeze all the processes
84 to prevent them from being in the middle of a pagetable update
85 during suspend. */
86 err = freeze_processes();
87 if (err) {
88 printk(KERN_ERR "xen suspend: freeze failed %d\n", err);
89 return;
91 #endif
93 err = device_suspend(PMSG_SUSPEND);
94 if (err) {
95 printk(KERN_ERR "xen suspend: device_suspend %d\n", err);
96 goto out;
99 printk("suspending xenbus...\n");
100 /* XXX use normal device tree? */
101 xenbus_suspend();
103 err = stop_machine(xen_suspend, &cancelled, &cpumask_of_cpu(0));
104 if (err) {
105 printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
106 goto out;
109 if (!cancelled) {
110 xen_arch_resume();
111 xenbus_resume();
112 } else
113 xenbus_suspend_cancel();
115 device_resume(PMSG_RESUME);
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;
125 #endif /* CONFIG_PM_SLEEP */
127 static void shutdown_handler(struct xenbus_watch *watch,
128 const char **vec, unsigned int len)
130 char *str;
131 struct xenbus_transaction xbt;
132 int err;
134 if (shutting_down != SHUTDOWN_INVALID)
135 return;
137 again:
138 err = xenbus_transaction_start(&xbt);
139 if (err)
140 return;
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;
149 xenbus_write(xbt, "control", "shutdown", "");
151 err = xenbus_transaction_end(xbt, 0);
152 if (err == -EAGAIN) {
153 kfree(str);
154 goto again;
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;
173 kfree(str);
176 static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
177 unsigned int len)
179 char sysrq_key = '\0';
180 struct xenbus_transaction xbt;
181 int err;
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;
194 if (sysrq_key != '\0')
195 xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
197 err = xenbus_transaction_end(xbt, 0);
198 if (err == -EAGAIN)
199 goto again;
201 if (sysrq_key != '\0')
202 handle_sysrq(sysrq_key, NULL);
205 static struct xenbus_watch shutdown_watch = {
206 .node = "control/shutdown",
207 .callback = shutdown_handler
210 static struct xenbus_watch sysrq_watch = {
211 .node = "control/sysrq",
212 .callback = sysrq_handler
215 static int setup_shutdown_watcher(void)
217 int err;
219 err = register_xenbus_watch(&shutdown_watch);
220 if (err) {
221 printk(KERN_ERR "Failed to set shutdown watcher\n");
222 return err;
225 err = register_xenbus_watch(&sysrq_watch);
226 if (err) {
227 printk(KERN_ERR "Failed to set sysrq watcher\n");
228 return err;
231 return 0;
234 static int shutdown_event(struct notifier_block *notifier,
235 unsigned long event,
236 void *data)
238 setup_shutdown_watcher();
239 return NOTIFY_DONE;
242 static int __init setup_shutdown_event(void)
244 static struct notifier_block xenstore_notifier = {
245 .notifier_call = shutdown_event
247 register_xenstore_notifier(&xenstore_notifier);
249 return 0;
252 subsys_initcall(setup_shutdown_event);