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