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