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