aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/kernel-parameters.txt10
-rw-r--r--drivers/base/power/sysfs.c24
-rw-r--r--kernel/power/snapshot.c54
-rw-r--r--kernel/power/suspend.c2
-rw-r--r--kernel/power/suspend_test.c32
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
95static const char enabled[] = "enabled";
96static const char disabled[] = "disabled";
97
98const char power_group_name[] = "power"; 95const char power_group_name[] = "power";
99EXPORT_SYMBOL_GPL(power_group_name); 96EXPORT_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
336static const char _enabled[] = "enabled";
337static const char _disabled[] = "disabled";
338
339static ssize_t 339static ssize_t
340wake_show(struct device * dev, struct device_attribute *attr, char * buf) 340wake_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
576static ssize_t async_store(struct device *dev, struct device_attribute *attr, 577static 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
728static 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
728static int memory_bm_test_bit(struct memory_bitmap *bm, unsigned long pfn) 736static 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
1334void swsusp_free(void) 1342void 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) && 1352loop:
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
1376out:
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
24static unsigned long suspend_test_start_time; 24static unsigned long suspend_test_start_time;
25static u32 test_repeat_count_max = 1;
26static u32 test_repeat_count_current;
25 27
26void suspend_test_start(void) 28void 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 */
79repeat:
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 =
137static int __init setup_test_suspend(char *value) 151static 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);