Merge tag 'perf-urgent-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git...
[deliverable/linux.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>
19234c08 11#include <linux/syscore_ops.h>
63c9744b 12#include <linux/export.h>
3e2b8fbe 13
016b6f5f 14#include <xen/xen.h>
3e2b8fbe 15#include <xen/xenbus.h>
0e91398f
JF
16#include <xen/grant_table.h>
17#include <xen/events.h>
18#include <xen/hvc-console.h>
19#include <xen/xen-ops.h>
3e2b8fbe 20
0e91398f
JF
21#include <asm/xen/hypercall.h>
22#include <asm/xen/page.h>
016b6f5f 23#include <asm/xen/hypervisor.h>
0e91398f
JF
24
25enum shutdown_state {
26 SHUTDOWN_INVALID = -1,
27 SHUTDOWN_POWEROFF = 0,
28 SHUTDOWN_SUSPEND = 2,
29 /* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only
30 report a crash, not be instructed to crash!
31 HALT is the same as POWEROFF, as far as we're concerned. The tools use
32 the distinction when we return the reason code to them. */
33 SHUTDOWN_HALT = 4,
34};
3e2b8fbe
JF
35
36/* Ignore multiple shutdown requests. */
0e91398f
JF
37static enum shutdown_state shutting_down = SHUTDOWN_INVALID;
38
ceb18029
IC
39struct suspend_info {
40 int cancelled;
36b401e2 41 unsigned long arg; /* extra hypercall argument */
55fb4ace
IC
42 void (*pre)(void);
43 void (*post)(int cancelled);
ceb18029
IC
44};
45
07af3810 46static void xen_hvm_post_suspend(int cancelled)
82043bb6 47{
07af3810 48 xen_arch_hvm_post_suspend(cancelled);
82043bb6
IC
49 gnttab_resume();
50}
51
52static void xen_pre_suspend(void)
53{
54 xen_mm_pin_all();
55 gnttab_suspend();
07af3810 56 xen_arch_pre_suspend();
82043bb6
IC
57}
58
07af3810 59static void xen_post_suspend(int cancelled)
82043bb6 60{
07af3810 61 xen_arch_post_suspend(cancelled);
82043bb6
IC
62 gnttab_resume();
63 xen_mm_unpin_all();
64}
65
1f112cee 66#ifdef CONFIG_HIBERNATE_CALLBACKS
016b6f5f
SS
67static int xen_suspend(void *data)
68{
ceb18029 69 struct suspend_info *si = data;
359cdd3f 70 int err;
0e91398f
JF
71
72 BUG_ON(!irqs_disabled());
73
2e711c04 74 err = syscore_suspend();
770824bd 75 if (err) {
19234c08 76 printk(KERN_ERR "xen_suspend: system core suspend failed: %d\n",
770824bd 77 err);
770824bd
RW
78 return err;
79 }
359cdd3f 80
55fb4ace
IC
81 if (si->pre)
82 si->pre();
0e91398f
JF
83
84 /*
85 * This hypercall returns 1 if suspend was cancelled
86 * or the domain was merely checkpointed, and 0 if it
87 * is resuming in a new domain.
88 */
36b401e2 89 si->cancelled = HYPERVISOR_suspend(si->arg);
0e91398f 90
55fb4ace
IC
91 if (si->post)
92 si->post(si->cancelled);
0e91398f 93
ceb18029 94 if (!si->cancelled) {
0e91398f
JF
95 xen_irq_resume();
96 xen_console_resume();
ad55db9f 97 xen_timer_resume();
0e91398f
JF
98 }
99
19234c08 100 syscore_resume();
1e6fcf84 101
0e91398f
JF
102 return 0;
103}
104
105static void do_suspend(void)
106{
107 int err;
ceb18029 108 struct suspend_info si;
0e91398f
JF
109
110 shutting_down = SHUTDOWN_SUSPEND;
111
112#ifdef CONFIG_PREEMPT
113 /* If the kernel is preemptible, we need to freeze all the processes
114 to prevent them from being in the middle of a pagetable update
115 during suspend. */
116 err = freeze_processes();
117 if (err) {
118 printk(KERN_ERR "xen suspend: freeze failed %d\n", err);
3fc1f1e2 119 goto out;
0e91398f
JF
120 }
121#endif
122
b3e96c0c 123 err = dpm_suspend_start(PMSG_FREEZE);
0e91398f 124 if (err) {
d1616302 125 printk(KERN_ERR "xen suspend: dpm_suspend_start %d\n", err);
65f63384 126 goto out_thaw;
0e91398f
JF
127 }
128
c5cae661
IC
129 printk(KERN_DEBUG "suspending xenstore...\n");
130 xs_suspend();
131
cf579dfb 132 err = dpm_suspend_end(PMSG_FREEZE);
2ed8d2b3 133 if (err) {
cf579dfb 134 printk(KERN_ERR "dpm_suspend_end failed: %d\n", err);
65f63384 135 goto out_resume;
2ed8d2b3
RW
136 }
137
ceb18029
IC
138 si.cancelled = 1;
139
55fb4ace 140 if (xen_hvm_domain()) {
36b401e2 141 si.arg = 0UL;
55fb4ace
IC
142 si.pre = NULL;
143 si.post = &xen_hvm_post_suspend;
144 } else {
36b401e2 145 si.arg = virt_to_mfn(xen_start_info);
55fb4ace
IC
146 si.pre = &xen_pre_suspend;
147 si.post = &xen_post_suspend;
148 }
36b401e2 149
b056b6a0 150 err = stop_machine(xen_suspend, &si, cpumask_of(0));
922cc38a 151
cf579dfb 152 dpm_resume_start(si.cancelled ? PMSG_THAW : PMSG_RESTORE);
922cc38a 153
0e91398f
JF
154 if (err) {
155 printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
ceb18029 156 si.cancelled = 1;
0e91398f
JF
157 }
158
c5cae661 159out_resume:
ceb18029 160 if (!si.cancelled) {
ad55db9f 161 xen_arch_resume();
de5b31bd 162 xs_resume();
ad55db9f 163 } else
de5b31bd 164 xs_suspend_cancel();
0e91398f 165
b3e96c0c 166 dpm_resume_end(si.cancelled ? PMSG_THAW : PMSG_RESTORE);
0e91398f 167
359cdd3f
JF
168 /* Make sure timer events get retriggered on all CPUs */
169 clock_was_set();
65f63384
IC
170
171out_thaw:
0e91398f
JF
172#ifdef CONFIG_PREEMPT
173 thaw_processes();
65f63384 174out:
3fc1f1e2 175#endif
0e91398f
JF
176 shutting_down = SHUTDOWN_INVALID;
177}
1f112cee 178#endif /* CONFIG_HIBERNATE_CALLBACKS */
3e2b8fbe 179
55271723
IC
180struct shutdown_handler {
181 const char *command;
182 void (*cb)(void);
183};
184
185static void do_poweroff(void)
186{
187 shutting_down = SHUTDOWN_POWEROFF;
188 orderly_poweroff(false);
189}
190
191static void do_reboot(void)
192{
193 shutting_down = SHUTDOWN_POWEROFF; /* ? */
194 ctrl_alt_del();
195}
196
3e2b8fbe
JF
197static void shutdown_handler(struct xenbus_watch *watch,
198 const char **vec, unsigned int len)
199{
200 char *str;
201 struct xenbus_transaction xbt;
202 int err;
55271723
IC
203 static struct shutdown_handler handlers[] = {
204 { "poweroff", do_poweroff },
205 { "halt", do_poweroff },
206 { "reboot", do_reboot },
1f112cee 207#ifdef CONFIG_HIBERNATE_CALLBACKS
55271723
IC
208 { "suspend", do_suspend },
209#endif
210 {NULL, NULL},
211 };
212 static struct shutdown_handler *handler;
3e2b8fbe
JF
213
214 if (shutting_down != SHUTDOWN_INVALID)
215 return;
216
217 again:
218 err = xenbus_transaction_start(&xbt);
219 if (err)
220 return;
221
222 str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
223 /* Ignore read errors and empty reads. */
224 if (XENBUS_IS_ERR_READ(str)) {
225 xenbus_transaction_end(xbt, 1);
226 return;
227 }
228
55271723
IC
229 for (handler = &handlers[0]; handler->command; handler++) {
230 if (strcmp(str, handler->command) == 0)
231 break;
232 }
233
234 /* Only acknowledge commands which we are prepared to handle. */
235 if (handler->cb)
236 xenbus_write(xbt, "control", "shutdown", "");
3e2b8fbe
JF
237
238 err = xenbus_transaction_end(xbt, 0);
239 if (err == -EAGAIN) {
240 kfree(str);
241 goto again;
242 }
243
55271723
IC
244 if (handler->cb) {
245 handler->cb();
0e91398f 246 } else {
3e2b8fbe
JF
247 printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
248 shutting_down = SHUTDOWN_INVALID;
249 }
250
251 kfree(str);
252}
253
f3bc3189 254#ifdef CONFIG_MAGIC_SYSRQ
3e2b8fbe
JF
255static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
256 unsigned int len)
257{
258 char sysrq_key = '\0';
259 struct xenbus_transaction xbt;
260 int err;
261
262 again:
263 err = xenbus_transaction_start(&xbt);
264 if (err)
265 return;
266 if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
267 printk(KERN_ERR "Unable to read sysrq code in "
268 "control/sysrq\n");
269 xenbus_transaction_end(xbt, 1);
270 return;
271 }
272
273 if (sysrq_key != '\0')
274 xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
275
276 err = xenbus_transaction_end(xbt, 0);
277 if (err == -EAGAIN)
278 goto again;
279
280 if (sysrq_key != '\0')
f335397d 281 handle_sysrq(sysrq_key);
3e2b8fbe
JF
282}
283
3e2b8fbe
JF
284static struct xenbus_watch sysrq_watch = {
285 .node = "control/sysrq",
286 .callback = sysrq_handler
287};
f3bc3189
RD
288#endif
289
290static struct xenbus_watch shutdown_watch = {
291 .node = "control/shutdown",
292 .callback = shutdown_handler
293};
3e2b8fbe
JF
294
295static int setup_shutdown_watcher(void)
296{
297 int err;
298
299 err = register_xenbus_watch(&shutdown_watch);
300 if (err) {
301 printk(KERN_ERR "Failed to set shutdown watcher\n");
302 return err;
303 }
304
f3bc3189 305#ifdef CONFIG_MAGIC_SYSRQ
3e2b8fbe
JF
306 err = register_xenbus_watch(&sysrq_watch);
307 if (err) {
308 printk(KERN_ERR "Failed to set sysrq watcher\n");
309 return err;
310 }
f3bc3189 311#endif
3e2b8fbe
JF
312
313 return 0;
314}
315
316static int shutdown_event(struct notifier_block *notifier,
317 unsigned long event,
318 void *data)
319{
320 setup_shutdown_watcher();
321 return NOTIFY_DONE;
322}
323
016b6f5f 324int xen_setup_shutdown_event(void)
3e2b8fbe
JF
325{
326 static struct notifier_block xenstore_notifier = {
327 .notifier_call = shutdown_event
328 };
702d4eb9
SS
329
330 if (!xen_domain())
331 return -ENODEV;
3e2b8fbe
JF
332 register_xenstore_notifier(&xenstore_notifier);
333
334 return 0;
335}
183d03cc 336EXPORT_SYMBOL_GPL(xen_setup_shutdown_event);
3e2b8fbe 337
702d4eb9 338subsys_initcall(xen_setup_shutdown_event);
This page took 0.491208 seconds and 5 git commands to generate.