Previously the bogus CMOS RTC sleep time has been ignored if pm_trace is enabled, however once the system successfully resumed back, any further read to CMOS RTC would return an error. Actually it is more user-friendly to bring the system back to normal after resumed.
This patch has registered an pm notifier to restore the RTC to the value before been overwitten by pm_trace. Cc: "Rafael J. Wysocki" <r...@rjwysocki.net> Cc: Thomas Gleixner <t...@linutronix.de> Cc: Len Brown <l...@kernel.org> Cc: John Stultz <john.stu...@linaro.org> Cc: Xunlei Pang <xlp...@redhat.com> Signed-off-by: Chen Yu <yu.c.c...@intel.com> --- drivers/base/power/trace.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/base/power/trace.c b/drivers/base/power/trace.c index aa9109a..1e6c611 100644 --- a/drivers/base/power/trace.c +++ b/drivers/base/power/trace.c @@ -10,6 +10,7 @@ #include <linux/pm-trace.h> #include <linux/export.h> #include <linux/rtc.h> +#include <linux/suspend.h> #include <linux/mc146818rtc.h> @@ -76,6 +77,11 @@ bool pm_trace_rtc_abused __read_mostly; static unsigned int dev_hash_value; +struct rtc_time_save { + struct rtc_time time; + atomic_t saved; +}; +static struct rtc_time_save rtc_saved; static int set_magic_time(unsigned int user, unsigned int file, unsigned int device) { @@ -104,6 +110,8 @@ static int set_magic_time(unsigned int user, unsigned int file, unsigned int dev n /= 24; time.tm_min = (n % 20) * 3; n /= 20; + if (!atomic_cmpxchg(&rtc_saved.saved, 0, 1)) + mc146818_get_time(&rtc_saved.time); mc146818_set_time(&time); pm_trace_rtc_abused = true; return n ? -1 : 0; @@ -240,10 +248,31 @@ int show_trace_dev_match(char *buf, size_t size) device_pm_unlock(); return ret; } +static int pm_trace_notify(struct notifier_block *nb, + unsigned long mode, void *_unused) +{ + switch (mode) { + case PM_POST_HIBERNATION: + case PM_POST_SUSPEND: + if (atomic_cmpxchg(&rtc_saved.saved, 1, 0)) { + mc146818_set_time(&rtc_saved.time); + pm_trace_rtc_abused = false; + } + break; + default: + break; + } + return 0; +} + +static struct notifier_block pm_trace_nb = { + .notifier_call = pm_trace_notify, +}; static int early_resume_init(void) { hash_value_early_read = read_magic_time(); + register_pm_notifier(&pm_trace_nb); return 0; } -- 2.7.4