Re: [tip:timers/core] time: Add timekeeping_inject_sleeptime
From: Arve Hjønnevåg
Date: Fri Apr 29 2011 - 19:28:25 EST
On Fri, Apr 29, 2011 at 10:31 AM, tip-bot for John Stultz
<john.stultz@xxxxxxxxxx> wrote:
...
>
> time: Add timekeeping_inject_sleeptime
>
> Some platforms cannot implement read_persistent_clock, as
> their RTC devices are only accessible when interrupts are enabled.
> This keeps them from being used by the timekeeping code on resume
> to measure the time in suspend.
>
> The RTC layer tries to work around this, by calling do_settimeofday
> on resume after irqs are reenabled to set the time properly. However,
> this only corrects CLOCK_REALTIME, and does not properly adjust
> the sleep time value. This causes btime in /proc/stat to be incorrect
> as well as making the new CLOCK_BOTTTIME inaccurate.
>
> This patch resolves the issue by introducing a new timekeeping hook
> to allow the RTC layer to inject the sleep time on resume.
>
> The code also checks to make sure that read_persistent_clock is
> nonfunctional before setting the sleep time, so that should the RTC's
> HCTOSYS option be configured in on a system that does support
> read_persistent_clock we will not increase the total_sleep_time twice.
>
> CC: Arve Hjønnevåg <arve@xxxxxxxxxxx>
> CC: Thomas Gleixner <tglx@xxxxxxxxxxxxx>
> Acked-by: Arnd Bergmann <arnd@xxxxxxxx>
> Signed-off-by: John Stultz <john.stultz@xxxxxxxxxx>
> ---
> drivers/rtc/class.c | 23 +++++++-----------
> include/linux/time.h | 1 +
> kernel/time/timekeeping.c | 56 ++++++++++++++++++++++++++++++++++++++++++--
> 3 files changed, 63 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
> index 3901386..4194e59 100644
> --- a/drivers/rtc/class.c
> +++ b/drivers/rtc/class.c
> @@ -41,26 +41,21 @@ static void rtc_device_release(struct device *dev)
> * system's wall clock; restore it on resume().
> */
>
> -static struct timespec delta;
> static time_t oldtime;
> +static struct timespec oldts;
>
> static int rtc_suspend(struct device *dev, pm_message_t mesg)
> {
> struct rtc_device *rtc = to_rtc_device(dev);
> struct rtc_time tm;
> - struct timespec ts = current_kernel_time();
>
> if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0)
> return 0;
>
> rtc_read_time(rtc, &tm);
> + ktime_get_ts(&oldts);
> rtc_tm_to_time(&tm, &oldtime);
>
> - /* RTC precision is 1 second; adjust delta for avg 1/2 sec err */
> - set_normalized_timespec(&delta,
> - ts.tv_sec - oldtime,
> - ts.tv_nsec - (NSEC_PER_SEC >> 1));
> -
> return 0;
> }
>
> @@ -70,10 +65,12 @@ static int rtc_resume(struct device *dev)
> struct rtc_time tm;
> time_t newtime;
> struct timespec time;
> + struct timespec newts;
>
> if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0)
> return 0;
>
> + ktime_get_ts(&newts);
> rtc_read_time(rtc, &tm);
> if (rtc_valid_tm(&tm) != 0) {
> pr_debug("%s: bogus resume time\n", dev_name(&rtc->dev));
> @@ -85,15 +82,13 @@ static int rtc_resume(struct device *dev)
> pr_debug("%s: time travel!\n", dev_name(&rtc->dev));
> return 0;
> }
> + /* calculate the RTC time delta */
> + set_normalized_timespec(&time, newtime - oldtime, 0);
>
> - /* restore wall clock using delta against this RTC;
> - * adjust again for avg 1/2 second RTC sampling error
> - */
> - set_normalized_timespec(&time,
> - newtime + delta.tv_sec,
> - (NSEC_PER_SEC >> 1) + delta.tv_nsec);
> - do_settimeofday(&time);
> + /* subtract kernel time between rtc_suspend to rtc_resume */
> + time = timespec_sub(time, timespec_sub(newts, oldts));
The delta you got from the rtc can be almost a second to long or
short. Do you do anything to prevent these errors from accumulating?
>
> + timekeeping_inject_sleeptime(&time);
> return 0;
> }
>
...
--
Arve Hjønnevåg
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/