aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/xen/manage.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/xen/manage.c')
-rw-r--r--drivers/xen/manage.c155
1 files changed, 92 insertions, 63 deletions
diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c
index db8c4c4ac880..1ac94125bf93 100644
--- a/drivers/xen/manage.c
+++ b/drivers/xen/manage.c
@@ -34,58 +34,62 @@ enum shutdown_state {
34/* Ignore multiple shutdown requests. */ 34/* Ignore multiple shutdown requests. */
35static enum shutdown_state shutting_down = SHUTDOWN_INVALID; 35static enum shutdown_state shutting_down = SHUTDOWN_INVALID;
36 36
37#ifdef CONFIG_PM_SLEEP 37struct suspend_info {
38static int xen_hvm_suspend(void *data) 38 int cancelled;
39{ 39 unsigned long arg; /* extra hypercall argument */
40 struct sched_shutdown r = { .reason = SHUTDOWN_suspend }; 40 void (*pre)(void);
41 int *cancelled = data; 41 void (*post)(int cancelled);
42 42};
43 BUG_ON(!irqs_disabled());
44
45 *cancelled = HYPERVISOR_sched_op(SCHEDOP_shutdown, &r);
46 43
47 xen_hvm_post_suspend(*cancelled); 44static void xen_hvm_post_suspend(int cancelled)
45{
46 xen_arch_hvm_post_suspend(cancelled);
48 gnttab_resume(); 47 gnttab_resume();
48}
49 49
50 if (!*cancelled) { 50static void xen_pre_suspend(void)
51 xen_irq_resume(); 51{
52 xen_console_resume(); 52 xen_mm_pin_all();
53 xen_timer_resume(); 53 gnttab_suspend();
54 } 54 xen_arch_pre_suspend();
55}
55 56
56 return 0; 57static void xen_post_suspend(int cancelled)
58{
59 xen_arch_post_suspend(cancelled);
60 gnttab_resume();
61 xen_mm_unpin_all();
57} 62}
58 63
64#ifdef CONFIG_HIBERNATE_CALLBACKS
59static int xen_suspend(void *data) 65static int xen_suspend(void *data)
60{ 66{
67 struct suspend_info *si = data;
61 int err; 68 int err;
62 int *cancelled = data;
63 69
64 BUG_ON(!irqs_disabled()); 70 BUG_ON(!irqs_disabled());
65 71
66 err = sysdev_suspend(PMSG_SUSPEND); 72 err = sysdev_suspend(PMSG_FREEZE);
67 if (err) { 73 if (err) {
68 printk(KERN_ERR "xen_suspend: sysdev_suspend failed: %d\n", 74 printk(KERN_ERR "xen_suspend: sysdev_suspend failed: %d\n",
69 err); 75 err);
70 return err; 76 return err;
71 } 77 }
72 78
73 xen_mm_pin_all(); 79 if (si->pre)
74 gnttab_suspend(); 80 si->pre();
75 xen_pre_suspend();
76 81
77 /* 82 /*
78 * This hypercall returns 1 if suspend was cancelled 83 * This hypercall returns 1 if suspend was cancelled
79 * or the domain was merely checkpointed, and 0 if it 84 * or the domain was merely checkpointed, and 0 if it
80 * is resuming in a new domain. 85 * is resuming in a new domain.
81 */ 86 */
82 *cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info)); 87 si->cancelled = HYPERVISOR_suspend(si->arg);
83 88
84 xen_post_suspend(*cancelled); 89 if (si->post)
85 gnttab_resume(); 90 si->post(si->cancelled);
86 xen_mm_unpin_all();
87 91
88 if (!*cancelled) { 92 if (!si->cancelled) {
89 xen_irq_resume(); 93 xen_irq_resume();
90 xen_console_resume(); 94 xen_console_resume();
91 xen_timer_resume(); 95 xen_timer_resume();
@@ -99,7 +103,7 @@ static int xen_suspend(void *data)
99static void do_suspend(void) 103static void do_suspend(void)
100{ 104{
101 int err; 105 int err;
102 int cancelled = 1; 106 struct suspend_info si;
103 107
104 shutting_down = SHUTDOWN_SUSPEND; 108 shutting_down = SHUTDOWN_SUSPEND;
105 109
@@ -114,7 +118,7 @@ static void do_suspend(void)
114 } 118 }
115#endif 119#endif
116 120
117 err = dpm_suspend_start(PMSG_SUSPEND); 121 err = dpm_suspend_start(PMSG_FREEZE);
118 if (err) { 122 if (err) {
119 printk(KERN_ERR "xen suspend: dpm_suspend_start %d\n", err); 123 printk(KERN_ERR "xen suspend: dpm_suspend_start %d\n", err);
120 goto out_thaw; 124 goto out_thaw;
@@ -123,32 +127,41 @@ static void do_suspend(void)
123 printk(KERN_DEBUG "suspending xenstore...\n"); 127 printk(KERN_DEBUG "suspending xenstore...\n");
124 xs_suspend(); 128 xs_suspend();
125 129
126 err = dpm_suspend_noirq(PMSG_SUSPEND); 130 err = dpm_suspend_noirq(PMSG_FREEZE);
127 if (err) { 131 if (err) {
128 printk(KERN_ERR "dpm_suspend_noirq failed: %d\n", err); 132 printk(KERN_ERR "dpm_suspend_noirq failed: %d\n", err);
129 goto out_resume; 133 goto out_resume;
130 } 134 }
131 135
132 if (xen_hvm_domain()) 136 si.cancelled = 1;
133 err = stop_machine(xen_hvm_suspend, &cancelled, cpumask_of(0)); 137
134 else 138 if (xen_hvm_domain()) {
135 err = stop_machine(xen_suspend, &cancelled, cpumask_of(0)); 139 si.arg = 0UL;
140 si.pre = NULL;
141 si.post = &xen_hvm_post_suspend;
142 } else {
143 si.arg = virt_to_mfn(xen_start_info);
144 si.pre = &xen_pre_suspend;
145 si.post = &xen_post_suspend;
146 }
147
148 err = stop_machine(xen_suspend, &si, cpumask_of(0));
136 149
137 dpm_resume_noirq(PMSG_RESUME); 150 dpm_resume_noirq(si.cancelled ? PMSG_THAW : PMSG_RESTORE);
138 151
139 if (err) { 152 if (err) {
140 printk(KERN_ERR "failed to start xen_suspend: %d\n", err); 153 printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
141 cancelled = 1; 154 si.cancelled = 1;
142 } 155 }
143 156
144out_resume: 157out_resume:
145 if (!cancelled) { 158 if (!si.cancelled) {
146 xen_arch_resume(); 159 xen_arch_resume();
147 xs_resume(); 160 xs_resume();
148 } else 161 } else
149 xs_suspend_cancel(); 162 xs_suspend_cancel();
150 163
151 dpm_resume_end(PMSG_RESUME); 164 dpm_resume_end(si.cancelled ? PMSG_THAW : PMSG_RESTORE);
152 165
153 /* Make sure timer events get retriggered on all CPUs */ 166 /* Make sure timer events get retriggered on all CPUs */
154 clock_was_set(); 167 clock_was_set();
@@ -160,7 +173,24 @@ out:
160#endif 173#endif
161 shutting_down = SHUTDOWN_INVALID; 174 shutting_down = SHUTDOWN_INVALID;
162} 175}
163#endif /* CONFIG_PM_SLEEP */ 176#endif /* CONFIG_HIBERNATE_CALLBACKS */
177
178struct shutdown_handler {
179 const char *command;
180 void (*cb)(void);
181};
182
183static void do_poweroff(void)
184{
185 shutting_down = SHUTDOWN_POWEROFF;
186 orderly_poweroff(false);
187}
188
189static void do_reboot(void)
190{
191 shutting_down = SHUTDOWN_POWEROFF; /* ? */
192 ctrl_alt_del();
193}
164 194
165static void shutdown_handler(struct xenbus_watch *watch, 195static void shutdown_handler(struct xenbus_watch *watch,
166 const char **vec, unsigned int len) 196 const char **vec, unsigned int len)
@@ -168,6 +198,16 @@ static void shutdown_handler(struct xenbus_watch *watch,
168 char *str; 198 char *str;
169 struct xenbus_transaction xbt; 199 struct xenbus_transaction xbt;
170 int err; 200 int err;
201 static struct shutdown_handler handlers[] = {
202 { "poweroff", do_poweroff },
203 { "halt", do_poweroff },
204 { "reboot", do_reboot },
205#ifdef CONFIG_HIBERNATE_CALLBACKS
206 { "suspend", do_suspend },
207#endif
208 {NULL, NULL},
209 };
210 static struct shutdown_handler *handler;
171 211
172 if (shutting_down != SHUTDOWN_INVALID) 212 if (shutting_down != SHUTDOWN_INVALID)
173 return; 213 return;
@@ -184,7 +224,14 @@ static void shutdown_handler(struct xenbus_watch *watch,
184 return; 224 return;
185 } 225 }
186 226
187 xenbus_write(xbt, "control", "shutdown", ""); 227 for (handler = &handlers[0]; handler->command; handler++) {
228 if (strcmp(str, handler->command) == 0)
229 break;
230 }
231
232 /* Only acknowledge commands which we are prepared to handle. */
233 if (handler->cb)
234 xenbus_write(xbt, "control", "shutdown", "");
188 235
189 err = xenbus_transaction_end(xbt, 0); 236 err = xenbus_transaction_end(xbt, 0);
190 if (err == -EAGAIN) { 237 if (err == -EAGAIN) {
@@ -192,17 +239,8 @@ static void shutdown_handler(struct xenbus_watch *watch,
192 goto again; 239 goto again;
193 } 240 }
194 241
195 if (strcmp(str, "poweroff") == 0 || 242 if (handler->cb) {
196 strcmp(str, "halt") == 0) { 243 handler->cb();
197 shutting_down = SHUTDOWN_POWEROFF;
198 orderly_poweroff(false);
199 } else if (strcmp(str, "reboot") == 0) {
200 shutting_down = SHUTDOWN_POWEROFF; /* ? */
201 ctrl_alt_del();
202#ifdef CONFIG_PM_SLEEP
203 } else if (strcmp(str, "suspend") == 0) {
204 do_suspend();
205#endif
206 } else { 244 } else {
207 printk(KERN_INFO "Ignoring shutdown request: %s\n", str); 245 printk(KERN_INFO "Ignoring shutdown request: %s\n", str);
208 shutting_down = SHUTDOWN_INVALID; 246 shutting_down = SHUTDOWN_INVALID;
@@ -281,27 +319,18 @@ static int shutdown_event(struct notifier_block *notifier,
281 return NOTIFY_DONE; 319 return NOTIFY_DONE;
282} 320}
283 321
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) 322int xen_setup_shutdown_event(void)
297{ 323{
298 static struct notifier_block xenstore_notifier = { 324 static struct notifier_block xenstore_notifier = {
299 .notifier_call = shutdown_event 325 .notifier_call = shutdown_event
300 }; 326 };
327
328 if (!xen_domain())
329 return -ENODEV;
301 register_xenstore_notifier(&xenstore_notifier); 330 register_xenstore_notifier(&xenstore_notifier);
302 331
303 return 0; 332 return 0;
304} 333}
305EXPORT_SYMBOL_GPL(xen_setup_shutdown_event); 334EXPORT_SYMBOL_GPL(xen_setup_shutdown_event);
306 335
307subsys_initcall(__setup_shutdown_event); 336subsys_initcall(xen_setup_shutdown_event);