struct suspend_info {
int cancelled;
- unsigned long arg; /* extra hypercall argument */
- void (*pre)(void);
- void (*post)(int cancelled);
};
static RAW_NOTIFIER_HEAD(xen_resume_notifier);
EXPORT_SYMBOL_GPL(xen_resume_notifier_unregister);
#ifdef CONFIG_HIBERNATE_CALLBACKS
-static void xen_hvm_post_suspend(int cancelled)
-{
- xen_arch_hvm_post_suspend(cancelled);
- gnttab_resume();
-}
-
-static void xen_pre_suspend(void)
-{
- xen_mm_pin_all();
- gnttab_suspend();
- xen_arch_pre_suspend();
-}
-
-static void xen_post_suspend(int cancelled)
-{
- xen_arch_post_suspend(cancelled);
- gnttab_resume();
- xen_mm_unpin_all();
-}
-
static int xen_suspend(void *data)
{
struct suspend_info *si = data;
return err;
}
- if (si->pre)
- si->pre();
+ gnttab_suspend();
+ xen_arch_pre_suspend();
/*
* This hypercall returns 1 if suspend was cancelled
* or the domain was merely checkpointed, and 0 if it
* is resuming in a new domain.
*/
- si->cancelled = HYPERVISOR_suspend(si->arg);
+ si->cancelled = HYPERVISOR_suspend(xen_pv_domain()
+ ? virt_to_mfn(xen_start_info)
+ : 0);
- if (si->post)
- si->post(si->cancelled);
+ xen_arch_post_suspend(si->cancelled);
+ gnttab_resume();
if (!si->cancelled) {
xen_irq_resume();
- xen_console_resume();
xen_timer_resume();
}
si.cancelled = 1;
- if (xen_hvm_domain()) {
- si.arg = 0UL;
- si.pre = NULL;
- si.post = &xen_hvm_post_suspend;
- } else {
- si.arg = virt_to_mfn(xen_start_info);
- si.pre = &xen_pre_suspend;
- si.post = &xen_post_suspend;
- }
-
err = stop_machine(xen_suspend, &si, cpumask_of(0));
+ /* Resume console as early as possible. */
+ if (!si.cancelled)
+ xen_console_resume();
+
raw_notifier_call_chain(&xen_resume_notifier, 0, NULL);
dpm_resume_start(si.cancelled ? PMSG_THAW : PMSG_RESTORE);
void (*cb)(void);
};
+static int poweroff_nb(struct notifier_block *cb, unsigned long code, void *unused)
+{
+ switch (code) {
+ case SYS_DOWN:
+ case SYS_HALT:
+ case SYS_POWER_OFF:
+ shutting_down = SHUTDOWN_POWEROFF;
+ default:
+ break;
+ }
+ return NOTIFY_DONE;
+}
static void do_poweroff(void)
{
- shutting_down = SHUTDOWN_POWEROFF;
- orderly_poweroff(false);
+ switch (system_state) {
+ case SYSTEM_BOOTING:
+ orderly_poweroff(true);
+ break;
+ case SYSTEM_RUNNING:
+ orderly_poweroff(false);
+ break;
+ default:
+ /* Don't do it when we are halting/rebooting. */
+ pr_info("Ignoring Xen toolstack shutdown.\n");
+ break;
+ }
}
static void do_reboot(void)
.callback = shutdown_handler
};
+static struct notifier_block xen_reboot_nb = {
+ .notifier_call = poweroff_nb,
+};
+
static int setup_shutdown_watcher(void)
{
int err;
return err;
}
+
#ifdef CONFIG_MAGIC_SYSRQ
err = register_xenbus_watch(&sysrq_watch);
if (err) {
if (!xen_domain())
return -ENODEV;
register_xenstore_notifier(&xenstore_notifier);
+ register_reboot_notifier(&xen_reboot_nb);
return 0;
}