• Thomas Gleixner's avatar
    timekeeping: Prevent time going backwards on resume · 6a669ee8
    Thomas Gleixner authored
    Timekeeping resume adjusts xtime by adding the slept time in seconds and
    resets the reference value of the clock source (clock->cycle_last).
    clock->cycle last is used to calculate the delta between the last xtime
    update and the readout of the clock source in __get_nsec_offset(). xtime
    plus the offset is the current time. The resume code ignores the delta
    which had already elapsed between the last xtime update and the actual
    time of suspend. If the suspend time is short, then we can see time
    going backwards on resume.
    
    Suspend:
    offs_s = clock->read() - clock->cycle_last;
    now = xtime + offs_s;
    timekeeping_suspend_time = read_rtc();
    
    Resume:
    sleep_time = read_rtc() - timekeeping_suspend_time;
    xtime.tv_sec += sleep_time;
    clock->cycle_last = clock->read();
    offs_r = clock->read() - clock->cycle_last;
    now = xtime + offs_r;
    
    if sleep_time_seconds == 0 and offs_r < offs_s, then time goes
    backwards.
    
    Fix this by storing the offset from the last xtime update and add it to
    xtime during resume, when we reset clock->cycle_last:
    
    sleep_time = read_rtc() - timekeeping_suspend_time;
    xtime.tv_sec += sleep_time;
    xtime += offs_s;	/* Fixup xtime offset at suspend time */
    clock->cycle_last = clock->read();
    offs_r = clock->read() - clock->cycle_last;
    now = xtime + offs_r;
    
    Thanks to Marcelo for tracking this down on the OLPC and providing the
    necessary details to analyze the root cause.
    Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
    Cc: John Stultz <johnstul@us.ibm.com>
    Cc: Tosatti <marcelo@kvack.org>
    6a669ee8
timekeeping.c 13.8 KB