Commit 0ede4700 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

Merge branch 'pm-sleep'

* pm-sleep:
  PM / hibernate: Iterate over set bits instead of PFNs in swsusp_free()
  PM / sleep: new suspend_resume trace event for console resume
  PM / sleep: Update test_suspend option documentation
  PM / sleep: Enhance test_suspend option with repeat capability
  PM / sleep: Support freeze as test_suspend option
  PM / sysfs: avoid shadowing variables
parents 88b42a48 fdd64ed5
Loading
Loading
Loading
Loading
+6 −4
Original line number Diff line number Diff line
@@ -3303,11 +3303,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.

	tdfx=		[HW,DRM]

	test_suspend=	[SUSPEND]
	test_suspend=	[SUSPEND][,N]
			Specify "mem" (for Suspend-to-RAM) or "standby" (for
			standby suspend) as the system sleep state to briefly
			enter during system startup.  The system is woken from
			this state using a wakeup-capable RTC alarm.
			standby suspend) or "freeze" (for suspend type freeze)
			as the system sleep state during system startup with
			the optional capability to repeat N number of times.
			The system is woken from this state using a
			wakeup-capable RTC alarm.

	thash_entries=	[KNL,NET]
			Set number of hash buckets for TCP connection
+13 −11
Original line number Diff line number Diff line
@@ -92,9 +92,6 @@
 *	wakeup_count - Report the number of wakeup events related to the device
 */

static const char enabled[] = "enabled";
static const char disabled[] = "disabled";

const char power_group_name[] = "power";
EXPORT_SYMBOL_GPL(power_group_name);

