Message ID | 1422547147-3073-1-git-send-email-xlpang@126.com |
---|---|
State | New |
Headers | show |
Ping ... On 29 January 2015 at 23:59, Xunlei Pang <xlpang@126.com> wrote: > From: Xunlei Pang <pang.xunlei@linaro.org> > > If a system does not provide a persistent_clock(), the time > will be updated on resume by rtc_resume(). With the addition > of the non-stop clocksources for suspend timing, those systems > set the time on resume in timekeeping_resume(), but may not > provide a valid persistent_clock(). > > This results in the rtc_resume() logic thinking no one has set > the time and it then will over-write the suspend time again, > which is not necessary and only increases clock error. > > So, fix this for rtc_resume(). > > Signed-off-by: Xunlei Pang <pang.xunlei@linaro.org> > --- > v2->v3: > Refine according to John's comments using internal variable. > > drivers/rtc/class.c | 2 +- > include/linux/timekeeping.h | 1 + > kernel/time/timekeeping.c | 32 ++++++++++++++++++++------------ > 3 files changed, 22 insertions(+), 13 deletions(-) > > diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c > index 472a5ad..6100af5 100644 > --- a/drivers/rtc/class.c > +++ b/drivers/rtc/class.c > @@ -102,7 +102,7 @@ static int rtc_resume(struct device *dev) > struct timespec64 sleep_time; > int err; > > - if (has_persistent_clock()) > + if (timekeeping_sleeptime_injected()) > return 0; > > rtc_hctosys_ret = -ENODEV; > diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h > index 9b63d13..17a460d 100644 > --- a/include/linux/timekeeping.h > +++ b/include/linux/timekeeping.h > @@ -225,6 +225,7 @@ static inline void timekeeping_clocktai(struct timespec *ts) > /* > * RTC specific > */ > +extern bool timekeeping_sleeptime_injected(void); > extern void timekeeping_inject_sleeptime64(struct timespec64 *delta); > > /* > diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c > index 6a93185..b02133e 100644 > --- a/kernel/time/timekeeping.c > +++ b/kernel/time/timekeeping.c > @@ -1125,12 +1125,26 @@ static void __timekeeping_inject_sleeptime(struct timekeeper *tk, > tk_debug_account_sleep_time(delta); > } > > +static bool sleeptime_inject; > + > +#if defined(CONFIG_RTC_CLASS) && \ > + defined(CONFIG_PM_SLEEP) && \ > + defined(CONFIG_RTC_HCTOSYS_DEVICE) > +/** > + * Used by rtc_resume(). > + */ > +bool timekeeping_sleeptime_injected(void) > +{ > + return sleeptime_inject; > +} > + > /** > * timekeeping_inject_sleeptime64 - Adds suspend interval to timeekeeping values > * @delta: pointer to a timespec64 delta value > * > * This hook is for architectures that cannot support read_persistent_clock > - * because their RTC/persistent clock is only accessible when irqs are enabled. > + * because their RTC/persistent clock is only accessible when irqs are enabled, > + * and also don't have an effective nonstop clocksource. > * > * This function should only be called by rtc_resume(), and allows > * a suspend offset to be injected into the timekeeping values. > @@ -1140,13 +1154,6 @@ void timekeeping_inject_sleeptime64(struct timespec64 *delta) > struct timekeeper *tk = &tk_core.timekeeper; > unsigned long flags; > > - /* > - * Make sure we don't set the clock twice, as timekeeping_resume() > - * already did it > - */ > - if (has_persistent_clock()) > - return; > - > raw_spin_lock_irqsave(&timekeeper_lock, flags); > write_seqcount_begin(&tk_core.seq); > > @@ -1162,6 +1169,7 @@ void timekeeping_inject_sleeptime64(struct timespec64 *delta) > /* signal hrtimers about time change */ > clock_was_set(); > } > +#endif > > /** > * timekeeping_resume - Resumes the generic timekeeping subsystem. > @@ -1178,8 +1186,8 @@ static void timekeeping_resume(void) > struct timespec64 ts_new, ts_delta; > struct timespec tmp; > cycle_t cycle_now, cycle_delta; > - bool suspendtime_found = false; > > + sleeptime_inject = false; > read_persistent_clock(&tmp); > ts_new = timespec_to_timespec64(tmp); > > @@ -1226,13 +1234,13 @@ static void timekeeping_resume(void) > nsec += ((u64) cycle_delta * mult) >> shift; > > ts_delta = ns_to_timespec64(nsec); > - suspendtime_found = true; > + sleeptime_inject = true; > } else if (timespec64_compare(&ts_new, &timekeeping_suspend_time) > 0) { > ts_delta = timespec64_sub(ts_new, timekeeping_suspend_time); > - suspendtime_found = true; > + sleeptime_inject = true; > } > > - if (suspendtime_found) > + if (sleeptime_inject) > __timekeeping_inject_sleeptime(tk, &ts_delta); > > /* Re-base the last cycle value */ > -- > 1.9.1 > > -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
On Thu, Jan 29, 2015 at 11:59 PM, Xunlei Pang <xlpang@126.com> wrote: > From: Xunlei Pang <pang.xunlei@linaro.org> > > If a system does not provide a persistent_clock(), the time > will be updated on resume by rtc_resume(). With the addition > of the non-stop clocksources for suspend timing, those systems > set the time on resume in timekeeping_resume(), but may not > provide a valid persistent_clock(). > > This results in the rtc_resume() logic thinking no one has set > the time and it then will over-write the suspend time again, > which is not necessary and only increases clock error. > > So, fix this for rtc_resume(). > > Signed-off-by: Xunlei Pang <pang.xunlei@linaro.org> > --- > v2->v3: > Refine according to John's comments using internal variable. > > drivers/rtc/class.c | 2 +- > include/linux/timekeeping.h | 1 + > kernel/time/timekeeping.c | 32 ++++++++++++++++++++------------ > 3 files changed, 22 insertions(+), 13 deletions(-) > > diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c > index 472a5ad..6100af5 100644 > --- a/drivers/rtc/class.c > +++ b/drivers/rtc/class.c > @@ -102,7 +102,7 @@ static int rtc_resume(struct device *dev) > struct timespec64 sleep_time; > int err; > > - if (has_persistent_clock()) > + if (timekeeping_sleeptime_injected()) > return 0; Took a closer look here.. So you're replacing has_persistent_clock() in the resume side, but not the suspend... Can we not cleanup has_persistent_clock and consolidate to one accessor for both sides of the suspend? > > rtc_hctosys_ret = -ENODEV; > diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h > index 9b63d13..17a460d 100644 > --- a/include/linux/timekeeping.h > +++ b/include/linux/timekeeping.h > @@ -225,6 +225,7 @@ static inline void timekeeping_clocktai(struct timespec *ts) > /* > * RTC specific > */ > +extern bool timekeeping_sleeptime_injected(void); > extern void timekeeping_inject_sleeptime64(struct timespec64 *delta); > > /* > diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c > index 6a93185..b02133e 100644 > --- a/kernel/time/timekeeping.c > +++ b/kernel/time/timekeeping.c > @@ -1125,12 +1125,26 @@ static void __timekeeping_inject_sleeptime(struct timekeeper *tk, > tk_debug_account_sleep_time(delta); > } > > +static bool sleeptime_inject; > + > +#if defined(CONFIG_RTC_CLASS) && \ > + defined(CONFIG_PM_SLEEP) && \ > + defined(CONFIG_RTC_HCTOSYS_DEVICE) This change wasn't explained in the commit message. Its fine as a small optimization, but probably should be split into its own patch. thanks -john -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Hi John, On 11 February 2015 at 08:01, John Stultz <john.stultz@linaro.org> wrote: > On Thu, Jan 29, 2015 at 11:59 PM, Xunlei Pang <xlpang@126.com> wrote: >> From: Xunlei Pang <pang.xunlei@linaro.org> >> >> If a system does not provide a persistent_clock(), the time >> will be updated on resume by rtc_resume(). With the addition >> of the non-stop clocksources for suspend timing, those systems >> set the time on resume in timekeeping_resume(), but may not >> provide a valid persistent_clock(). >> >> This results in the rtc_resume() logic thinking no one has set >> the time and it then will over-write the suspend time again, >> which is not necessary and only increases clock error. >> >> So, fix this for rtc_resume(). >> >> Signed-off-by: Xunlei Pang <pang.xunlei@linaro.org> >> --- >> v2->v3: >> Refine according to John's comments using internal variable. >> >> drivers/rtc/class.c | 2 +- >> include/linux/timekeeping.h | 1 + >> kernel/time/timekeeping.c | 32 ++++++++++++++++++++------------ >> 3 files changed, 22 insertions(+), 13 deletions(-) >> >> diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c >> index 472a5ad..6100af5 100644 >> --- a/drivers/rtc/class.c >> +++ b/drivers/rtc/class.c >> @@ -102,7 +102,7 @@ static int rtc_resume(struct device *dev) >> struct timespec64 sleep_time; >> int err; >> >> - if (has_persistent_clock()) >> + if (timekeeping_sleeptime_injected()) >> return 0; > > Took a closer look here.. So you're replacing has_persistent_clock() > in the resume side, but not the suspend... Can we not cleanup > has_persistent_clock and consolidate to one accessor for both sides of > the suspend? The sequential calls when the system is suspended are: rtc_suspend(), then timekeeping_suspend(). The sequential calls when the system is resumed are: timekeeping_resume(), then rtc_resume(). Obviously, timekeeping_sleeptime_injected() used by rtc_resume() can be easily determined at timekeeping_resume(). And for nonstop clocksources, currently we have code below: timekeeping_resume(): cycle_now = tk->tkr.read(clock); if ((clock->flags & CLOCK_SOURCE_SUSPEND_NONSTOP) && cycle_now > tk->tkr.cycle_last) { Here comes the confusing thing: "cycle_now > tk->tkr.cycle_last". I can't quite catch what's the purpose by judging cycle_now and cycle_last here, May Nonstop clocksource get wrapped or still can get disfunctional during system suspend? If so, I think it would be hard to judge exactly whether rtc_suspend() is needed for nonstop clocksource cases. If we can get rid of this judgement, I think it would be easy to consolidate this just using read_persistent_clock() and CLOCK_SOURCE_SUSPEND_NONSTOP flag. Any suggestion for this? Thanks, Xunlei > >> >> rtc_hctosys_ret = -ENODEV; >> diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h >> index 9b63d13..17a460d 100644 >> --- a/include/linux/timekeeping.h >> +++ b/include/linux/timekeeping.h >> @@ -225,6 +225,7 @@ static inline void timekeeping_clocktai(struct timespec *ts) >> /* >> * RTC specific >> */ >> +extern bool timekeeping_sleeptime_injected(void); >> extern void timekeeping_inject_sleeptime64(struct timespec64 *delta); >> >> /* >> diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c >> index 6a93185..b02133e 100644 >> --- a/kernel/time/timekeeping.c >> +++ b/kernel/time/timekeeping.c >> @@ -1125,12 +1125,26 @@ static void __timekeeping_inject_sleeptime(struct timekeeper *tk, >> tk_debug_account_sleep_time(delta); >> } >> >> +static bool sleeptime_inject; >> + >> +#if defined(CONFIG_RTC_CLASS) && \ >> + defined(CONFIG_PM_SLEEP) && \ >> + defined(CONFIG_RTC_HCTOSYS_DEVICE) > > This change wasn't explained in the commit message. Its fine as a > small optimization, but probably should be split into its own patch. > > thanks > -john -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 472a5ad..6100af5 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -102,7 +102,7 @@ static int rtc_resume(struct device *dev) struct timespec64 sleep_time; int err; - if (has_persistent_clock()) + if (timekeeping_sleeptime_injected()) return 0; rtc_hctosys_ret = -ENODEV; diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h index 9b63d13..17a460d 100644 --- a/include/linux/timekeeping.h +++ b/include/linux/timekeeping.h @@ -225,6 +225,7 @@ static inline void timekeeping_clocktai(struct timespec *ts) /* * RTC specific */ +extern bool timekeeping_sleeptime_injected(void); extern void timekeeping_inject_sleeptime64(struct timespec64 *delta); /* diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 6a93185..b02133e 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -1125,12 +1125,26 @@ static void __timekeeping_inject_sleeptime(struct timekeeper *tk, tk_debug_account_sleep_time(delta); } +static bool sleeptime_inject; + +#if defined(CONFIG_RTC_CLASS) && \ + defined(CONFIG_PM_SLEEP) && \ + defined(CONFIG_RTC_HCTOSYS_DEVICE) +/** + * Used by rtc_resume(). + */ +bool timekeeping_sleeptime_injected(void) +{ + return sleeptime_inject; +} + /** * timekeeping_inject_sleeptime64 - Adds suspend interval to timeekeeping values * @delta: pointer to a timespec64 delta value * * This hook is for architectures that cannot support read_persistent_clock - * because their RTC/persistent clock is only accessible when irqs are enabled. + * because their RTC/persistent clock is only accessible when irqs are enabled, + * and also don't have an effective nonstop clocksource. * * This function should only be called by rtc_resume(), and allows * a suspend offset to be injected into the timekeeping values. @@ -1140,13 +1154,6 @@ void timekeeping_inject_sleeptime64(struct timespec64 *delta) struct timekeeper *tk = &tk_core.timekeeper; unsigned long flags; - /* - * Make sure we don't set the clock twice, as timekeeping_resume() - * already did it - */ - if (has_persistent_clock()) - return; - raw_spin_lock_irqsave(&timekeeper_lock, flags); write_seqcount_begin(&tk_core.seq); @@ -1162,6 +1169,7 @@ void timekeeping_inject_sleeptime64(struct timespec64 *delta) /* signal hrtimers about time change */ clock_was_set(); } +#endif /** * timekeeping_resume - Resumes the generic timekeeping subsystem. @@ -1178,8 +1186,8 @@ static void timekeeping_resume(void) struct timespec64 ts_new, ts_delta; struct timespec tmp; cycle_t cycle_now, cycle_delta; - bool suspendtime_found = false; + sleeptime_inject = false; read_persistent_clock(&tmp); ts_new = timespec_to_timespec64(tmp); @@ -1226,13 +1234,13 @@ static void timekeeping_resume(void) nsec += ((u64) cycle_delta * mult) >> shift; ts_delta = ns_to_timespec64(nsec); - suspendtime_found = true; + sleeptime_inject = true; } else if (timespec64_compare(&ts_new, &timekeeping_suspend_time) > 0) { ts_delta = timespec64_sub(ts_new, timekeeping_suspend_time); - suspendtime_found = true; + sleeptime_inject = true; } - if (suspendtime_found) + if (sleeptime_inject) __timekeeping_inject_sleeptime(tk, &ts_delta); /* Re-base the last cycle value */