diff options
Diffstat (limited to 'kernel/power/disk.c')
| -rw-r--r-- | kernel/power/disk.c | 195 | 
1 files changed, 108 insertions, 87 deletions
diff --git a/kernel/power/disk.c b/kernel/power/disk.c index 06331374d86..b5f0543ed84 100644 --- a/kernel/power/disk.c +++ b/kernel/power/disk.c @@ -30,30 +30,69 @@ char resume_file[256] = CONFIG_PM_STD_PARTITION;  dev_t swsusp_resume_device;  sector_t swsusp_resume_block; +enum { +	HIBERNATION_INVALID, +	HIBERNATION_PLATFORM, +	HIBERNATION_TEST, +	HIBERNATION_TESTPROC, +	HIBERNATION_SHUTDOWN, +	HIBERNATION_REBOOT, +	/* keep last */ +	__HIBERNATION_AFTER_LAST +}; +#define HIBERNATION_MAX (__HIBERNATION_AFTER_LAST-1) +#define HIBERNATION_FIRST (HIBERNATION_INVALID + 1) + +static int hibernation_mode = HIBERNATION_SHUTDOWN; + +struct hibernation_ops *hibernation_ops; + +/** + * hibernation_set_ops - set the global hibernate operations + * @ops: the hibernation operations to use in subsequent hibernation transitions + */ + +void hibernation_set_ops(struct hibernation_ops *ops) +{ +	if (ops && !(ops->prepare && ops->enter && ops->finish)) { +		WARN_ON(1); +		return; +	} +	mutex_lock(&pm_mutex); +	hibernation_ops = ops; +	if (ops) +		hibernation_mode = HIBERNATION_PLATFORM; +	else if (hibernation_mode == HIBERNATION_PLATFORM) +		hibernation_mode = HIBERNATION_SHUTDOWN; + +	mutex_unlock(&pm_mutex); +} + +  /**   *	platform_prepare - prepare the machine for hibernation using the   *	platform driver if so configured and return an error code if it fails   */ -static inline int platform_prepare(void) +static int platform_prepare(void)  { -	int error = 0; +	return (hibernation_mode == HIBERNATION_PLATFORM && hibernation_ops) ? +		hibernation_ops->prepare() : 0; +} -	switch (pm_disk_mode) { -	case PM_DISK_TEST: -	case PM_DISK_TESTPROC: -	case PM_DISK_SHUTDOWN: -	case PM_DISK_REBOOT: -		break; -	default: -		if (pm_ops && pm_ops->prepare) -			error = pm_ops->prepare(PM_SUSPEND_DISK); -	} -	return error; +/** + *	platform_finish - switch the machine to the normal mode of operation + *	using the platform driver (must be called after platform_prepare()) + */ + +static void platform_finish(void) +{ +	if (hibernation_mode == HIBERNATION_PLATFORM && hibernation_ops) +		hibernation_ops->finish();  }  /** - *	power_down - Shut machine down for hibernate. + *	power_down - Shut the machine down for hibernation.   *   *	Use the platform driver, if configured so; otherwise try   *	to power off or reboot. @@ -61,20 +100,20 @@ static inline int platform_prepare(void)  static void power_down(void)  { -	switch (pm_disk_mode) { -	case PM_DISK_TEST: -	case PM_DISK_TESTPROC: +	switch (hibernation_mode) { +	case HIBERNATION_TEST: +	case HIBERNATION_TESTPROC:  		break; -	case PM_DISK_SHUTDOWN: +	case HIBERNATION_SHUTDOWN:  		kernel_power_off();  		break; -	case PM_DISK_REBOOT: +	case HIBERNATION_REBOOT:  		kernel_restart(NULL);  		break; -	default: -		if (pm_ops && pm_ops->enter) { +	case HIBERNATION_PLATFORM: +		if (hibernation_ops) {  			kernel_shutdown_prepare(SYSTEM_SUSPEND_DISK); -			pm_ops->enter(PM_SUSPEND_DISK); +			hibernation_ops->enter();  			break;  		}  	} @@ -87,20 +126,6 @@ static void power_down(void)  	while(1);  } -static inline void platform_finish(void) -{ -	switch (pm_disk_mode) { -	case PM_DISK_TEST: -	case PM_DISK_TESTPROC: -	case PM_DISK_SHUTDOWN: -	case PM_DISK_REBOOT: -		break; -	default: -		if (pm_ops && pm_ops->finish) -			pm_ops->finish(PM_SUSPEND_DISK); -	} -} -  static void unprepare_processes(void)  {  	thaw_processes(); @@ -120,13 +145,10 @@ static int prepare_processes(void)  }  /** - *	pm_suspend_disk - The granpappy of hibernation power management. - * - *	If not, then call swsusp to do its thing, then figure out how - *	to power down the system. + *	hibernate - The granpappy of the built-in hibernation management   */ -int pm_suspend_disk(void) +int hibernate(void)  {  	int error; @@ -143,7 +165,8 @@ int pm_suspend_disk(void)  	if (error)  		goto Finish; -	if (pm_disk_mode == PM_DISK_TESTPROC) { +	mutex_lock(&pm_mutex); +	if (hibernation_mode == HIBERNATION_TESTPROC) {  		printk("swsusp debug: Waiting for 5 seconds.\n");  		mdelay(5000);  		goto Thaw; @@ -168,7 +191,7 @@ int pm_suspend_disk(void)  	if (error)  		goto Enable_cpus; -	if (pm_disk_mode == PM_DISK_TEST) { +	if (hibernation_mode == HIBERNATION_TEST) {  		printk("swsusp debug: Waiting for 5 seconds.\n");  		mdelay(5000);  		goto Enable_cpus; @@ -205,6 +228,7 @@ int pm_suspend_disk(void)  	device_resume();  	resume_console();   Thaw: +	mutex_unlock(&pm_mutex);  	unprepare_processes();   Finish:  	free_basic_memory_bitmaps(); @@ -220,7 +244,7 @@ int pm_suspend_disk(void)   *	Called as a late_initcall (so all devices are discovered and   *	initialized), we call swsusp to see if we have a saved image or not.   *	If so, we quiesce devices, the restore the saved image. We will - *	return above (in pm_suspend_disk() ) if everything goes well. + *	return above (in hibernate() ) if everything goes well.   *	Otherwise, we fail gracefully and return to the normally   *	scheduled program.   * @@ -315,25 +339,26 @@ static int software_resume(void)  late_initcall(software_resume); -static const char * const pm_disk_modes[] = { -	[PM_DISK_PLATFORM]	= "platform", -	[PM_DISK_SHUTDOWN]	= "shutdown", -	[PM_DISK_REBOOT]	= "reboot", -	[PM_DISK_TEST]		= "test", -	[PM_DISK_TESTPROC]	= "testproc", +static const char * const hibernation_modes[] = { +	[HIBERNATION_PLATFORM]	= "platform", +	[HIBERNATION_SHUTDOWN]	= "shutdown", +	[HIBERNATION_REBOOT]	= "reboot", +	[HIBERNATION_TEST]	= "test", +	[HIBERNATION_TESTPROC]	= "testproc",  };  /** - *	disk - Control suspend-to-disk mode + *	disk - Control hibernation mode   *   *	Suspend-to-disk can be handled in several ways. We have a few options   *	for putting the system to sleep - using the platform driver (e.g. ACPI - *	or other pm_ops), powering off the system or rebooting the system - *	(for testing) as well as the two test modes. + *	or other hibernation_ops), powering off the system or rebooting the + *	system (for testing) as well as the two test modes.   *   *	The system can support 'platform', and that is known a priori (and - *	encoded in pm_ops). However, the user may choose 'shutdown' or 'reboot' - *	as alternatives, as well as the test modes 'test' and 'testproc'. + *	encoded by the presence of hibernation_ops). However, the user may + *	choose 'shutdown' or 'reboot' as alternatives, as well as one fo the + *	test modes, 'test' or 'testproc'.   *   *	show() will display what the mode is currently set to.   *	store() will accept one of @@ -345,7 +370,7 @@ static const char * const pm_disk_modes[] = {   *	'testproc'   *   *	It will only change to 'platform' if the system - *	supports it (as determined from pm_ops->pm_disk_mode). + *	supports it (as determined by having hibernation_ops).   */  static ssize_t disk_show(struct kset *kset, char *buf) @@ -353,28 +378,25 @@ static ssize_t disk_show(struct kset *kset, char *buf)  	int i;  	char *start = buf; -	for (i = PM_DISK_PLATFORM; i < PM_DISK_MAX; i++) { -		if (!pm_disk_modes[i]) +	for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) { +		if (!hibernation_modes[i])  			continue;  		switch (i) { -		case PM_DISK_SHUTDOWN: -		case PM_DISK_REBOOT: -		case PM_DISK_TEST: -		case PM_DISK_TESTPROC: +		case HIBERNATION_SHUTDOWN: +		case HIBERNATION_REBOOT: +		case HIBERNATION_TEST: +		case HIBERNATION_TESTPROC:  			break; -		default: -			if (pm_ops && pm_ops->enter && -			    (i == pm_ops->pm_disk_mode)) +		case HIBERNATION_PLATFORM: +			if (hibernation_ops)  				break;  			/* not a valid mode, continue with loop */  			continue;  		} -		if (i == pm_disk_mode) -			buf += sprintf(buf, "[%s]", pm_disk_modes[i]); +		if (i == hibernation_mode) +			buf += sprintf(buf, "[%s] ", hibernation_modes[i]);  		else -			buf += sprintf(buf, "%s", pm_disk_modes[i]); -		if (i+1 != PM_DISK_MAX) -			buf += sprintf(buf, " "); +			buf += sprintf(buf, "%s ", hibernation_modes[i]);  	}  	buf += sprintf(buf, "\n");  	return buf-start; @@ -387,39 +409,38 @@ static ssize_t disk_store(struct kset *kset, const char *buf, size_t n)  	int i;  	int len;  	char *p; -	suspend_disk_method_t mode = 0; +	int mode = HIBERNATION_INVALID;  	p = memchr(buf, '\n', n);  	len = p ? p - buf : n;  	mutex_lock(&pm_mutex); -	for (i = PM_DISK_PLATFORM; i < PM_DISK_MAX; i++) { -		if (!strncmp(buf, pm_disk_modes[i], len)) { +	for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) { +		if (!strncmp(buf, hibernation_modes[i], len)) {  			mode = i;  			break;  		}  	} -	if (mode) { +	if (mode != HIBERNATION_INVALID) {  		switch (mode) { -		case PM_DISK_SHUTDOWN: -		case PM_DISK_REBOOT: -		case PM_DISK_TEST: -		case PM_DISK_TESTPROC: -			pm_disk_mode = mode; +		case HIBERNATION_SHUTDOWN: +		case HIBERNATION_REBOOT: +		case HIBERNATION_TEST: +		case HIBERNATION_TESTPROC: +			hibernation_mode = mode;  			break; -		default: -			if (pm_ops && pm_ops->enter && -			    (mode == pm_ops->pm_disk_mode)) -				pm_disk_mode = mode; +		case HIBERNATION_PLATFORM: +			if (hibernation_ops) +				hibernation_mode = mode;  			else  				error = -EINVAL;  		} -	} else { +	} else  		error = -EINVAL; -	} -	pr_debug("PM: suspend-to-disk mode set to '%s'\n", -		 pm_disk_modes[mode]); +	if (!error) +		pr_debug("PM: suspend-to-disk mode set to '%s'\n", +			 hibernation_modes[mode]);  	mutex_unlock(&pm_mutex);  	return error ? error : n;  }  | 
