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
commit 0ede470030
5 changed files with 88 additions and 32 deletions

View file

@ -3303,11 +3303,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
tdfx= [HW,DRM] tdfx= [HW,DRM]
test_suspend= [SUSPEND] test_suspend= [SUSPEND][,N]
Specify "mem" (for Suspend-to-RAM) or "standby" (for Specify "mem" (for Suspend-to-RAM) or "standby" (for
standby suspend) as the system sleep state to briefly standby suspend) or "freeze" (for suspend type freeze)
enter during system startup. The system is woken from as the system sleep state during system startup with
this state using a wakeup-capable RTC alarm. 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] thash_entries= [KNL,NET]
Set number of hash buckets for TCP connection Set number of hash buckets for TCP connection

View file

@ -92,9 +92,6 @@
* wakeup_count - Report the number of wakeup events related to the device * 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"; const char power_group_name[] = "power";
EXPORT_SYMBOL_GPL(power_group_name); EXPORT_SYMBOL_GPL(power_group_name);
@ -336,11 +333,14 @@ static DEVICE_ATTR(pm_qos_remote_wakeup, 0644,
#endif /* CONFIG_PM_RUNTIME */ #endif /* CONFIG_PM_RUNTIME */
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
static const char _enabled[] = "enabled";
static const char _disabled[] = "disabled";
static ssize_t static ssize_t
wake_show(struct device * dev, struct device_attribute *attr, char * buf) wake_show(struct device * dev, struct device_attribute *attr, char * buf)
{ {
return sprintf(buf, "%s\n", device_can_wakeup(dev) 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); cp = memchr(buf, '\n', n);
if (cp) if (cp)
len = cp - buf; len = cp - buf;
if (len == sizeof enabled - 1 if (len == sizeof _enabled - 1
&& strncmp(buf, enabled, sizeof enabled - 1) == 0) && strncmp(buf, _enabled, sizeof _enabled - 1) == 0)
device_set_wakeup_enable(dev, 1); device_set_wakeup_enable(dev, 1);
else if (len == sizeof disabled - 1 else if (len == sizeof _disabled - 1
&& strncmp(buf, disabled, sizeof disabled - 1) == 0) && strncmp(buf, _disabled, sizeof _disabled - 1) == 0)
device_set_wakeup_enable(dev, 0); device_set_wakeup_enable(dev, 0);
else else
return -EINVAL; return -EINVAL;
@ -570,7 +570,8 @@ static ssize_t async_show(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
return sprintf(buf, "%s\n", 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, 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); cp = memchr(buf, '\n', n);
if (cp) if (cp)
len = cp - buf; 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); 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); device_disable_async_suspend(dev);
else else
return -EINVAL; return -EINVAL;

View file

@ -725,6 +725,14 @@ static void memory_bm_clear_bit(struct memory_bitmap *bm, unsigned long pfn)
clear_bit(bit, addr); 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) static int memory_bm_test_bit(struct memory_bitmap *bm, unsigned long pfn)
{ {
void *addr; void *addr;
@ -1333,23 +1341,39 @@ static struct memory_bitmap copy_bm;
void swsusp_free(void) void swsusp_free(void)
{ {
struct zone *zone; unsigned long fb_pfn, fr_pfn;
unsigned long pfn, max_zone_pfn;
for_each_populated_zone(zone) { if (!forbidden_pages_map || !free_pages_map)
max_zone_pfn = zone_end_pfn(zone); goto out;
for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++)
if (pfn_valid(pfn)) {
struct page *page = pfn_to_page(pfn);
if (swsusp_page_is_forbidden(page) && memory_bm_position_reset(forbidden_pages_map);
swsusp_page_is_free(page)) { memory_bm_position_reset(free_pages_map);
swsusp_unset_page_forbidden(page);
swsusp_unset_page_free(page); loop:
__free_page(page); 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_copy_pages = 0;
nr_meta_pages = 0; nr_meta_pages = 0;
restore_pblist = NULL; restore_pblist = NULL;

View file

@ -361,7 +361,9 @@ int suspend_devices_and_enter(suspend_state_t state)
suspend_test_start(); suspend_test_start();
dpm_resume_end(PMSG_RESUME); dpm_resume_end(PMSG_RESUME);
suspend_test_finish("resume devices"); suspend_test_finish("resume devices");
trace_suspend_resume(TPS("resume_console"), state, true);
resume_console(); resume_console();
trace_suspend_resume(TPS("resume_console"), state, false);
Close: Close:
platform_suspend_end(state); platform_suspend_end(state);

View file

@ -22,6 +22,8 @@
#define TEST_SUSPEND_SECONDS 10 #define TEST_SUSPEND_SECONDS 10
static unsigned long suspend_test_start_time; 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) void suspend_test_start(void)
{ {
@ -74,6 +76,7 @@ static void __init test_wakealarm(struct rtc_device *rtc, suspend_state_t state)
int status; int status;
/* this may fail if the RTC hasn't been initialized */ /* this may fail if the RTC hasn't been initialized */
repeat:
status = rtc_read_time(rtc, &alm.time); status = rtc_read_time(rtc, &alm.time);
if (status < 0) { if (status < 0) {
printk(err_readtime, dev_name(&rtc->dev), status); 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) { if (state == PM_SUSPEND_STANDBY) {
printk(info_test, pm_states[state]); printk(info_test, pm_states[state]);
status = pm_suspend(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) if (status < 0)
printk(err_suspend, status); 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 /* Some platforms can't detect that the alarm triggered the
* wakeup, or (accordingly) disable it after it afterwards. * wakeup, or (accordingly) disable it after it afterwards.
* It's supposed to give oneshot behavior; cope. * 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) static int __init setup_test_suspend(char *value)
{ {
int i; int i;
char *repeat;
char *suspend_type;
/* "=mem" ==> "mem" */ /* example : "=mem[,N]" ==> "mem[,N]" */
value++; 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++) 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]; test_state_label = pm_labels[i];
return 0; return 0;
} }
printk(warn_bad_state, value); printk(warn_bad_state, suspend_type);
return 0; return 0;
} }
__setup("test_suspend", setup_test_suspend); __setup("test_suspend", setup_test_suspend);