Merge remote branch 'origin/x86/cpu' into x86/amd-nb
[deliverable/linux.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/xen.h>
13 #include <xen/xenbus.h>
14 #include <xen/grant_table.h>
15 #include <xen/events.h>
16 #include <xen/hvc-console.h>
17 #include <xen/xen-ops.h>
18
19 #include <asm/xen/hypercall.h>
20 #include <asm/xen/page.h>
21 #include <asm/xen/hypervisor.h>
22
23 enum shutdown_state {
24 SHUTDOWN_INVALID = -1,
25 SHUTDOWN_POWEROFF = 0,
26 SHUTDOWN_SUSPEND = 2,
27 /* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only
28 report a crash, not be instructed to crash!
29 HALT is the same as POWEROFF, as far as we're concerned. The tools use
30 the distinction when we return the reason code to them. */
31 SHUTDOWN_HALT = 4,
32 };
33
34 /* Ignore multiple shutdown requests. */
35 static enum shutdown_state shutting_down = SHUTDOWN_INVALID;
36
37 #ifdef CONFIG_PM_SLEEP
38 static int xen_hvm_suspend(void *data)
39 {
40 struct sched_shutdown r = { .reason = SHUTDOWN_suspend };
41 int *cancelled = data;
42
43 BUG_ON(!irqs_disabled());
44
45 *cancelled = HYPERVISOR_sched_op(SCHEDOP_shutdown, &r);
46
47 xen_hvm_post_suspend(*cancelled);
48 gnttab_resume();
49
50 if (!*cancelled) {
51 xen_irq_resume();
52 xen_timer_resume();
53 }
54
55 return 0;
56 }
57
58 static int xen_suspend(void *data)
59 {
60 int err;
61 int *cancelled = data;
62
63 BUG_ON(!irqs_disabled());
64
65 err = sysdev_suspend(PMSG_SUSPEND);
66 if (err) {
67 printk(KERN_ERR "xen_suspend: sysdev_suspend failed: %d\n",
68 err);
69 return err;
70 }
71
72 xen_mm_pin_all();
73 gnttab_suspend();
74 xen_pre_suspend();
75
76 /*
77 * This hypercall returns 1 if suspend was cancelled
78 * or the domain was merely checkpointed, and 0 if it
79 * is resuming in a new domain.
80 */
81 *cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info));
82
83 xen_post_suspend(*cancelled);
84 gnttab_resume();
85 xen_mm_unpin_all();
86
87 if (!*cancelled) {
88 xen_irq_resume();
89 xen_console_resume();
90 xen_timer_resume();
91 }
92
93 sysdev_resume();
94
95 return 0;
96 }
97
98 static void do_suspend(void)
99 {
100 int err;
101 int cancelled = 1;
102
103 shutting_down = SHUTDOWN_SUSPEND;
104
105 #ifdef CONFIG_PREEMPT
106 /* If the kernel is preemptible, we need to freeze all the processes
107 to prevent them from being in the middle of a pagetable update
108 during suspend. */
109 err = freeze_processes();
110 if (err) {
111 printk(KERN_ERR "xen suspend: freeze failed %d\n", err);
112 goto out;
113 }
114 #endif
115
116 err = dpm_suspend_start(PMSG_SUSPEND);
117 if (err) {
118 printk(KERN_ERR "xen suspend: dpm_suspend_start %d\n", err);
119 goto out_thaw;
120 }
121
122 printk(KERN_DEBUG "suspending xenstore...\n");
123 xs_suspend();
124
125 err = dpm_suspend_noirq(PMSG_SUSPEND);
126 if (err) {
127 printk(KERN_ERR "dpm_suspend_noirq failed: %d\n", err);
128 goto out_resume;
129 }
130
131 if (xen_hvm_domain())
132 err = stop_machine(xen_hvm_suspend, &cancelled, cpumask_of(0));
133 else
134 err = stop_machine(xen_suspend, &cancelled, cpumask_of(0));
135
136 dpm_resume_noirq(PMSG_RESUME);
137
138 if (err) {
139 printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
140 cancelled = 1;
141 }
142
143 out_resume:
144 if (!cancelled) {
145 xen_arch_resume();
146 xs_resume();
147 } else
148 xs_suspend_cancel();
149
150 dpm_resume_end(PMSG_RESUME);
151
152 /* Make sure timer events get retriggered on all CPUs */
153 clock_was_set();
154
155 out_thaw:
156 #ifdef CONFIG_PREEMPT
157 thaw_processes();
158 out:
159 #endif
160 shutting_down = SHUTDOWN_INVALID;
161 }
162 #endif /* CONFIG_PM_SLEEP */
163
164 static void shutdown_handler(struct xenbus_watch *watch,
165 const char **vec, unsigned int len)
166 {
167 char *str;
168 struct xenbus_transaction xbt;
169 int err;
170
171 if (shutting_down != SHUTDOWN_INVALID)
172 return;
173
174 again:
175 err = xenbus_transaction_start(&xbt);
176 if (err)
177 return;
178
179 str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
180 /* Ignore read errors and empty reads. */
181 if (XENBUS_IS_ERR_READ(str)) {
182 xenbus_transaction_end(xbt, 1);
183 return;
184 }
185
186 xenbus_write(xbt, "control", "shutdown", "");
187
188 err = xenbus_transaction_end(xbt, 0);
189 if (err == -EAGAIN) {
190 kfree(str);
191 goto again;
192 }
193
194 if (strcmp(str, "poweroff") == 0 ||
195 strcmp(str, "halt") == 0) {
196 shutting_down = SHUTDOWN_POWEROFF;
197 orderly_poweroff(false);
198 } else if (strcmp(str, "reboot") == 0) {
199 shutting_down = SHUTDOWN_POWEROFF; /* ? */
200 ctrl_alt_del();
201 #ifdef CONFIG_PM_SLEEP
202 } else if (strcmp(str, "suspend") == 0) {
203 do_suspend();
204 #endif
205 } else {
206 printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
207 shutting_down = SHUTDOWN_INVALID;
208 }
209
210 kfree(str);
211 }
212
213 #ifdef CONFIG_MAGIC_SYSRQ
214 static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
215 unsigned int len)
216 {
217 char sysrq_key = '\0';
218 struct xenbus_transaction xbt;
219 int err;
220
221 again:
222 err = xenbus_transaction_start(&xbt);
223 if (err)
224 return;
225 if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
226 printk(KERN_ERR "Unable to read sysrq code in "
227 "control/sysrq\n");
228 xenbus_transaction_end(xbt, 1);
229 return;
230 }
231
232 if (sysrq_key != '\0')
233 xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
234
235 err = xenbus_transaction_end(xbt, 0);
236 if (err == -EAGAIN)
237 goto again;
238
239 if (sysrq_key != '\0')
240 handle_sysrq(sysrq_key);
241 }
242
243 static struct xenbus_watch sysrq_watch = {
244 .node = "control/sysrq",
245 .callback = sysrq_handler
246 };
247 #endif
248
249 static struct xenbus_watch shutdown_watch = {
250 .node = "control/shutdown",
251 .callback = shutdown_handler
252 };
253
254 static int setup_shutdown_watcher(void)
255 {
256 int err;
257
258 err = register_xenbus_watch(&shutdown_watch);
259 if (err) {
260 printk(KERN_ERR "Failed to set shutdown watcher\n");
261 return err;
262 }
263
264 #ifdef CONFIG_MAGIC_SYSRQ
265 err = register_xenbus_watch(&sysrq_watch);
266 if (err) {
267 printk(KERN_ERR "Failed to set sysrq watcher\n");
268 return err;
269 }
270 #endif
271
272 return 0;
273 }
274
275 static int shutdown_event(struct notifier_block *notifier,
276 unsigned long event,
277 void *data)
278 {
279 setup_shutdown_watcher();
280 return NOTIFY_DONE;
281 }
282
283 static int __init __setup_shutdown_event(void)
284 {
285 /* Delay initialization in the PV on HVM case */
286 if (xen_hvm_domain())
287 return 0;
288
289 if (!xen_pv_domain())
290 return -ENODEV;
291
292 return xen_setup_shutdown_event();
293 }
294
295 int xen_setup_shutdown_event(void)
296 {
297 static struct notifier_block xenstore_notifier = {
298 .notifier_call = shutdown_event
299 };
300 register_xenstore_notifier(&xenstore_notifier);
301
302 return 0;
303 }
304 EXPORT_SYMBOL_GPL(xen_setup_shutdown_event);
305
306 subsys_initcall(__setup_shutdown_event);
This page took 0.071386 seconds and 6 git commands to generate.