Commit 322e929d authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

Merge back new material related to system-wide PM for v5.6.

parents 18451f9f c052bf82
...@@ -407,3 +407,16 @@ Contact: Kalesh Singh <kaleshsingh96@gmail.com> ...@@ -407,3 +407,16 @@ Contact: Kalesh Singh <kaleshsingh96@gmail.com>
Description: Description:
The /sys/power/suspend_stats/last_failed_step file contains The /sys/power/suspend_stats/last_failed_step file contains
the last failed step in the suspend/resume path. the last failed step in the suspend/resume path.
What: /sys/power/sync_on_suspend
Date: October 2019
Contact: Jonas Meurer <jonas@freesources.org>
Description:
This file controls whether or not the kernel will sync()
filesystems during system suspend (after freezing user space
and before suspending devices).
Writing a "1" to this file enables the sync() and writing a "0"
disables it. Reads from the file return the current value.
The default is "1" if the build-time "SUSPEND_SKIP_SYNC" config
flag is unset, or "0" otherwise.
...@@ -1125,6 +1125,9 @@ static void *wakeup_sources_stats_seq_next(struct seq_file *m, ...@@ -1125,6 +1125,9 @@ static void *wakeup_sources_stats_seq_next(struct seq_file *m,
break; break;
} }
if (!next_ws)
print_wakeup_source_stats(m, &deleted_ws);
return next_ws; return next_ws;
} }
......
...@@ -329,6 +329,7 @@ extern void arch_suspend_disable_irqs(void); ...@@ -329,6 +329,7 @@ extern void arch_suspend_disable_irqs(void);
extern void arch_suspend_enable_irqs(void); extern void arch_suspend_enable_irqs(void);
extern int pm_suspend(suspend_state_t state); extern int pm_suspend(suspend_state_t state);
extern bool sync_on_suspend_enabled;
#else /* !CONFIG_SUSPEND */ #else /* !CONFIG_SUSPEND */
#define suspend_valid_only_mem NULL #define suspend_valid_only_mem NULL
...@@ -342,6 +343,7 @@ static inline bool pm_suspend_default_s2idle(void) { return false; } ...@@ -342,6 +343,7 @@ static inline bool pm_suspend_default_s2idle(void) { return false; }
static inline void suspend_set_ops(const struct platform_suspend_ops *ops) {} static inline void suspend_set_ops(const struct platform_suspend_ops *ops) {}
static inline int pm_suspend(suspend_state_t state) { return -ENOSYS; } static inline int pm_suspend(suspend_state_t state) { return -ENOSYS; }
static inline bool sync_on_suspend_enabled(void) { return true; }
static inline bool idle_should_enter_s2idle(void) { return false; } static inline bool idle_should_enter_s2idle(void) { return false; }
static inline void __init pm_states_init(void) {} static inline void __init pm_states_init(void) {}
static inline void s2idle_set_ops(const struct platform_s2idle_ops *ops) {} static inline void s2idle_set_ops(const struct platform_s2idle_ops *ops) {}
......
...@@ -27,7 +27,10 @@ config SUSPEND_SKIP_SYNC ...@@ -27,7 +27,10 @@ config SUSPEND_SKIP_SYNC
Skip the kernel sys_sync() before freezing user processes. Skip the kernel sys_sync() before freezing user processes.
Some systems prefer not to pay this cost on every invocation Some systems prefer not to pay this cost on every invocation
of suspend, or they are content with invoking sync() from of suspend, or they are content with invoking sync() from
user-space before invoking suspend. Say Y if that's your case. user-space before invoking suspend. There's a run-time switch
at '/sys/power/sync_on_suspend' to configure this behaviour.
This setting changes the default for the run-tim switch. Say Y
to change the default to disable the kernel sys_sync().
config HIBERNATE_CALLBACKS config HIBERNATE_CALLBACKS
bool bool
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* Copyright (C) 2012 Bojan Smojver <bojan@rexursive.com> * Copyright (C) 2012 Bojan Smojver <bojan@rexursive.com>
*/ */
#define pr_fmt(fmt) "PM: " fmt #define pr_fmt(fmt) "PM: hibernation: " fmt
#include <linux/export.h> #include <linux/export.h>
#include <linux/suspend.h> #include <linux/suspend.h>
...@@ -106,7 +106,7 @@ EXPORT_SYMBOL(system_entering_hibernation); ...@@ -106,7 +106,7 @@ EXPORT_SYMBOL(system_entering_hibernation);
#ifdef CONFIG_PM_DEBUG #ifdef CONFIG_PM_DEBUG
static void hibernation_debug_sleep(void) static void hibernation_debug_sleep(void)
{ {
pr_info("hibernation debug: Waiting for 5 seconds.\n"); pr_info("debug: Waiting for 5 seconds.\n");
mdelay(5000); mdelay(5000);
} }
...@@ -277,7 +277,7 @@ static int create_image(int platform_mode) ...@@ -277,7 +277,7 @@ static int create_image(int platform_mode)
error = dpm_suspend_end(PMSG_FREEZE); error = dpm_suspend_end(PMSG_FREEZE);
if (error) { if (error) {
pr_err("Some devices failed to power down, aborting hibernation\n"); pr_err("Some devices failed to power down, aborting\n");
return error; return error;
} }
...@@ -295,7 +295,7 @@ static int create_image(int platform_mode) ...@@ -295,7 +295,7 @@ static int create_image(int platform_mode)
error = syscore_suspend(); error = syscore_suspend();
if (error) { if (error) {
pr_err("Some system devices failed to power down, aborting hibernation\n"); pr_err("Some system devices failed to power down, aborting\n");
goto Enable_irqs; goto Enable_irqs;
} }
...@@ -310,7 +310,7 @@ static int create_image(int platform_mode) ...@@ -310,7 +310,7 @@ static int create_image(int platform_mode)
restore_processor_state(); restore_processor_state();
trace_suspend_resume(TPS("machine_suspend"), PM_EVENT_HIBERNATE, false); trace_suspend_resume(TPS("machine_suspend"), PM_EVENT_HIBERNATE, false);
if (error) if (error)
pr_err("Error %d creating hibernation image\n", error); pr_err("Error %d creating image\n", error);
if (!in_suspend) { if (!in_suspend) {
events_check_enabled = false; events_check_enabled = false;
...@@ -680,7 +680,7 @@ static int load_image_and_restore(void) ...@@ -680,7 +680,7 @@ static int load_image_and_restore(void)
if (!error) if (!error)
hibernation_restore(flags & SF_PLATFORM_MODE); hibernation_restore(flags & SF_PLATFORM_MODE);
pr_err("Failed to load hibernation image, recovering.\n"); pr_err("Failed to load image, recovering.\n");
swsusp_free(); swsusp_free();
free_basic_memory_bitmaps(); free_basic_memory_bitmaps();
Unlock: Unlock:
...@@ -743,7 +743,7 @@ int hibernate(void) ...@@ -743,7 +743,7 @@ int hibernate(void)
else else
flags |= SF_CRC32_MODE; flags |= SF_CRC32_MODE;
pm_pr_dbg("Writing image.\n"); pm_pr_dbg("Writing hibernation image.\n");
error = swsusp_write(flags); error = swsusp_write(flags);
swsusp_free(); swsusp_free();
if (!error) { if (!error) {
...@@ -755,7 +755,7 @@ int hibernate(void) ...@@ -755,7 +755,7 @@ int hibernate(void)
in_suspend = 0; in_suspend = 0;
pm_restore_gfp_mask(); pm_restore_gfp_mask();
} else { } else {
pm_pr_dbg("Image restored successfully.\n"); pm_pr_dbg("Hibernation image restored successfully.\n");
} }
Free_bitmaps: Free_bitmaps:
...@@ -894,7 +894,7 @@ static int software_resume(void) ...@@ -894,7 +894,7 @@ static int software_resume(void)
goto Close_Finish; goto Close_Finish;
} }
pm_pr_dbg("Preparing processes for restore.\n"); pm_pr_dbg("Preparing processes for hibernation restore.\n");
error = freeze_processes(); error = freeze_processes();
if (error) if (error)
goto Close_Finish; goto Close_Finish;
...@@ -903,7 +903,7 @@ static int software_resume(void) ...@@ -903,7 +903,7 @@ static int software_resume(void)
Finish: Finish:
__pm_notifier_call_chain(PM_POST_RESTORE, nr_calls, NULL); __pm_notifier_call_chain(PM_POST_RESTORE, nr_calls, NULL);
pm_restore_console(); pm_restore_console();
pr_info("resume from hibernation failed (%d)\n", error); pr_info("resume failed (%d)\n", error);
atomic_inc(&snapshot_device_available); atomic_inc(&snapshot_device_available);
/* For success case, the suspend path will release the lock */ /* For success case, the suspend path will release the lock */
Unlock: Unlock:
...@@ -1068,7 +1068,8 @@ static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr, ...@@ -1068,7 +1068,8 @@ static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr,
lock_system_sleep(); lock_system_sleep();
swsusp_resume_device = res; swsusp_resume_device = res;
unlock_system_sleep(); unlock_system_sleep();
pm_pr_dbg("Configured resume from disk to %u\n", swsusp_resume_device); pm_pr_dbg("Configured hibernation resume from disk to %u\n",
swsusp_resume_device);
noresume = 0; noresume = 0;
software_resume(); software_resume();
return n; return n;
......
...@@ -190,6 +190,38 @@ static ssize_t mem_sleep_store(struct kobject *kobj, struct kobj_attribute *attr ...@@ -190,6 +190,38 @@ static ssize_t mem_sleep_store(struct kobject *kobj, struct kobj_attribute *attr
} }
power_attr(mem_sleep); power_attr(mem_sleep);
/*
* sync_on_suspend: invoke ksys_sync_helper() before suspend.
*
* show() returns whether ksys_sync_helper() is invoked before suspend.
* store() accepts 0 or 1. 0 disables ksys_sync_helper() and 1 enables it.
*/
bool sync_on_suspend_enabled = !IS_ENABLED(CONFIG_SUSPEND_SKIP_SYNC);
static ssize_t sync_on_suspend_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", sync_on_suspend_enabled);
}
static ssize_t sync_on_suspend_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t n)
{
unsigned long val;
if (kstrtoul(buf, 10, &val))
return -EINVAL;
if (val > 1)
return -EINVAL;
sync_on_suspend_enabled = !!val;
return n;
}
power_attr(sync_on_suspend);
#endif /* CONFIG_SUSPEND */ #endif /* CONFIG_SUSPEND */
#ifdef CONFIG_PM_SLEEP_DEBUG #ifdef CONFIG_PM_SLEEP_DEBUG
...@@ -855,6 +887,7 @@ static struct attribute * g[] = { ...@@ -855,6 +887,7 @@ static struct attribute * g[] = {
&wakeup_count_attr.attr, &wakeup_count_attr.attr,
#ifdef CONFIG_SUSPEND #ifdef CONFIG_SUSPEND
&mem_sleep_attr.attr, &mem_sleep_attr.attr,
&sync_on_suspend_attr.attr,
#endif #endif
#ifdef CONFIG_PM_AUTOSLEEP #ifdef CONFIG_PM_AUTOSLEEP
&autosleep_attr.attr, &autosleep_attr.attr,
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl> * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl>
*/ */
#define pr_fmt(fmt) "PM: " fmt #define pr_fmt(fmt) "PM: hibernation: " fmt
#include <linux/version.h> #include <linux/version.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -1566,9 +1566,7 @@ static unsigned long preallocate_image_highmem(unsigned long nr_pages) ...@@ -1566,9 +1566,7 @@ static unsigned long preallocate_image_highmem(unsigned long nr_pages)
*/ */
static unsigned long __fraction(u64 x, u64 multiplier, u64 base) static unsigned long __fraction(u64 x, u64 multiplier, u64 base)
{ {
x *= multiplier; return div64_u64(x * multiplier, base);
do_div(x, base);
return (unsigned long)x;
} }
static unsigned long preallocate_highmem_fraction(unsigned long nr_pages, static unsigned long preallocate_highmem_fraction(unsigned long nr_pages,
...@@ -1705,16 +1703,20 @@ int hibernate_preallocate_memory(void) ...@@ -1705,16 +1703,20 @@ int hibernate_preallocate_memory(void)
ktime_t start, stop; ktime_t start, stop;
int error; int error;
pr_info("Preallocating image memory... "); pr_info("Preallocating image memory\n");
start = ktime_get(); start = ktime_get();
error = memory_bm_create(&orig_bm, GFP_IMAGE, PG_ANY); error = memory_bm_create(&orig_bm, GFP_IMAGE, PG_ANY);
if (error) if (error) {
pr_err("Cannot allocate original bitmap\n");
goto err_out; goto err_out;
}
error = memory_bm_create(&copy_bm, GFP_IMAGE, PG_ANY); error = memory_bm_create(&copy_bm, GFP_IMAGE, PG_ANY);
if (error) if (error) {
pr_err("Cannot allocate copy bitmap\n");
goto err_out; goto err_out;
}
alloc_normal = 0; alloc_normal = 0;
alloc_highmem = 0; alloc_highmem = 0;
...@@ -1804,8 +1806,11 @@ int hibernate_preallocate_memory(void) ...@@ -1804,8 +1806,11 @@ int hibernate_preallocate_memory(void)
alloc -= pages; alloc -= pages;
pages += pages_highmem; pages += pages_highmem;
pages_highmem = preallocate_image_highmem(alloc); pages_highmem = preallocate_image_highmem(alloc);
if (pages_highmem < alloc) if (pages_highmem < alloc) {
pr_err("Image allocation is %lu pages short\n",
alloc - pages_highmem);
goto err_out; goto err_out;
}
pages += pages_highmem; pages += pages_highmem;
/* /*
* size is the desired number of saveable pages to leave in * size is the desired number of saveable pages to leave in
...@@ -1836,13 +1841,12 @@ int hibernate_preallocate_memory(void) ...@@ -1836,13 +1841,12 @@ int hibernate_preallocate_memory(void)
out: out:
stop = ktime_get(); stop = ktime_get();
pr_cont("done (allocated %lu pages)\n", pages); pr_info("Allocated %lu pages for snapshot\n", pages);
swsusp_show_speed(start, stop, pages, "Allocated"); swsusp_show_speed(start, stop, pages, "Allocated");
return 0; return 0;
err_out: err_out:
pr_cont("\n");
swsusp_free(); swsusp_free();
return -ENOMEM; return -ENOMEM;
} }
...@@ -1976,7 +1980,7 @@ asmlinkage __visible int swsusp_save(void) ...@@ -1976,7 +1980,7 @@ asmlinkage __visible int swsusp_save(void)
{ {
unsigned int nr_pages, nr_highmem; unsigned int nr_pages, nr_highmem;
pr_info("Creating hibernation image:\n"); pr_info("Creating image:\n");
drain_local_pages(NULL); drain_local_pages(NULL);
nr_pages = count_data_pages(); nr_pages = count_data_pages();
...@@ -2010,7 +2014,7 @@ asmlinkage __visible int swsusp_save(void) ...@@ -2010,7 +2014,7 @@ asmlinkage __visible int swsusp_save(void)
nr_copy_pages = nr_pages; nr_copy_pages = nr_pages;
nr_meta_pages = DIV_ROUND_UP(nr_pages * sizeof(long), PAGE_SIZE); nr_meta_pages = DIV_ROUND_UP(nr_pages * sizeof(long), PAGE_SIZE);
pr_info("Hibernation image created (%d pages copied)\n", nr_pages); pr_info("Image created (%d pages copied)\n", nr_pages);
return 0; return 0;
} }
......
...@@ -564,7 +564,7 @@ static int enter_state(suspend_state_t state) ...@@ -564,7 +564,7 @@ static int enter_state(suspend_state_t state)
if (state == PM_SUSPEND_TO_IDLE) if (state == PM_SUSPEND_TO_IDLE)
s2idle_begin(); s2idle_begin();
if (!IS_ENABLED(CONFIG_SUSPEND_SKIP_SYNC)) { if (sync_on_suspend_enabled) {
trace_suspend_resume(TPS("sync_filesystems"), 0, true); trace_suspend_resume(TPS("sync_filesystems"), 0, true);
ksys_sync_helper(); ksys_sync_helper();
trace_suspend_resume(TPS("sync_filesystems"), 0, false); trace_suspend_resume(TPS("sync_filesystems"), 0, false);
......
...@@ -70,7 +70,7 @@ static void __init test_wakealarm(struct rtc_device *rtc, suspend_state_t state) ...@@ -70,7 +70,7 @@ static void __init test_wakealarm(struct rtc_device *rtc, suspend_state_t state)
static char info_test[] __initdata = static char info_test[] __initdata =
KERN_INFO "PM: test RTC wakeup from '%s' suspend\n"; KERN_INFO "PM: test RTC wakeup from '%s' suspend\n";
unsigned long now; time64_t now;
struct rtc_wkalrm alm; struct rtc_wkalrm alm;
int status; int status;
...@@ -81,10 +81,10 @@ static void __init test_wakealarm(struct rtc_device *rtc, suspend_state_t state) ...@@ -81,10 +81,10 @@ static void __init test_wakealarm(struct rtc_device *rtc, suspend_state_t state)
printk(err_readtime, dev_name(&rtc->dev), status); printk(err_readtime, dev_name(&rtc->dev), status);
return; return;
} }
rtc_tm_to_time(&alm.time, &now); now = rtc_tm_to_time64(&alm.time);
memset(&alm, 0, sizeof alm); memset(&alm, 0, sizeof alm);
rtc_time_to_tm(now + TEST_SUSPEND_SECONDS, &alm.time); rtc_time64_to_tm(now + TEST_SUSPEND_SECONDS, &alm.time);
alm.enabled = true; alm.enabled = true;
status = rtc_set_alarm(rtc, &alm); status = rtc_set_alarm(rtc, &alm);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment