xen: maintain clock offset over save/restore
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / xen / manage.c
blob675c3dd23962ff45fa6c058250bbb0c834085be1
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 static int xen_suspend(void *data)
36 int *cancelled = data;
37 int err;
39 BUG_ON(!irqs_disabled());
41 load_cr3(swapper_pg_dir);
43 err = device_power_down(PMSG_SUSPEND);
44 if (err) {
45 printk(KERN_ERR "xen_suspend: device_power_down failed: %d\n",
46 err);
47 return err;
50 xen_mm_pin_all();
51 gnttab_suspend();
52 xen_pre_suspend();
55 * This hypercall returns 1 if suspend was cancelled
56 * or the domain was merely checkpointed, and 0 if it
57 * is resuming in a new domain.
59 *cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info));
61 xen_post_suspend(*cancelled);
62 gnttab_resume();
63 xen_mm_unpin_all();
65 device_power_up();
67 if (!*cancelled) {
68 xen_irq_resume();
69 xen_console_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_run(xen_suspend, &cancelled, 0);
104 if (err) {
105 printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
106 goto out;
109 if (!cancelled)
110 xenbus_resume();
111 else
112 xenbus_suspend_cancel();
114 device_resume();
116 /* Make sure timer events get retriggered on all CPUs */
117 clock_was_set();
118 out:
119 #ifdef CONFIG_PREEMPT
120 thaw_processes();
121 #endif
122 shutting_down = SHUTDOWN_INVALID;
125 static void shutdown_handler(struct xenbus_watch *watch,
126 const char **vec, unsigned int len)
128 char *str;
129 struct xenbus_transaction xbt;
130 int err;
132 if (shutting_down != SHUTDOWN_INVALID)
133 return;
135 again:
136 err = xenbus_transaction_start(&xbt);
137 if (err)
138 return;
140 str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
141 /* Ignore read errors and empty reads. */
142 if (XENBUS_IS_ERR_READ(str)) {
143 xenbus_transaction_end(xbt, 1);
144 return;
147 xenbus_write(xbt, "control", "shutdown", "");
149 err = xenbus_transaction_end(xbt, 0);
150 if (err == -EAGAIN) {
151 kfree(str);
152 goto again;
155 if (strcmp(str, "poweroff") == 0 ||
156 strcmp(str, "halt") == 0) {
157 shutting_down = SHUTDOWN_POWEROFF;
158 orderly_poweroff(false);
159 } else if (strcmp(str, "reboot") == 0) {
160 shutting_down = SHUTDOWN_POWEROFF; /* ? */
161 ctrl_alt_del();
162 #ifdef CONFIG_PM_SLEEP
163 } else if (strcmp(str, "suspend") == 0) {
164 do_suspend();
165 #endif
166 } else {
167 printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
168 shutting_down = SHUTDOWN_INVALID;
171 kfree(str);
174 static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
175 unsigned int len)
177 char sysrq_key = '\0';
178 struct xenbus_transaction xbt;
179 int err;
181 again:
182 err = xenbus_transaction_start(&xbt);
183 if (err)
184 return;
185 if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
186 printk(KERN_ERR "Unable to read sysrq code in "
187 "control/sysrq\n");
188 xenbus_transaction_end(xbt, 1);
189 return;
192 if (sysrq_key != '\0')
193 xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
195 err = xenbus_transaction_end(xbt, 0);
196 if (err == -EAGAIN)
197 goto again;
199 if (sysrq_key != '\0')
200 handle_sysrq(sysrq_key, NULL);
203 static struct xenbus_watch shutdown_watch = {
204 .node = "control/shutdown",
205 .callback = shutdown_handler
208 static struct xenbus_watch sysrq_watch = {
209 .node = "control/sysrq",
210 .callback = sysrq_handler
213 static int setup_shutdown_watcher(void)
215 int err;
217 err = register_xenbus_watch(&shutdown_watch);
218 if (err) {
219 printk(KERN_ERR "Failed to set shutdown watcher\n");
220 return err;
223 err = register_xenbus_watch(&sysrq_watch);
224 if (err) {
225 printk(KERN_ERR "Failed to set sysrq watcher\n");
226 return err;
229 return 0;
232 static int shutdown_event(struct notifier_block *notifier,
233 unsigned long event,
234 void *data)
236 setup_shutdown_watcher();
237 return NOTIFY_DONE;
240 static int __init setup_shutdown_event(void)
242 static struct notifier_block xenstore_notifier = {
243 .notifier_call = shutdown_event
245 register_xenstore_notifier(&xenstore_notifier);
247 return 0;
250 subsys_initcall(setup_shutdown_event);