xen: resume interrupts before system devices.
[safe/jmp/linux-2.6] / 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 #ifdef CONFIG_PM_SLEEP
35 static int xen_suspend(void *data)
36 {
37         int *cancelled = data;
38         int err;
39
40         BUG_ON(!irqs_disabled());
41
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;
47         }
48         err = sysdev_suspend(PMSG_SUSPEND);
49         if (err) {
50                 printk(KERN_ERR "xen_suspend: sysdev_suspend failed: %d\n",
51                         err);
52                 device_power_up(PMSG_RESUME);
53                 return err;
54         }
55
56         xen_mm_pin_all();
57         gnttab_suspend();
58         xen_pre_suspend();
59
60         /*
61          * This hypercall returns 1 if suspend was cancelled
62          * or the domain was merely checkpointed, and 0 if it
63          * is resuming in a new domain.
64          */
65         *cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info));
66
67         xen_post_suspend(*cancelled);
68         gnttab_resume();
69         xen_mm_unpin_all();
70
71         if (!*cancelled) {
72                 xen_irq_resume();
73                 xen_console_resume();
74                 xen_timer_resume();
75         }
76
77         sysdev_resume();
78         device_power_up(PMSG_RESUME);
79
80         return 0;
81 }
82
83 static void do_suspend(void)
84 {
85         int err;
86         int cancelled = 1;
87
88         shutting_down = SHUTDOWN_SUSPEND;
89
90 #ifdef CONFIG_PREEMPT
91         /* If the kernel is preemptible, we need to freeze all the processes
92            to prevent them from being in the middle of a pagetable update
93            during suspend. */
94         err = freeze_processes();
95         if (err) {
96                 printk(KERN_ERR "xen suspend: freeze failed %d\n", err);
97                 return;
98         }
99 #endif
100
101         err = device_suspend(PMSG_SUSPEND);
102         if (err) {
103                 printk(KERN_ERR "xen suspend: device_suspend %d\n", err);
104                 goto out;
105         }
106
107         printk("suspending xenbus...\n");
108         /* XXX use normal device tree? */
109         xenbus_suspend();
110
111         err = stop_machine(xen_suspend, &cancelled, cpumask_of(0));
112         if (err) {
113                 printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
114                 goto out;
115         }
116
117         if (!cancelled) {
118                 xen_arch_resume();
119                 xenbus_resume();
120         } else
121                 xenbus_suspend_cancel();
122
123         device_resume(PMSG_RESUME);
124
125         /* Make sure timer events get retriggered on all CPUs */
126         clock_was_set();
127 out:
128 #ifdef CONFIG_PREEMPT
129         thaw_processes();
130 #endif
131         shutting_down = SHUTDOWN_INVALID;
132 }
133 #endif  /* CONFIG_PM_SLEEP */
134
135 static void shutdown_handler(struct xenbus_watch *watch,
136                              const char **vec, unsigned int len)
137 {
138         char *str;
139         struct xenbus_transaction xbt;
140         int err;
141
142         if (shutting_down != SHUTDOWN_INVALID)
143                 return;
144
145  again:
146         err = xenbus_transaction_start(&xbt);
147         if (err)
148                 return;
149
150         str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
151         /* Ignore read errors and empty reads. */
152         if (XENBUS_IS_ERR_READ(str)) {
153                 xenbus_transaction_end(xbt, 1);
154                 return;
155         }
156
157         xenbus_write(xbt, "control", "shutdown", "");
158
159         err = xenbus_transaction_end(xbt, 0);
160         if (err == -EAGAIN) {
161                 kfree(str);
162                 goto again;
163         }
164
165         if (strcmp(str, "poweroff") == 0 ||
166             strcmp(str, "halt") == 0) {
167                 shutting_down = SHUTDOWN_POWEROFF;
168                 orderly_poweroff(false);
169         } else if (strcmp(str, "reboot") == 0) {
170                 shutting_down = SHUTDOWN_POWEROFF; /* ? */
171                 ctrl_alt_del();
172 #ifdef CONFIG_PM_SLEEP
173         } else if (strcmp(str, "suspend") == 0) {
174                 do_suspend();
175 #endif
176         } else {
177                 printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
178                 shutting_down = SHUTDOWN_INVALID;
179         }
180
181         kfree(str);
182 }
183
184 static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
185                           unsigned int len)
186 {
187         char sysrq_key = '\0';
188         struct xenbus_transaction xbt;
189         int err;
190
191  again:
192         err = xenbus_transaction_start(&xbt);
193         if (err)
194                 return;
195         if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
196                 printk(KERN_ERR "Unable to read sysrq code in "
197                        "control/sysrq\n");
198                 xenbus_transaction_end(xbt, 1);
199                 return;
200         }
201
202         if (sysrq_key != '\0')
203                 xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
204
205         err = xenbus_transaction_end(xbt, 0);
206         if (err == -EAGAIN)
207                 goto again;
208
209         if (sysrq_key != '\0')
210                 handle_sysrq(sysrq_key, NULL);
211 }
212
213 static struct xenbus_watch shutdown_watch = {
214         .node = "control/shutdown",
215         .callback = shutdown_handler
216 };
217
218 static struct xenbus_watch sysrq_watch = {
219         .node = "control/sysrq",
220         .callback = sysrq_handler
221 };
222
223 static int setup_shutdown_watcher(void)
224 {
225         int err;
226
227         err = register_xenbus_watch(&shutdown_watch);
228         if (err) {
229                 printk(KERN_ERR "Failed to set shutdown watcher\n");
230                 return err;
231         }
232
233         err = register_xenbus_watch(&sysrq_watch);
234         if (err) {
235                 printk(KERN_ERR "Failed to set sysrq watcher\n");
236                 return err;
237         }
238
239         return 0;
240 }
241
242 static int shutdown_event(struct notifier_block *notifier,
243                           unsigned long event,
244                           void *data)
245 {
246         setup_shutdown_watcher();
247         return NOTIFY_DONE;
248 }
249
250 static int __init setup_shutdown_event(void)
251 {
252         static struct notifier_block xenstore_notifier = {
253                 .notifier_call = shutdown_event
254         };
255         register_xenstore_notifier(&xenstore_notifier);
256
257         return 0;
258 }
259
260 subsys_initcall(setup_shutdown_event);