diff options
Diffstat (limited to 'drivers/xen/manage.c')
| -rw-r--r-- | drivers/xen/manage.c | 86 | 
1 files changed, 51 insertions, 35 deletions
diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c index 624e8dc2453..5f1e1f3cd18 100644 --- a/drivers/xen/manage.c +++ b/drivers/xen/manage.c @@ -41,32 +41,23 @@ static enum shutdown_state shutting_down = SHUTDOWN_INVALID;  struct suspend_info {  	int cancelled; -	unsigned long arg; /* extra hypercall argument */ -	void (*pre)(void); -	void (*post)(int cancelled);  }; -#ifdef CONFIG_HIBERNATE_CALLBACKS -static void xen_hvm_post_suspend(int cancelled) -{ -	xen_arch_hvm_post_suspend(cancelled); -	gnttab_resume(); -} +static RAW_NOTIFIER_HEAD(xen_resume_notifier); -static void xen_pre_suspend(void) +void xen_resume_notifier_register(struct notifier_block *nb)  { -	xen_mm_pin_all(); -	gnttab_suspend(); -	xen_arch_pre_suspend(); +	raw_notifier_chain_register(&xen_resume_notifier, nb);  } +EXPORT_SYMBOL_GPL(xen_resume_notifier_register); -static void xen_post_suspend(int cancelled) +void xen_resume_notifier_unregister(struct notifier_block *nb)  { -	xen_arch_post_suspend(cancelled); -	gnttab_resume(); -	xen_mm_unpin_all(); +	raw_notifier_chain_unregister(&xen_resume_notifier, nb);  } +EXPORT_SYMBOL_GPL(xen_resume_notifier_unregister); +#ifdef CONFIG_HIBERNATE_CALLBACKS  static int xen_suspend(void *data)  {  	struct suspend_info *si = data; @@ -80,22 +71,23 @@ static int xen_suspend(void *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();  	} @@ -140,18 +132,14 @@ static void do_suspend(void)  	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);  	if (err) { @@ -182,10 +170,32 @@ struct shutdown_handler {  	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) @@ -291,6 +301,10 @@ static struct xenbus_watch shutdown_watch = {  	.callback = shutdown_handler  }; +static struct notifier_block xen_reboot_nb = { +	.notifier_call = poweroff_nb, +}; +  static int setup_shutdown_watcher(void)  {  	int err; @@ -301,6 +315,7 @@ static int setup_shutdown_watcher(void)  		return err;  	} +  #ifdef CONFIG_MAGIC_SYSRQ  	err = register_xenbus_watch(&sysrq_watch);  	if (err) { @@ -329,6 +344,7 @@ int xen_setup_shutdown_event(void)  	if (!xen_domain())  		return -ENODEV;  	register_xenstore_notifier(&xenstore_notifier); +	register_reboot_notifier(&xen_reboot_nb);  	return 0;  }  | 
