Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 366174
b: refs/heads/master
c: e445cf1
h: refs/heads/master
v: v3
  • Loading branch information
Feng Tang authored and John Stultz committed Mar 15, 2013
1 parent df4dbb9 commit f706fd6
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 8 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 82f9c080b22a5b859ae2b50822dfb6b812898fdb
refs/heads/master: e445cf1c4257cc0238d72e4129eb4739f46fd3de
58 changes: 51 additions & 7 deletions trunk/kernel/time/timekeeping.c
Original file line number Diff line number Diff line change
Expand Up @@ -788,22 +788,66 @@ void timekeeping_inject_sleeptime(struct timespec *delta)
static void timekeeping_resume(void)
{
struct timekeeper *tk = &timekeeper;
struct clocksource *clock = tk->clock;
unsigned long flags;
struct timespec ts;
struct timespec ts_new, ts_delta;
cycle_t cycle_now, cycle_delta;
bool suspendtime_found = false;

read_persistent_clock(&ts);
read_persistent_clock(&ts_new);

clockevents_resume();
clocksource_resume();

write_seqlock_irqsave(&tk->lock, flags);

if (timespec_compare(&ts, &timekeeping_suspend_time) > 0) {
ts = timespec_sub(ts, timekeeping_suspend_time);
__timekeeping_inject_sleeptime(tk, &ts);
/*
* After system resumes, we need to calculate the suspended time and
* compensate it for the OS time. There are 3 sources that could be
* used: Nonstop clocksource during suspend, persistent clock and rtc
* device.
*
* One specific platform may have 1 or 2 or all of them, and the
* preference will be:
* suspend-nonstop clocksource -> persistent clock -> rtc
* The less preferred source will only be tried if there is no better
* usable source. The rtc part is handled separately in rtc core code.
*/
cycle_now = clock->read(clock);
if ((clock->flags & CLOCK_SOURCE_SUSPEND_NONSTOP) &&
cycle_now > clock->cycle_last) {
u64 num, max = ULLONG_MAX;
u32 mult = clock->mult;
u32 shift = clock->shift;
s64 nsec = 0;

cycle_delta = (cycle_now - clock->cycle_last) & clock->mask;

/*
* "cycle_delta * mutl" may cause 64 bits overflow, if the
* suspended time is too long. In that case we need do the
* 64 bits math carefully
*/
do_div(max, mult);
if (cycle_delta > max) {
num = div64_u64(cycle_delta, max);
nsec = (((u64) max * mult) >> shift) * num;
cycle_delta -= num * max;
}
nsec += ((u64) cycle_delta * mult) >> shift;

ts_delta = ns_to_timespec(nsec);
suspendtime_found = true;
} else if (timespec_compare(&ts_new, &timekeeping_suspend_time) > 0) {
ts_delta = timespec_sub(ts_new, timekeeping_suspend_time);
suspendtime_found = true;
}
/* re-base the last cycle value */
tk->clock->cycle_last = tk->clock->read(tk->clock);

if (suspendtime_found)
__timekeeping_inject_sleeptime(tk, &ts_delta);

/* Re-base the last cycle value */
clock->cycle_last = cycle_now;
tk->ntp_error = 0;
timekeeping_suspended = 0;
timekeeping_update(tk, false);
Expand Down

0 comments on commit f706fd6

Please sign in to comment.