xref: /openbmc/linux/drivers/xen/manage.c (revision 8fa5723aa7e053d498336b48448b292fc2e0458b)
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 = device_power_down(PMSG_SUSPEND);
43 	if (err) {
44 		printk(KERN_ERR "xen_suspend: device_power_down 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 	device_power_up(PMSG_RESUME);
65 
66 	if (!*cancelled) {
67 		xen_irq_resume();
68 		xen_console_resume();
69 		xen_timer_resume();
70 	}
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 #ifdef CONFIG_PREEMPT
83 	/* If the kernel is preemptible, we need to freeze all the processes
84 	   to prevent them from being in the middle of a pagetable update
85 	   during suspend. */
86 	err = freeze_processes();
87 	if (err) {
88 		printk(KERN_ERR "xen suspend: freeze failed %d\n", err);
89 		return;
90 	}
91 #endif
92 
93 	err = device_suspend(PMSG_SUSPEND);
94 	if (err) {
95 		printk(KERN_ERR "xen suspend: device_suspend %d\n", err);
96 		goto out;
97 	}
98 
99 	printk("suspending xenbus...\n");
100 	/* XXX use normal device tree? */
101 	xenbus_suspend();
102 
103 	err = stop_machine(xen_suspend, &cancelled, &cpumask_of_cpu(0));
104 	if (err) {
105 		printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
106 		goto out;
107 	}
108 
109 	if (!cancelled) {
110 		xen_arch_resume();
111 		xenbus_resume();
112 	} else
113 		xenbus_suspend_cancel();
114 
115 	device_resume(PMSG_RESUME);
116 
117 	/* Make sure timer events get retriggered on all CPUs */
118 	clock_was_set();
119 out:
120 #ifdef CONFIG_PREEMPT
121 	thaw_processes();
122 #endif
123 	shutting_down = SHUTDOWN_INVALID;
124 }
125 #endif	/* CONFIG_PM_SLEEP */
126 
127 static void shutdown_handler(struct xenbus_watch *watch,
128 			     const char **vec, unsigned int len)
129 {
130 	char *str;
131 	struct xenbus_transaction xbt;
132 	int err;
133 
134 	if (shutting_down != SHUTDOWN_INVALID)
135 		return;
136 
137  again:
138 	err = xenbus_transaction_start(&xbt);
139 	if (err)
140 		return;
141 
142 	str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
143 	/* Ignore read errors and empty reads. */
144 	if (XENBUS_IS_ERR_READ(str)) {
145 		xenbus_transaction_end(xbt, 1);
146 		return;
147 	}
148 
149 	xenbus_write(xbt, "control", "shutdown", "");
150 
151 	err = xenbus_transaction_end(xbt, 0);
152 	if (err == -EAGAIN) {
153 		kfree(str);
154 		goto again;
155 	}
156 
157 	if (strcmp(str, "poweroff") == 0 ||
158 	    strcmp(str, "halt") == 0) {
159 		shutting_down = SHUTDOWN_POWEROFF;
160 		orderly_poweroff(false);
161 	} else if (strcmp(str, "reboot") == 0) {
162 		shutting_down = SHUTDOWN_POWEROFF; /* ? */
163 		ctrl_alt_del();
164 #ifdef CONFIG_PM_SLEEP
165 	} else if (strcmp(str, "suspend") == 0) {
166 		do_suspend();
167 #endif
168 	} else {
169 		printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
170 		shutting_down = SHUTDOWN_INVALID;
171 	}
172 
173 	kfree(str);
174 }
175 
176 static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
177 			  unsigned int len)
178 {
179 	char sysrq_key = '\0';
180 	struct xenbus_transaction xbt;
181 	int err;
182 
183  again:
184 	err = xenbus_transaction_start(&xbt);
185 	if (err)
186 		return;
187 	if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
188 		printk(KERN_ERR "Unable to read sysrq code in "
189 		       "control/sysrq\n");
190 		xenbus_transaction_end(xbt, 1);
191 		return;
192 	}
193 
194 	if (sysrq_key != '\0')
195 		xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
196 
197 	err = xenbus_transaction_end(xbt, 0);
198 	if (err == -EAGAIN)
199 		goto again;
200 
201 	if (sysrq_key != '\0')
202 		handle_sysrq(sysrq_key, NULL);
203 }
204 
205 static struct xenbus_watch shutdown_watch = {
206 	.node = "control/shutdown",
207 	.callback = shutdown_handler
208 };
209 
210 static struct xenbus_watch sysrq_watch = {
211 	.node = "control/sysrq",
212 	.callback = sysrq_handler
213 };
214 
215 static int setup_shutdown_watcher(void)
216 {
217 	int err;
218 
219 	err = register_xenbus_watch(&shutdown_watch);
220 	if (err) {
221 		printk(KERN_ERR "Failed to set shutdown watcher\n");
222 		return err;
223 	}
224 
225 	err = register_xenbus_watch(&sysrq_watch);
226 	if (err) {
227 		printk(KERN_ERR "Failed to set sysrq watcher\n");
228 		return err;
229 	}
230 
231 	return 0;
232 }
233 
234 static int shutdown_event(struct notifier_block *notifier,
235 			  unsigned long event,
236 			  void *data)
237 {
238 	setup_shutdown_watcher();
239 	return NOTIFY_DONE;
240 }
241 
242 static int __init setup_shutdown_event(void)
243 {
244 	static struct notifier_block xenstore_notifier = {
245 		.notifier_call = shutdown_event
246 	};
247 	register_xenstore_notifier(&xenstore_notifier);
248 
249 	return 0;
250 }
251 
252 subsys_initcall(setup_shutdown_event);
253