xen: maintain clock offset over save/restore
[linux-2.6.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/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 static int xen_suspend(void *data)
35 {
36         int *cancelled = data;
37         int err;
38
39         BUG_ON(!irqs_disabled());
40
41         load_cr3(swapper_pg_dir);
42
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;
48         }
49
50         xen_mm_pin_all();
51         gnttab_suspend();
52         xen_pre_suspend();
53
54         /*
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.
58          */
59         *cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info));
60
61         xen_post_suspend(*cancelled);
62         gnttab_resume();
63         xen_mm_unpin_all();
64
65         device_power_up();
66
67         if (!*cancelled) {
68                 xen_irq_resume();
69                 xen_console_resume();
70         }
71
72         return 0;
73 }
74
75 static void do_suspend(void)
76 {
77         int err;
78         int cancelled = 1;
79
80         shutting_down = SHUTDOWN_SUSPEND;
81
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;
90         }
91 #endif
92
93         err = device_suspend(PMSG_SUSPEND);
94         if (err) {
95                 printk(KERN_ERR "xen suspend: device_suspend %d\n", err);
96                 goto out;
97         }
98
99         printk("suspending xenbus...\n");
100         /* XXX use normal device tree? */
101         xenbus_suspend();
102
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;
107         }
108
109         if (!cancelled)
110                 xenbus_resume();
111         else
112                 xenbus_suspend_cancel();
113
114         device_resume();
115
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;
123 }
124
125 static void shutdown_handler(struct xenbus_watch *watch,
126                              const char **vec, unsigned int len)
127 {
128         char *str;
129         struct xenbus_transaction xbt;
130         int err;
131
132         if (shutting_down != SHUTDOWN_INVALID)
133                 return;
134
135  again:
136         err = xenbus_transaction_start(&xbt);
137         if (err)
138                 return;
139
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;
145         }
146
147         xenbus_write(xbt, "control", "shutdown", "");
148
149         err = xenbus_transaction_end(xbt, 0);
150         if (err == -EAGAIN) {
151                 kfree(str);
152                 goto again;
153         }
154
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;
169         }
170
171         kfree(str);
172 }
173
174 static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
175                           unsigned int len)
176 {
177         char sysrq_key = '\0';
178         struct xenbus_transaction xbt;
179         int err;
180
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;
190         }
191
192         if (sysrq_key != '\0')
193                 xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
194
195         err = xenbus_transaction_end(xbt, 0);
196         if (err == -EAGAIN)
197                 goto again;
198
199         if (sysrq_key != '\0')
200                 handle_sysrq(sysrq_key, NULL);
201 }
202
203 static struct xenbus_watch shutdown_watch = {
204         .node = "control/shutdown",
205         .callback = shutdown_handler
206 };
207
208 static struct xenbus_watch sysrq_watch = {
209         .node = "control/sysrq",
210         .callback = sysrq_handler
211 };
212
213 static int setup_shutdown_watcher(void)
214 {
215         int err;
216
217         err = register_xenbus_watch(&shutdown_watch);
218         if (err) {
219                 printk(KERN_ERR "Failed to set shutdown watcher\n");
220                 return err;
221         }
222
223         err = register_xenbus_watch(&sysrq_watch);
224         if (err) {
225                 printk(KERN_ERR "Failed to set sysrq watcher\n");
226                 return err;
227         }
228
229         return 0;
230 }
231
232 static int shutdown_event(struct notifier_block *notifier,
233                           unsigned long event,
234                           void *data)
235 {
236         setup_shutdown_watcher();
237         return NOTIFY_DONE;
238 }
239
240 static int __init setup_shutdown_event(void)
241 {
242         static struct notifier_block xenstore_notifier = {
243                 .notifier_call = shutdown_event
244         };
245         register_xenstore_notifier(&xenstore_notifier);
246
247         return 0;
248 }
249
250 subsys_initcall(setup_shutdown_event);