diff options
Diffstat (limited to 'kernel/power')
| -rw-r--r-- | kernel/power/Kconfig | 4 | ||||
| -rw-r--r-- | kernel/power/hibernate.c | 42 | ||||
| -rw-r--r-- | kernel/power/main.c | 45 | ||||
| -rw-r--r-- | kernel/power/power.h | 3 | ||||
| -rw-r--r-- | kernel/power/suspend.c | 3 | ||||
| -rw-r--r-- | kernel/power/swap.c | 82 | ||||
| -rw-r--r-- | kernel/power/wakelock.c | 7 | 
7 files changed, 157 insertions, 29 deletions
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index 8f9b4eb974e..a70518c9d82 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig @@ -175,7 +175,7 @@ config PM_TEST_SUSPEND  	You probably want to have your system's RTC driver statically  	linked, ensuring that it's available when this test runs. -config CAN_PM_TRACE +config PM_SLEEP_DEBUG  	def_bool y  	depends on PM_DEBUG && PM_SLEEP @@ -196,7 +196,7 @@ config PM_TRACE  config PM_TRACE_RTC  	bool "Suspend/resume event tracing" -	depends on CAN_PM_TRACE +	depends on PM_SLEEP_DEBUG  	depends on X86  	select PM_TRACE  	---help--- diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index 238025f5472..b26f5f1e773 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -5,6 +5,7 @@   * Copyright (c) 2003 Open Source Development Lab   * Copyright (c) 2004 Pavel Machek <pavel@ucw.cz>   * Copyright (c) 2009 Rafael J. Wysocki, Novell Inc. + * Copyright (C) 2012 Bojan Smojver <bojan@rexursive.com>   *   * This file is released under the GPLv2.   */ @@ -45,6 +46,9 @@ enum {  	HIBERNATION_PLATFORM,  	HIBERNATION_SHUTDOWN,  	HIBERNATION_REBOOT, +#ifdef CONFIG_SUSPEND +	HIBERNATION_SUSPEND, +#endif  	/* keep last */  	__HIBERNATION_AFTER_LAST  }; @@ -353,6 +357,7 @@ int hibernation_snapshot(int platform_mode)  	}  	suspend_console(); +	ftrace_stop();  	pm_restrict_gfp_mask();  	error = dpm_suspend(PMSG_FREEZE); @@ -378,6 +383,7 @@ int hibernation_snapshot(int platform_mode)  	if (error || !in_suspend)  		pm_restore_gfp_mask(); +	ftrace_start();  	resume_console();  	dpm_complete(msg); @@ -480,6 +486,7 @@ int hibernation_restore(int platform_mode)  	pm_prepare_console();  	suspend_console(); +	ftrace_stop();  	pm_restrict_gfp_mask();  	error = dpm_suspend_start(PMSG_QUIESCE);  	if (!error) { @@ -487,6 +494,7 @@ int hibernation_restore(int platform_mode)  		dpm_resume_end(PMSG_RECOVER);  	}  	pm_restore_gfp_mask(); +	ftrace_start();  	resume_console();  	pm_restore_console();  	return error; @@ -513,6 +521,7 @@ int hibernation_platform_enter(void)  	entering_platform_hibernation = true;  	suspend_console(); +	ftrace_stop();  	error = dpm_suspend_start(PMSG_HIBERNATE);  	if (error) {  		if (hibernation_ops->recover) @@ -556,6 +565,7 @@ int hibernation_platform_enter(void)   Resume_devices:  	entering_platform_hibernation = false;  	dpm_resume_end(PMSG_RESTORE); +	ftrace_start();  	resume_console();   Close: @@ -573,6 +583,10 @@ int hibernation_platform_enter(void)   */  static void power_down(void)  { +#ifdef CONFIG_SUSPEND +	int error; +#endif +  	switch (hibernation_mode) {  	case HIBERNATION_REBOOT:  		kernel_restart(NULL); @@ -582,6 +596,25 @@ static void power_down(void)  	case HIBERNATION_SHUTDOWN:  		kernel_power_off();  		break; +#ifdef CONFIG_SUSPEND +	case HIBERNATION_SUSPEND: +		error = suspend_devices_and_enter(PM_SUSPEND_MEM); +		if (error) { +			if (hibernation_ops) +				hibernation_mode = HIBERNATION_PLATFORM; +			else +				hibernation_mode = HIBERNATION_SHUTDOWN; +			power_down(); +		} +		/* +		 * Restore swap signature. +		 */ +		error = swsusp_unmark(); +		if (error) +			printk(KERN_ERR "PM: Swap will be unusable! " +			                "Try swapon -a.\n"); +		return; +#endif  	}  	kernel_halt();  	/* @@ -819,6 +852,9 @@ static const char * const hibernation_modes[] = {  	[HIBERNATION_PLATFORM]	= "platform",  	[HIBERNATION_SHUTDOWN]	= "shutdown",  	[HIBERNATION_REBOOT]	= "reboot", +#ifdef CONFIG_SUSPEND +	[HIBERNATION_SUSPEND]	= "suspend", +#endif  };  /* @@ -859,6 +895,9 @@ static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr,  		switch (i) {  		case HIBERNATION_SHUTDOWN:  		case HIBERNATION_REBOOT: +#ifdef CONFIG_SUSPEND +		case HIBERNATION_SUSPEND: +#endif  			break;  		case HIBERNATION_PLATFORM:  			if (hibernation_ops) @@ -899,6 +938,9 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr,  		switch (mode) {  		case HIBERNATION_SHUTDOWN:  		case HIBERNATION_REBOOT: +#ifdef CONFIG_SUSPEND +		case HIBERNATION_SUSPEND: +#endif  			hibernation_mode = mode;  			break;  		case HIBERNATION_PLATFORM: diff --git a/kernel/power/main.c b/kernel/power/main.c index 428f8a034e9..f458238109c 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -235,6 +235,47 @@ late_initcall(pm_debugfs_init);  #endif /* CONFIG_PM_SLEEP */ +#ifdef CONFIG_PM_SLEEP_DEBUG +/* + * pm_print_times: print time taken by devices to suspend and resume. + * + * show() returns whether printing of suspend and resume times is enabled. + * store() accepts 0 or 1.  0 disables printing and 1 enables it. + */ +bool pm_print_times_enabled; + +static ssize_t pm_print_times_show(struct kobject *kobj, +				   struct kobj_attribute *attr, char *buf) +{ +	return sprintf(buf, "%d\n", pm_print_times_enabled); +} + +static ssize_t pm_print_times_store(struct kobject *kobj, +				    struct kobj_attribute *attr, +				    const char *buf, size_t n) +{ +	unsigned long val; + +	if (kstrtoul(buf, 10, &val)) +		return -EINVAL; + +	if (val > 1) +		return -EINVAL; + +	pm_print_times_enabled = !!val; +	return n; +} + +power_attr(pm_print_times); + +static inline void pm_print_times_init(void) +{ +	pm_print_times_enabled = !!initcall_debug; +} +#else /* !CONFIG_PP_SLEEP_DEBUG */ +static inline void pm_print_times_init(void) {} +#endif /* CONFIG_PM_SLEEP_DEBUG */ +  struct kobject *power_kobj;  /** @@ -531,6 +572,9 @@ static struct attribute * g[] = {  #ifdef CONFIG_PM_DEBUG  	&pm_test_attr.attr,  #endif +#ifdef CONFIG_PM_SLEEP_DEBUG +	&pm_print_times_attr.attr, +#endif  #endif  	NULL,  }; @@ -566,6 +610,7 @@ static int __init pm_init(void)  	error = sysfs_create_group(power_kobj, &attr_group);  	if (error)  		return error; +	pm_print_times_init();  	return pm_autosleep_init();  } diff --git a/kernel/power/power.h b/kernel/power/power.h index b0bd4beaebf..7d4b7ffb3c1 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h @@ -156,6 +156,9 @@ extern void swsusp_free(void);  extern int swsusp_read(unsigned int *flags_p);  extern int swsusp_write(unsigned int flags);  extern void swsusp_close(fmode_t); +#ifdef CONFIG_SUSPEND +extern int swsusp_unmark(void); +#endif  /* kernel/power/block_io.c */  extern struct block_device *hib_resume_bdev; diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 396d262b8fd..c8b7446b27d 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -24,6 +24,7 @@  #include <linux/export.h>  #include <linux/suspend.h>  #include <linux/syscore_ops.h> +#include <linux/ftrace.h>  #include <trace/events/power.h>  #include "power.h" @@ -212,6 +213,7 @@ int suspend_devices_and_enter(suspend_state_t state)  			goto Close;  	}  	suspend_console(); +	ftrace_stop();  	suspend_test_start();  	error = dpm_suspend_start(PMSG_SUSPEND);  	if (error) { @@ -231,6 +233,7 @@ int suspend_devices_and_enter(suspend_state_t state)  	suspend_test_start();  	dpm_resume_end(PMSG_RESUME);  	suspend_test_finish("resume devices"); +	ftrace_start();  	resume_console();   Close:  	if (suspend_ops->end) diff --git a/kernel/power/swap.c b/kernel/power/swap.c index 11e22c068e8..3c9d764eb0d 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c @@ -448,9 +448,9 @@ static int save_image(struct swap_map_handle *handle,  	struct timeval start;  	struct timeval stop; -	printk(KERN_INFO "PM: Saving image data pages (%u pages) ...     ", +	printk(KERN_INFO "PM: Saving image data pages (%u pages)...\n",  		nr_to_write); -	m = nr_to_write / 100; +	m = nr_to_write / 10;  	if (!m)  		m = 1;  	nr_pages = 0; @@ -464,7 +464,8 @@ static int save_image(struct swap_map_handle *handle,  		if (ret)  			break;  		if (!(nr_pages % m)) -			printk(KERN_CONT "\b\b\b\b%3d%%", nr_pages / m); +			printk(KERN_INFO "PM: Image saving progress: %3d%%\n", +			       nr_pages / m * 10);  		nr_pages++;  	}  	err2 = hib_wait_on_bio_chain(&bio); @@ -472,9 +473,7 @@ static int save_image(struct swap_map_handle *handle,  	if (!ret)  		ret = err2;  	if (!ret) -		printk(KERN_CONT "\b\b\b\bdone\n"); -	else -		printk(KERN_CONT "\n"); +		printk(KERN_INFO "PM: Image saving done.\n");  	swsusp_show_speed(&start, &stop, nr_to_write, "Wrote");  	return ret;  } @@ -668,9 +667,9 @@ static int save_image_lzo(struct swap_map_handle *handle,  	printk(KERN_INFO  		"PM: Using %u thread(s) for compression.\n" -		"PM: Compressing and saving image data (%u pages) ...     ", +		"PM: Compressing and saving image data (%u pages)...\n",  		nr_threads, nr_to_write); -	m = nr_to_write / 100; +	m = nr_to_write / 10;  	if (!m)  		m = 1;  	nr_pages = 0; @@ -690,8 +689,10 @@ static int save_image_lzo(struct swap_map_handle *handle,  				       data_of(*snapshot), PAGE_SIZE);  				if (!(nr_pages % m)) -					printk(KERN_CONT "\b\b\b\b%3d%%", -				               nr_pages / m); +					printk(KERN_INFO +					       "PM: Image saving progress: " +					       "%3d%%\n", +				               nr_pages / m * 10);  				nr_pages++;  			}  			if (!off) @@ -761,11 +762,8 @@ out_finish:  	do_gettimeofday(&stop);  	if (!ret)  		ret = err2; -	if (!ret) { -		printk(KERN_CONT "\b\b\b\bdone\n"); -	} else { -		printk(KERN_CONT "\n"); -	} +	if (!ret) +		printk(KERN_INFO "PM: Image saving done.\n");  	swsusp_show_speed(&start, &stop, nr_to_write, "Wrote");  out_clean:  	if (crc) { @@ -973,9 +971,9 @@ static int load_image(struct swap_map_handle *handle,  	int err2;  	unsigned nr_pages; -	printk(KERN_INFO "PM: Loading image data pages (%u pages) ...     ", +	printk(KERN_INFO "PM: Loading image data pages (%u pages)...\n",  		nr_to_read); -	m = nr_to_read / 100; +	m = nr_to_read / 10;  	if (!m)  		m = 1;  	nr_pages = 0; @@ -993,7 +991,8 @@ static int load_image(struct swap_map_handle *handle,  		if (ret)  			break;  		if (!(nr_pages % m)) -			printk("\b\b\b\b%3d%%", nr_pages / m); +			printk(KERN_INFO "PM: Image loading progress: %3d%%\n", +			       nr_pages / m * 10);  		nr_pages++;  	}  	err2 = hib_wait_on_bio_chain(&bio); @@ -1001,12 +1000,11 @@ static int load_image(struct swap_map_handle *handle,  	if (!ret)  		ret = err2;  	if (!ret) { -		printk("\b\b\b\bdone\n"); +		printk(KERN_INFO "PM: Image loading done.\n");  		snapshot_write_finalize(snapshot);  		if (!snapshot_image_loaded(snapshot))  			ret = -ENODATA; -	} else -		printk("\n"); +	}  	swsusp_show_speed(&start, &stop, nr_to_read, "Read");  	return ret;  } @@ -1185,9 +1183,9 @@ static int load_image_lzo(struct swap_map_handle *handle,  	printk(KERN_INFO  		"PM: Using %u thread(s) for decompression.\n" -		"PM: Loading and decompressing image data (%u pages) ...     ", +		"PM: Loading and decompressing image data (%u pages)...\n",  		nr_threads, nr_to_read); -	m = nr_to_read / 100; +	m = nr_to_read / 10;  	if (!m)  		m = 1;  	nr_pages = 0; @@ -1319,7 +1317,10 @@ static int load_image_lzo(struct swap_map_handle *handle,  				       data[thr].unc + off, PAGE_SIZE);  				if (!(nr_pages % m)) -					printk("\b\b\b\b%3d%%", nr_pages / m); +					printk(KERN_INFO +					       "PM: Image loading progress: " +					       "%3d%%\n", +					       nr_pages / m * 10);  				nr_pages++;  				ret = snapshot_write_next(snapshot); @@ -1344,7 +1345,7 @@ out_finish:  	}  	do_gettimeofday(&stop);  	if (!ret) { -		printk("\b\b\b\bdone\n"); +		printk(KERN_INFO "PM: Image loading done.\n");  		snapshot_write_finalize(snapshot);  		if (!snapshot_image_loaded(snapshot))  			ret = -ENODATA; @@ -1357,8 +1358,7 @@ out_finish:  				}  			}  		} -	} else -		printk("\n"); +	}  	swsusp_show_speed(&start, &stop, nr_to_read, "Read");  out_clean:  	for (i = 0; i < ring_size; i++) @@ -1472,6 +1472,34 @@ void swsusp_close(fmode_t mode)  	blkdev_put(hib_resume_bdev, mode);  } +/** + *      swsusp_unmark - Unmark swsusp signature in the resume device + */ + +#ifdef CONFIG_SUSPEND +int swsusp_unmark(void) +{ +	int error; + +	hib_bio_read_page(swsusp_resume_block, swsusp_header, NULL); +	if (!memcmp(HIBERNATE_SIG,swsusp_header->sig, 10)) { +		memcpy(swsusp_header->sig,swsusp_header->orig_sig, 10); +		error = hib_bio_write_page(swsusp_resume_block, +					swsusp_header, NULL); +	} else { +		printk(KERN_ERR "PM: Cannot find swsusp signature!\n"); +		error = -ENODEV; +	} + +	/* +	 * We just returned from suspend, we don't need the image any more. +	 */ +	free_all_swap_pages(root_swap); + +	return error; +} +#endif +  static int swsusp_header_init(void)  {  	swsusp_header = (struct swsusp_header*) __get_free_page(GFP_KERNEL); diff --git a/kernel/power/wakelock.c b/kernel/power/wakelock.c index c8fba338007..8f50de394d2 100644 --- a/kernel/power/wakelock.c +++ b/kernel/power/wakelock.c @@ -9,6 +9,7 @@   * manipulate wakelocks on Android.   */ +#include <linux/capability.h>  #include <linux/ctype.h>  #include <linux/device.h>  #include <linux/err.h> @@ -188,6 +189,9 @@ int pm_wake_lock(const char *buf)  	size_t len;  	int ret = 0; +	if (!capable(CAP_BLOCK_SUSPEND)) +		return -EPERM; +  	while (*str && !isspace(*str))  		str++; @@ -231,6 +235,9 @@ int pm_wake_unlock(const char *buf)  	size_t len;  	int ret = 0; +	if (!capable(CAP_BLOCK_SUSPEND)) +		return -EPERM; +  	len = strlen(buf);  	if (!len)  		return -EINVAL;  |