include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[linux-2.6-block.git] / drivers / xen / manage.c
CommitLineData
3e2b8fbe
JF
1/*
2 * Handle extern requests for shutdown, reboot and sysrq
3 */
4#include <linux/kernel.h>
5#include <linux/err.h>
5a0e3ad6 6#include <linux/slab.h>
3e2b8fbe
JF
7#include <linux/reboot.h>
8#include <linux/sysrq.h>
0e91398f
JF
9#include <linux/stop_machine.h>
10#include <linux/freezer.h>
3e2b8fbe
JF
11
12#include <xen/xenbus.h>
0e91398f
JF
13#include <xen/grant_table.h>
14#include <xen/events.h>
15#include <xen/hvc-console.h>
16#include <xen/xen-ops.h>
3e2b8fbe 17
0e91398f
JF
18#include <asm/xen/hypercall.h>
19#include <asm/xen/page.h>
20
21enum 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};
3e2b8fbe
JF
31
32/* Ignore multiple shutdown requests. */
0e91398f
JF
33static enum shutdown_state shutting_down = SHUTDOWN_INVALID;
34
c7827728 35#ifdef CONFIG_PM_SLEEP
0e91398f
JF
36static int xen_suspend(void *data)
37{
38 int *cancelled = data;
359cdd3f 39 int err;
0e91398f
JF
40
41 BUG_ON(!irqs_disabled());
42
770824bd
RW
43 err = sysdev_suspend(PMSG_SUSPEND);
44 if (err) {
45 printk(KERN_ERR "xen_suspend: sysdev_suspend failed: %d\n",
46 err);
770824bd
RW
47 return err;
48 }
359cdd3f 49
0e91398f
JF
50 xen_mm_pin_all();
51 gnttab_suspend();
0e91398f
JF
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);
0e91398f
JF
62 gnttab_resume();
63 xen_mm_unpin_all();
64
65 if (!*cancelled) {
66 xen_irq_resume();
67 xen_console_resume();
ad55db9f 68 xen_timer_resume();
0e91398f
JF
69 }
70
1e6fcf84 71 sysdev_resume();
1e6fcf84 72
0e91398f
JF
73 return 0;
74}
75
76static void do_suspend(void)
77{
78 int err;
79 int cancelled = 1;
80
81 shutting_down = SHUTDOWN_SUSPEND;
82
b4606f21
IC
83 err = stop_machine_create();
84 if (err) {
85 printk(KERN_ERR "xen suspend: failed to setup stop_machine %d\n", err);
86 goto out;
87 }
88
0e91398f
JF
89#ifdef CONFIG_PREEMPT
90 /* If the kernel is preemptible, we need to freeze all the processes
91 to prevent them from being in the middle of a pagetable update
92 during suspend. */
93 err = freeze_processes();
94 if (err) {
95 printk(KERN_ERR "xen suspend: freeze failed %d\n", err);
b4606f21 96 goto out_destroy_sm;
0e91398f
JF
97 }
98#endif
99
d1616302 100 err = dpm_suspend_start(PMSG_SUSPEND);
0e91398f 101 if (err) {
d1616302 102 printk(KERN_ERR "xen suspend: dpm_suspend_start %d\n", err);
65f63384 103 goto out_thaw;
0e91398f
JF
104 }
105
c5cae661
IC
106 printk(KERN_DEBUG "suspending xenstore...\n");
107 xs_suspend();
108
d1616302 109 err = dpm_suspend_noirq(PMSG_SUSPEND);
2ed8d2b3 110 if (err) {
d1616302 111 printk(KERN_ERR "dpm_suspend_noirq failed: %d\n", err);
65f63384 112 goto out_resume;
2ed8d2b3
RW
113 }
114
f7df8ed1 115 err = stop_machine(xen_suspend, &cancelled, cpumask_of(0));
922cc38a
JF
116
117 dpm_resume_noirq(PMSG_RESUME);
118
0e91398f
JF
119 if (err) {
120 printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
65f63384 121 cancelled = 1;
0e91398f
JF
122 }
123
c5cae661 124out_resume:
ad55db9f
IY
125 if (!cancelled) {
126 xen_arch_resume();
de5b31bd 127 xs_resume();
ad55db9f 128 } else
de5b31bd 129 xs_suspend_cancel();
0e91398f 130
d1616302 131 dpm_resume_end(PMSG_RESUME);
0e91398f 132
359cdd3f
JF
133 /* Make sure timer events get retriggered on all CPUs */
134 clock_was_set();
65f63384
IC
135
136out_thaw:
0e91398f
JF
137#ifdef CONFIG_PREEMPT
138 thaw_processes();
b4606f21
IC
139
140out_destroy_sm:
0e91398f 141#endif
b4606f21
IC
142 stop_machine_destroy();
143
65f63384 144out:
0e91398f
JF
145 shutting_down = SHUTDOWN_INVALID;
146}
c7827728 147#endif /* CONFIG_PM_SLEEP */
3e2b8fbe
JF
148
149static void shutdown_handler(struct xenbus_watch *watch,
150 const char **vec, unsigned int len)
151{
152 char *str;
153 struct xenbus_transaction xbt;
154 int err;
155
156 if (shutting_down != SHUTDOWN_INVALID)
157 return;
158
159 again:
160 err = xenbus_transaction_start(&xbt);
161 if (err)
162 return;
163
164 str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
165 /* Ignore read errors and empty reads. */
166 if (XENBUS_IS_ERR_READ(str)) {
167 xenbus_transaction_end(xbt, 1);
168 return;
169 }
170
171 xenbus_write(xbt, "control", "shutdown", "");
172
173 err = xenbus_transaction_end(xbt, 0);
174 if (err == -EAGAIN) {
175 kfree(str);
176 goto again;
177 }
178
179 if (strcmp(str, "poweroff") == 0 ||
0e91398f
JF
180 strcmp(str, "halt") == 0) {
181 shutting_down = SHUTDOWN_POWEROFF;
3e2b8fbe 182 orderly_poweroff(false);
0e91398f
JF
183 } else if (strcmp(str, "reboot") == 0) {
184 shutting_down = SHUTDOWN_POWEROFF; /* ? */
3e2b8fbe 185 ctrl_alt_del();
0e91398f
JF
186#ifdef CONFIG_PM_SLEEP
187 } else if (strcmp(str, "suspend") == 0) {
188 do_suspend();
189#endif
190 } else {
3e2b8fbe
JF
191 printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
192 shutting_down = SHUTDOWN_INVALID;
193 }
194
195 kfree(str);
196}
197
198static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
199 unsigned int len)
200{
201 char sysrq_key = '\0';
202 struct xenbus_transaction xbt;
203 int err;
204
205 again:
206 err = xenbus_transaction_start(&xbt);
207 if (err)
208 return;
209 if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
210 printk(KERN_ERR "Unable to read sysrq code in "
211 "control/sysrq\n");
212 xenbus_transaction_end(xbt, 1);
213 return;
214 }
215
216 if (sysrq_key != '\0')
217 xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
218
219 err = xenbus_transaction_end(xbt, 0);
220 if (err == -EAGAIN)
221 goto again;
222
223 if (sysrq_key != '\0')
224 handle_sysrq(sysrq_key, NULL);
225}
226
227static struct xenbus_watch shutdown_watch = {
228 .node = "control/shutdown",
229 .callback = shutdown_handler
230};
231
232static struct xenbus_watch sysrq_watch = {
233 .node = "control/sysrq",
234 .callback = sysrq_handler
235};
236
237static int setup_shutdown_watcher(void)
238{
239 int err;
240
241 err = register_xenbus_watch(&shutdown_watch);
242 if (err) {
243 printk(KERN_ERR "Failed to set shutdown watcher\n");
244 return err;
245 }
246
247 err = register_xenbus_watch(&sysrq_watch);
248 if (err) {
249 printk(KERN_ERR "Failed to set sysrq watcher\n");
250 return err;
251 }
252
253 return 0;
254}
255
256static int shutdown_event(struct notifier_block *notifier,
257 unsigned long event,
258 void *data)
259{
260 setup_shutdown_watcher();
261 return NOTIFY_DONE;
262}
263
264static int __init setup_shutdown_event(void)
265{
266 static struct notifier_block xenstore_notifier = {
267 .notifier_call = shutdown_event
268 };
269 register_xenstore_notifier(&xenstore_notifier);
270
271 return 0;
272}
273
274subsys_initcall(setup_shutdown_event);