@@ -336,11 +333,14 @@ static DEVICE_ATTR(pm_qos_remote_wakeup, 0644,
#endif /* CONFIG_PM_RUNTIME */

#ifdef CONFIG_PM_SLEEP
static const char _enabled[] = "enabled";
static const char _disabled[] = "disabled";

static ssize_t
wake_show(struct device * dev, struct device_attribute *attr, char * buf)
{
	return sprintf(buf, "%s\n", device_can_wakeup(dev)
		? (device_may_wakeup(dev) ? enabled : disabled)
		? (device_may_wakeup(dev) ? _enabled : _disabled)
		: "");
}

@@ -357,11 +357,11 @@ wake_store(struct device * dev, struct device_attribute *attr,
	cp = memchr(buf, '\n', n);
	if (cp)
		len = cp - buf;
	if (len == sizeof enabled - 1
			&& strncmp(buf, enabled, sizeof enabled - 1) == 0)
	if (len == sizeof _enabled - 1
			&& strncmp(buf, _enabled, sizeof _enabled - 1) == 0)
		device_set_wakeup_enable(dev, 1);
	else if (len == sizeof disabled - 1
			&& strncmp(buf, disabled, sizeof disabled - 1) == 0)
	else if (len == sizeof _disabled - 1
			&& strncmp(buf, _disabled, sizeof _disabled - 1) == 0)
		device_set_wakeup_enable(dev, 0);
	else
		return -EINVAL;
@@ -570,7 +570,8 @@ static ssize_t async_show(struct device *dev, struct device_attribute *attr,
			  char *buf)
{
	return sprintf(buf, "%s\n",
			device_async_suspend_enabled(dev) ? enabled : disabled);
			device_async_suspend_enabled(dev) ?
				_enabled : _disabled);
}

static ssize_t async_store(struct device *dev, struct device_attribute *attr,
@@ -582,9 +583,10 @@ static ssize_t async_store(struct device *dev, struct device_attribute *attr,
	cp = memchr(buf, '\n', n);
	if (cp)
		len = cp - buf;
	if (len == sizeof enabled - 1 && strncmp(buf, enabled, len) == 0)
	if (len == sizeof _enabled - 1 && strncmp(buf, _enabled, len) == 0)
		device_enable_async_suspend(dev);
	else if (len == sizeof disabled - 1 && strncmp(buf, disabled, len) == 0)
	else if (len == sizeof _disabled - 1 &&
		 strncmp(buf, _disabled, len) == 0)
		device_disable_async_suspend(dev);
	else
		return -EINVAL;
+39 −15
Original line number Diff line number Diff line
@@ -725,6 +725,14 @@ static void memory_bm_clear_bit(struct memory_bitmap *bm, unsigned long pfn)
	clear_bit(bit, addr);
}

static void memory_bm_clear_current(struct memory_bitmap *bm)
{
	int bit;

	bit = max(bm->cur.node_bit - 1, 0);
	clear_bit(bit, bm->cur.node->data);
}

static int memory_bm_test_bit(struct memory_bitmap *bm, unsigned long pfn)
{
	void *addr;
@@ -1333,23 +1341,39 @@ static struct memory_bitmap copy_bm;

void swsusp_free(void)
{
	struct zone *zone;
	unsigned long pfn, max_zone_pfn;
	unsigned long fb_pfn, fr_pfn;

	for_each_populated_zone(zone) {
		max_zone_pfn = zone_end_pfn(zone);
		for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++)
			if (pfn_valid(pfn)) {
				struct page *page = pfn_to_page(pfn);
	if (!forbidden_pages_map || !free_pages_map)
		goto out;

				if (swsusp_page_is_forbidden(page) &&
				    swsusp_page_is_free(page)) {
					swsusp_unset_page_forbidden(page);
					swsusp_unset_page_free(page);
	memory_bm_position_reset(forbidden_pages_map);
	memory_bm_position_reset(free_pages_map);

loop:
	fr_pfn = memory_bm_next_pfn(free_pages_map);
	fb_pfn = memory_bm_next_pfn(forbidden_pages_map);

	/*
	 * Find the next bit set in both bitmaps. This is guaranteed to
	 * terminate when fb_pfn == fr_pfn == BM_END_OF_MAP.
	 */
	do {
		if (fb_pfn < fr_pfn)
			fb_pfn = memory_bm_next_pfn(forbidden_pages_map);
		if (fr_pfn < fb_pfn)
			fr_pfn = memory_bm_next_pfn(free_pages_map);
	} while (fb_pfn != fr_pfn);

	if (fr_pfn != BM_END_OF_MAP && pfn_valid(fr_pfn)) {
		struct page *page = pfn_to_page(fr_pfn);

		memory_bm_clear_current(forbidden_pages_map);
		memory_bm_clear_current(free_pages_map);
		__free_page(page);
		goto loop;
	}
			}
	}

out:
	nr_copy_pages = 0;
	nr_meta_pages = 0;
	restore_pblist = NULL;
+2 −0
Original line number Diff line number Diff line
@@ -361,7 +361,9 @@ int suspend_devices_and_enter(suspend_state_t state)
	suspend_test_start();
	dpm_resume_end(PMSG_RESUME);
	suspend_test_finish("resume devices");
	trace_suspend_resume(TPS("resume_console"), state, true);
	resume_console();
	trace_suspend_resume(TPS("resume_console"), state, false);

 Close:
	platform_suspend_end(state);
+29 −3
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@
#define TEST_SUSPEND_SECONDS	10

static unsigned long suspend_test_start_time;
static u32 test_repeat_count_max = 1;
static u32 test_repeat_count_current;

void suspend_test_start(void)
{
@@ -74,6 +76,7 @@ static void __init test_wakealarm(struct rtc_device *rtc, suspend_state_t state)
	int			status;

	/* this may fail if the RTC hasn't been initialized */
repeat:
	status = rtc_read_time(rtc, &alm.time);
	if (status < 0) {
		printk(err_readtime, dev_name(&rtc->dev), status);
@@ -100,10 +103,21 @@ static void __init test_wakealarm(struct rtc_device *rtc, suspend_state_t state)
	if (state == PM_SUSPEND_STANDBY) {
		printk(info_test, pm_states[state]);
		status = pm_suspend(state);
		if (status < 0)
			state = PM_SUSPEND_FREEZE;
	}
	if (state == PM_SUSPEND_FREEZE) {
		printk(info_test, pm_states[state]);
		status = pm_suspend(state);
	}

	if (status < 0)
		printk(err_suspend, status);

	test_repeat_count_current++;
	if (test_repeat_count_current < test_repeat_count_max)
		goto repeat;

	/* Some platforms can't detect that the alarm triggered the
	 * wakeup, or (accordingly) disable it after it afterwards.
	 * It's supposed to give oneshot behavior; cope.
@@ -137,16 +151,28 @@ static char warn_bad_state[] __initdata =
static int __init setup_test_suspend(char *value)
{
	int i;
	char *repeat;
	char *suspend_type;

	/* "=mem" ==> "mem" */
	/* example : "=mem[,N]" ==> "mem[,N]" */
	value++;
	suspend_type = strsep(&value, ",");
	if (!suspend_type)
		return 0;

	repeat = strsep(&value, ",");
	if (repeat) {
		if (kstrtou32(repeat, 0, &test_repeat_count_max))
			return 0;
	}

	for (i = 0; pm_labels[i]; i++)
		if (!strcmp(pm_labels[i], value)) {
		if (!strcmp(pm_labels[i], suspend_type)) {
			test_state_label = pm_labels[i];
			return 0;
		}

	printk(warn_bad_state, value);
	printk(warn_bad_state, suspend_type);
	return 0;
}
__setup("test_suspend", setup_test_suspend);