diff options
-rw-r--r-- | Documentation/kernel-parameters.txt | 10 | ||||
-rw-r--r-- | drivers/base/power/sysfs.c | 24 | ||||
-rw-r--r-- | kernel/power/snapshot.c | 54 | ||||
-rw-r--r-- | kernel/power/suspend.c | 2 | ||||
-rw-r--r-- | kernel/power/suspend_test.c | 32 |
5 files changed, 89 insertions, 33 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 10d51c2f10d7..ccbab5653bb8 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
@@ -3303,11 +3303,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted. | |||
3303 | 3303 | ||
3304 | tdfx= [HW,DRM] | 3304 | tdfx= [HW,DRM] |
3305 | 3305 | ||
3306 | test_suspend= [SUSPEND] | 3306 | test_suspend= [SUSPEND][,N] |
3307 | Specify "mem" (for Suspend-to-RAM) or "standby" (for | 3307 | Specify "mem" (for Suspend-to-RAM) or "standby" (for |
3308 | standby suspend) as the system sleep state to briefly | 3308 | standby suspend) or "freeze" (for suspend type freeze) |
3309 | enter during system startup. The system is woken from | 3309 | as the system sleep state during system startup with |
3310 | this state using a wakeup-capable RTC alarm. | 3310 | the optional capability to repeat N number of times. |
3311 | The system is woken from this state using a | ||
3312 | wakeup-capable RTC alarm. | ||
3311 | 3313 | ||
3312 | thash_entries= [KNL,NET] | 3314 | thash_entries= [KNL,NET] |
3313 | Set number of hash buckets for TCP connection | 3315 | Set number of hash buckets for TCP connection |
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c index 95b181d1ca6d..a9d26ed11bf4 100644 --- a/drivers/base/power/sysfs.c +++ b/drivers/base/power/sysfs.c | |||
@@ -92,9 +92,6 @@ | |||
92 | * wakeup_count - Report the number of wakeup events related to the device | 92 | * wakeup_count - Report the number of wakeup events related to the device |
93 | */ | 93 | */ |
94 | 94 | ||
95 | static const char enabled[] = "enabled"; | ||
96 | static const char disabled[] = "disabled"; | ||
97 | |||
98 | const char power_group_name[] = "power"; | 95 | const char power_group_name[] = "power"; |
99 | EXPORT_SYMBOL_GPL(power_group_name); | 96 | EXPORT_SYMBOL_GPL(power_group_name); |
100 | 97 | ||
@@ -336,11 +333,14 @@ static DEVICE_ATTR(pm_qos_remote_wakeup, 0644, | |||
336 | #endif /* CONFIG_PM_RUNTIME */ | 333 | #endif /* CONFIG_PM_RUNTIME */ |
337 | 334 | ||
338 | #ifdef CONFIG_PM_SLEEP | 335 | #ifdef CONFIG_PM_SLEEP |
336 | static const char _enabled[] = "enabled"; | ||
337 | static const char _disabled[] = "disabled"; | ||
338 | |||
339 | static ssize_t | 339 | static ssize_t |
340 | wake_show(struct device * dev, struct device_attribute *attr, char * buf) | 340 | wake_show(struct device * dev, struct device_attribute *attr, char * buf) |
341 | { | 341 | { |
342 | return sprintf(buf, "%s\n", device_can_wakeup(dev) | 342 | return sprintf(buf, "%s\n", device_can_wakeup(dev) |
343 | ? (device_may_wakeup(dev) ? enabled : disabled) | 343 | ? (device_may_wakeup(dev) ? _enabled : _disabled) |
344 | : ""); | 344 | : ""); |
345 | } | 345 | } |
346 | 346 | ||
@@ -357,11 +357,11 @@ wake_store(struct device * dev, struct device_attribute *attr, | |||
357 | cp = memchr(buf, '\n', n); | 357 | cp = memchr(buf, '\n', n); |
358 | if (cp) | 358 | if (cp) |
359 | len = cp - buf; | 359 | len = cp - buf; |
360 | if (len == sizeof enabled - 1 | 360 | if (len == sizeof _enabled - 1 |
361 | && strncmp(buf, enabled, sizeof enabled - 1) == 0) | 361 | && strncmp(buf, _enabled, sizeof _enabled - 1) == 0) |
362 | device_set_wakeup_enable(dev, 1); | 362 | device_set_wakeup_enable(dev, 1); |
363 | else if (len == sizeof disabled - 1 | 363 | else if (len == sizeof _disabled - 1 |
364 | && strncmp(buf, disabled, sizeof disabled - 1) == 0) | 364 | && strncmp(buf, _disabled, sizeof _disabled - 1) == 0) |
365 | device_set_wakeup_enable(dev, 0); | 365 | device_set_wakeup_enable(dev, 0); |
366 | else | 366 | else |
367 | return -EINVAL; | 367 | return -EINVAL; |
@@ -570,7 +570,8 @@ static ssize_t async_show(struct device *dev, struct device_attribute *attr, | |||
570 | char *buf) | 570 | char *buf) |
571 | { | 571 | { |
572 | return sprintf(buf, "%s\n", | 572 | return sprintf(buf, "%s\n", |
573 | device_async_suspend_enabled(dev) ? enabled : disabled); | 573 | device_async_suspend_enabled(dev) ? |
574 | _enabled : _disabled); | ||
574 | } | 575 | } |
575 | 576 | ||
576 | static ssize_t async_store(struct device *dev, struct device_attribute *attr, | 577 | 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, | |||
582 | cp = memchr(buf, '\n', n); | 583 | cp = memchr(buf, '\n', n); |
583 | if (cp) | 584 | if (cp) |
584 | len = cp - buf; | 585 | len = cp - buf; |
585 | if (len == sizeof enabled - 1 && strncmp(buf, enabled, len) == 0) | 586 | if (len == sizeof _enabled - 1 && strncmp(buf, _enabled, len) == 0) |
586 | device_enable_async_suspend(dev); | 587 | device_enable_async_suspend(dev); |
587 | else if (len == sizeof disabled - 1 && strncmp(buf, disabled, len) == 0) | 588 | else if (len == sizeof _disabled - 1 && |
589 | strncmp(buf, _disabled, len) == 0) | ||
588 | device_disable_async_suspend(dev); | 590 | device_disable_async_suspend(dev); |
589 | else | 591 | else |
590 | return -EINVAL; | 592 | return -EINVAL; |
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index f1604d8cf489..791a61892bb5 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c | |||
@@ -725,6 +725,14 @@ static void memory_bm_clear_bit(struct memory_bitmap *bm, unsigned long pfn) | |||
725 | clear_bit(bit, addr); | 725 | clear_bit(bit, addr); |
726 | } | 726 | } |
727 | 727 | ||
728 | static void memory_bm_clear_current(struct memory_bitmap *bm) | ||
729 | { | ||
730 | int bit; | ||
731 | |||
732 | bit = max(bm->cur.node_bit - 1, 0); | ||
733 | clear_bit(bit, bm->cur.node->data); | ||
734 | } | ||
735 | |||
728 | static int memory_bm_test_bit(struct memory_bitmap *bm, unsigned long pfn) | 736 | static int memory_bm_test_bit(struct memory_bitmap *bm, unsigned long pfn) |
729 | { | 737 | { |
730 | void *addr; | 738 | void *addr; |
@@ -1333,23 +1341,39 @@ static struct memory_bitmap copy_bm; | |||
1333 | 1341 | ||
1334 | void swsusp_free(void) | 1342 | void swsusp_free(void) |
1335 | { | 1343 | { |
1336 | struct zone *zone; | 1344 | unsigned long fb_pfn, fr_pfn; |
1337 | unsigned long pfn, max_zone_pfn; | ||
1338 | 1345 | ||
1339 | for_each_populated_zone(zone) { | 1346 | if (!forbidden_pages_map || !free_pages_map) |
1340 | max_zone_pfn = zone_end_pfn(zone); | 1347 | goto out; |
1341 | for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++) | 1348 | |
1342 | if (pfn_valid(pfn)) { | 1349 | memory_bm_position_reset(forbidden_pages_map); |
1343 | struct page *page = pfn_to_page(pfn); | 1350 | memory_bm_position_reset(free_pages_map); |
1344 | 1351 | ||
1345 | if (swsusp_page_is_forbidden(page) && | 1352 | loop: |
1346 | swsusp_page_is_free(page)) { | 1353 | fr_pfn = memory_bm_next_pfn(free_pages_map); |
1347 | swsusp_unset_page_forbidden(page); | 1354 | fb_pfn = memory_bm_next_pfn(forbidden_pages_map); |
1348 | swsusp_unset_page_free(page); | 1355 | |
1349 | __free_page(page); | 1356 | /* |
1350 | } | 1357 | * Find the next bit set in both bitmaps. This is guaranteed to |
1351 | } | 1358 | * terminate when fb_pfn == fr_pfn == BM_END_OF_MAP. |
1359 | */ | ||
1360 | do { | ||
1361 | if (fb_pfn < fr_pfn) | ||
1362 | fb_pfn = memory_bm_next_pfn(forbidden_pages_map); | ||
1363 | if (fr_pfn < fb_pfn) | ||
1364 | fr_pfn = memory_bm_next_pfn(free_pages_map); | ||
1365 | } while (fb_pfn != fr_pfn); | ||
1366 | |||
1367 | if (fr_pfn != BM_END_OF_MAP && pfn_valid(fr_pfn)) { | ||
1368 | struct page *page = pfn_to_page(fr_pfn); | ||
1369 | |||
1370 | memory_bm_clear_current(forbidden_pages_map); | ||
1371 | memory_bm_clear_current(free_pages_map); | ||
1372 | __free_page(page); | ||
1373 | goto loop; | ||
1352 | } | 1374 | } |
1375 | |||
1376 | out: | ||
1353 | nr_copy_pages = 0; | 1377 | nr_copy_pages = 0; |
1354 | nr_meta_pages = 0; | 1378 | nr_meta_pages = 0; |
1355 | restore_pblist = NULL; | 1379 | restore_pblist = NULL; |
diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 18c62195660f..e837dd6783c6 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c | |||
@@ -361,7 +361,9 @@ int suspend_devices_and_enter(suspend_state_t state) | |||
361 | suspend_test_start(); | 361 | suspend_test_start(); |
362 | dpm_resume_end(PMSG_RESUME); | 362 | dpm_resume_end(PMSG_RESUME); |
363 | suspend_test_finish("resume devices"); | 363 | suspend_test_finish("resume devices"); |
364 | trace_suspend_resume(TPS("resume_console"), state, true); | ||
364 | resume_console(); | 365 | resume_console(); |
366 | trace_suspend_resume(TPS("resume_console"), state, false); | ||
365 | 367 | ||
366 | Close: | 368 | Close: |
367 | platform_suspend_end(state); | 369 | platform_suspend_end(state); |
diff --git a/kernel/power/suspend_test.c b/kernel/power/suspend_test.c index bd91bc177c93..084452e34a12 100644 --- a/kernel/power/suspend_test.c +++ b/kernel/power/suspend_test.c | |||
@@ -22,6 +22,8 @@ | |||
22 | #define TEST_SUSPEND_SECONDS 10 | 22 | #define TEST_SUSPEND_SECONDS 10 |
23 | 23 | ||
24 | static unsigned long suspend_test_start_time; | 24 | static unsigned long suspend_test_start_time; |
25 | static u32 test_repeat_count_max = 1; | ||
26 | static u32 test_repeat_count_current; | ||
25 | 27 | ||
26 | void suspend_test_start(void) | 28 | void suspend_test_start(void) |
27 | { | 29 | { |
@@ -74,6 +76,7 @@ static void __init test_wakealarm(struct rtc_device *rtc, suspend_state_t state) | |||
74 | int status; | 76 | int status; |
75 | 77 | ||
76 | /* this may fail if the RTC hasn't been initialized */ | 78 | /* this may fail if the RTC hasn't been initialized */ |
79 | repeat: | ||
77 | status = rtc_read_time(rtc, &alm.time); | 80 | status = rtc_read_time(rtc, &alm.time); |
78 | if (status < 0) { | 81 | if (status < 0) { |
79 | printk(err_readtime, dev_name(&rtc->dev), status); | 82 | 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) | |||
100 | if (state == PM_SUSPEND_STANDBY) { | 103 | if (state == PM_SUSPEND_STANDBY) { |
101 | printk(info_test, pm_states[state]); | 104 | printk(info_test, pm_states[state]); |
102 | status = pm_suspend(state); | 105 | status = pm_suspend(state); |
106 | if (status < 0) | ||
107 | state = PM_SUSPEND_FREEZE; | ||
103 | } | 108 | } |
109 | if (state == PM_SUSPEND_FREEZE) { | ||
110 | printk(info_test, pm_states[state]); | ||
111 | status = pm_suspend(state); | ||
112 | } | ||
113 | |||
104 | if (status < 0) | 114 | if (status < 0) |
105 | printk(err_suspend, status); | 115 | printk(err_suspend, status); |
106 | 116 | ||
117 | test_repeat_count_current++; | ||
118 | if (test_repeat_count_current < test_repeat_count_max) | ||
119 | goto repeat; | ||
120 | |||
107 | /* Some platforms can't detect that the alarm triggered the | 121 | /* Some platforms can't detect that the alarm triggered the |
108 | * wakeup, or (accordingly) disable it after it afterwards. | 122 | * wakeup, or (accordingly) disable it after it afterwards. |
109 | * It's supposed to give oneshot behavior; cope. | 123 | * It's supposed to give oneshot behavior; cope. |
@@ -137,16 +151,28 @@ static char warn_bad_state[] __initdata = | |||
137 | static int __init setup_test_suspend(char *value) | 151 | static int __init setup_test_suspend(char *value) |
138 | { | 152 | { |
139 | int i; | 153 | int i; |
154 | char *repeat; | ||
155 | char *suspend_type; | ||
140 | 156 | ||
141 | /* "=mem" ==> "mem" */ | 157 | /* example : "=mem[,N]" ==> "mem[,N]" */ |
142 | value++; | 158 | value++; |
159 | suspend_type = strsep(&value, ","); | ||
160 | if (!suspend_type) | ||
161 | return 0; | ||
162 | |||
163 | repeat = strsep(&value, ","); | ||
164 | if (repeat) { | ||
165 | if (kstrtou32(repeat, 0, &test_repeat_count_max)) | ||
166 | return 0; | ||
167 | } | ||
168 | |||
143 | for (i = 0; pm_labels[i]; i++) | 169 | for (i = 0; pm_labels[i]; i++) |
144 | if (!strcmp(pm_labels[i], value)) { | 170 | if (!strcmp(pm_labels[i], suspend_type)) { |
145 | test_state_label = pm_labels[i]; | 171 | test_state_label = pm_labels[i]; |
146 | return 0; | 172 | return 0; |
147 | } | 173 | } |
148 | 174 | ||
149 | printk(warn_bad_state, value); | 175 | printk(warn_bad_state, suspend_type); |
150 | return 0; | 176 | return 0; |
151 | } | 177 | } |
152 | __setup("test_suspend", setup_test_suspend); | 178 | __setup("test_suspend", setup_test_suspend); |