lkml.org 
[lkml]   [2011]   [Apr]   [29]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    Date
    SubjectRe: [tip:timers/core] time: Add timekeeping_inject_sleeptime
    From
    On Fri, Apr 29, 2011 at 10:31 AM, tip-bot for John Stultz
    <john.stultz@linaro.org> 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@android.com>
    > CC: Thomas Gleixner <tglx@linutronix.de>
    > Acked-by: Arnd Bergmann <arnd@arndb.de>
    > Signed-off-by: John Stultz <john.stultz@linaro.org>
    > ---
    >  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@vger.kernel.org
    More majordomo info at http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at http://www.tux.org/lkml/

    \
     
     \ /
      Last update: 2011-04-30 01:31    [W:2.192 / U:0.036 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site