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
This commit is contained in:
Rafael J. Wysocki
2014-10-07 01:17:30 +02:00
5 changed files with 88 additions and 32 deletions
+38 -14
View File
@@ -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);
__free_page(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
View File
@@ -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
View File
@@ -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);