stop_machine: reimplement using cpu_stop
[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/slab.h>
7 #include <linux/reboot.h>
8 #include <linux/sysrq.h>
9 #include <linux/stop_machine.h>
10 #include <linux/freezer.h>
11
12 #include <xen/xenbus.h>
13 #include <xen/grant_table.h>
14 #include <xen/events.h>
15 #include <xen/hvc-console.h>
16 #include <xen/xen-ops.h>
17
18 #include <asm/xen/hypercall.h>
19 #include <asm/xen/page.h>
20
21 enum shutdown_state {
22         SHUTDOWN_INVALID = -1,
23         SHUTDOWN_POWEROFF = 0,
24         SHUTDOWN_SUSPEND = 2,
25         /* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only
26            report a crash, not be instructed to crash!
27            HALT is the same as POWEROFF, as far as we're concerned.  The tools use
28            the distinction when we return the reason code to them.  */
29          SHUTDOWN_HALT = 4,
30 };
31
32 /* Ignore multiple shutdown requests. */
33 static enum shutdown_state shutting_down = SHUTDOWN_INVALID;
34
35 #ifdef CONFIG_PM_SLEEP
36 static int xen_suspend(void *data)
37 {
38         int *cancelled = data;
39         int err;
40
41         BUG_ON(!irqs_disabled());
42
43         err = sysdev_suspend(PMSG_SUSPEND);
44         if (err) {
45                 printk(KERN_ERR "xen_suspend: sysdev_suspend 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         if (!*cancelled) {
66                 xen_irq_resume();
67                 xen_console_resume();
68                 xen_timer_resume();
69         }
70
71         sysdev_resume();
72
73         return 0;
74 }
75
76 static void do_suspend(void)
77 {
78         int err;
79         int cancelled = 1;
80
81         shutting_down = SHUTDOWN_SUSPEND;
82
83 #ifdef CONFIG_PREEMPT
84         /* If the kernel is preemptible, we need to freeze all the processes
85            to prevent them from being in the middle of a pagetable update
86            during suspend. */
87         err = freeze_processes();
88         if (err) {
89                 printk(KERN_ERR "xen suspend: freeze failed %d\n", err);
90                 goto out;
91         }
92 #endif
93
94         err = dpm_suspend_start(PMSG_SUSPEND);
95         if (err) {
96                 printk(KERN_ERR "xen suspend: dpm_suspend_start %d\n", err);
97                 goto out_thaw;
98         }
99
100         printk(KERN_DEBUG "suspending xenstore...\n");
101         xs_suspend();
102
103         err = dpm_suspend_noirq(PMSG_SUSPEND);
104         if (err) {
105                 printk(KERN_ERR "dpm_suspend_noirq failed: %d\n", err);
106                 goto out_resume;
107         }
108
109         err = stop_machine(xen_suspend, &cancelled, cpumask_of(0));
110
111         dpm_resume_noirq(PMSG_RESUME);
112
113         if (err) {
114                 printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
115                 cancelled = 1;
116         }
117
118 out_resume:
119         if (!cancelled) {
120                 xen_arch_resume();
121                 xs_resume();
122         } else
123                 xs_suspend_cancel();
124
125         dpm_resume_end(PMSG_RESUME);
126
127         /* Make sure timer events get retriggered on all CPUs */
128         clock_was_set();
129
130 out_thaw:
131 #ifdef CONFIG_PREEMPT
132         thaw_processes();
133 out:
134 #endif
135         shutting_down = SHUTDOWN_INVALID;
136 }
137 #endif  /* CONFIG_PM_SLEEP */
138
139 static void shutdown_handler(struct xenbus_watch *watch,
140                              const char **vec, unsigned int len)
141 {
142         char *str;
143         struct xenbus_transaction xbt;
144         int err;
145
146         if (shutting_down != SHUTDOWN_INVALID)
147                 return;
148
149  again:
150         err = xenbus_transaction_start(&xbt);
151         if (err)
152                 return;
153
154         str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
155         /* Ignore read errors and empty reads. */
156         if (XENBUS_IS_ERR_READ(str)) {
157                 xenbus_transaction_end(xbt, 1);
158                 return;
159         }
160
161         xenbus_write(xbt, "control", "shutdown", "");
162
163         err = xenbus_transaction_end(xbt, 0);
164         if (err == -EAGAIN) {
165                 kfree(str);
166                 goto again;
167         }
168
169         if (strcmp(str, "poweroff") == 0 ||
170             strcmp(str, "halt") == 0) {
171                 shutting_down = SHUTDOWN_POWEROFF;
172                 orderly_poweroff(false);
173         } else if (strcmp(str, "reboot") == 0) {
174                 shutting_down = SHUTDOWN_POWEROFF; /* ? */
175                 ctrl_alt_del();
176 #ifdef CONFIG_PM_SLEEP
177         } else if (strcmp(str, "suspend") == 0) {
178                 do_suspend();
179 #endif
180         } else {
181                 printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
182                 shutting_down = SHUTDOWN_INVALID;
183         }
184
185         kfree(str);
186 }
187
188 static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
189                           unsigned int len)
190 {
191         char sysrq_key = '\0';
192         struct xenbus_transaction xbt;
193         int err;
194
195  again:
196         err = xenbus_transaction_start(&xbt);
197         if (err)
198                 return;
199         if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
200                 printk(KERN_ERR "Unable to read sysrq code in "
201                        "control/sysrq\n");
202                 xenbus_transaction_end(xbt, 1);
203                 return;
204         }
205
206         if (sysrq_key != '\0')
207                 xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
208
209         err = xenbus_transaction_end(xbt, 0);
210         if (err == -EAGAIN)
211                 goto again;
212
213         if (sysrq_key != '\0')
214                 handle_sysrq(sysrq_key, NULL);
215 }
216
217 static struct xenbus_watch shutdown_watch = {
218         .node = "control/shutdown",
219         .callback = shutdown_handler
220 };
221
222 static struct xenbus_watch sysrq_watch = {
223         .node = "control/sysrq",
224         .callback = sysrq_handler
225 };
226
227 static int setup_shutdown_watcher(void)
228 {
229         int err;
230
231         err = register_xenbus_watch(&shutdown_watch);
232         if (err) {
233                 printk(KERN_ERR "Failed to set shutdown watcher\n");
234                 return err;
235         }
236
237         err = register_xenbus_watch(&sysrq_watch);
238         if (err) {
239                 printk(KERN_ERR "Failed to set sysrq watcher\n");
240                 return err;
241         }
242
243         return 0;
244 }
245
246 static int shutdown_event(struct notifier_block *notifier,
247                           unsigned long event,
248                           void *data)
249 {
250         setup_shutdown_watcher();
251         return NOTIFY_DONE;
252 }
253
254 static int __init setup_shutdown_event(void)
255 {
256         static struct notifier_block xenstore_notifier = {
257                 .notifier_call = shutdown_event
258         };
259         register_xenstore_notifier(&xenstore_notifier);
260
261         return 0;
262 }
263
264 subsys_initcall(setup_shutdown_event);