diff options
Diffstat (limited to 'kernel/time/timekeeping.c')
-rw-r--r-- | kernel/time/timekeeping.c | 37 |
1 files changed, 37 insertions, 0 deletions
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 3d1042f82a68..728cedfd3cbd 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c | |||
@@ -36,9 +36,17 @@ EXPORT_SYMBOL(xtime_lock); | |||
36 | * at zero at system boot time, so wall_to_monotonic will be negative, | 36 | * at zero at system boot time, so wall_to_monotonic will be negative, |
37 | * however, we will ALWAYS keep the tv_nsec part positive so we can use | 37 | * however, we will ALWAYS keep the tv_nsec part positive so we can use |
38 | * the usual normalization. | 38 | * the usual normalization. |
39 | * | ||
40 | * wall_to_monotonic is moved after resume from suspend for the monotonic | ||
41 | * time not to jump. We need to add total_sleep_time to wall_to_monotonic | ||
42 | * to get the real boot based time offset. | ||
43 | * | ||
44 | * - wall_to_monotonic is no longer the boot time, getboottime must be | ||
45 | * used instead. | ||
39 | */ | 46 | */ |
40 | struct timespec xtime __attribute__ ((aligned (16))); | 47 | struct timespec xtime __attribute__ ((aligned (16))); |
41 | struct timespec wall_to_monotonic __attribute__ ((aligned (16))); | 48 | struct timespec wall_to_monotonic __attribute__ ((aligned (16))); |
49 | static unsigned long total_sleep_time; /* seconds */ | ||
42 | 50 | ||
43 | EXPORT_SYMBOL(xtime); | 51 | EXPORT_SYMBOL(xtime); |
44 | 52 | ||
@@ -251,6 +259,7 @@ void __init timekeeping_init(void) | |||
251 | xtime.tv_nsec = 0; | 259 | xtime.tv_nsec = 0; |
252 | set_normalized_timespec(&wall_to_monotonic, | 260 | set_normalized_timespec(&wall_to_monotonic, |
253 | -xtime.tv_sec, -xtime.tv_nsec); | 261 | -xtime.tv_sec, -xtime.tv_nsec); |
262 | total_sleep_time = 0; | ||
254 | 263 | ||
255 | write_sequnlock_irqrestore(&xtime_lock, flags); | 264 | write_sequnlock_irqrestore(&xtime_lock, flags); |
256 | } | 265 | } |
@@ -282,6 +291,7 @@ static int timekeeping_resume(struct sys_device *dev) | |||
282 | 291 | ||
283 | xtime.tv_sec += sleep_length; | 292 | xtime.tv_sec += sleep_length; |
284 | wall_to_monotonic.tv_sec -= sleep_length; | 293 | wall_to_monotonic.tv_sec -= sleep_length; |
294 | total_sleep_time += sleep_length; | ||
285 | } | 295 | } |
286 | /* re-base the last cycle value */ | 296 | /* re-base the last cycle value */ |
287 | clock->cycle_last = clocksource_read(clock); | 297 | clock->cycle_last = clocksource_read(clock); |
@@ -476,3 +486,30 @@ void update_wall_time(void) | |||
476 | change_clocksource(); | 486 | change_clocksource(); |
477 | update_vsyscall(&xtime, clock); | 487 | update_vsyscall(&xtime, clock); |
478 | } | 488 | } |
489 | |||
490 | /** | ||
491 | * getboottime - Return the real time of system boot. | ||
492 | * @ts: pointer to the timespec to be set | ||
493 | * | ||
494 | * Returns the time of day in a timespec. | ||
495 | * | ||
496 | * This is based on the wall_to_monotonic offset and the total suspend | ||
497 | * time. Calls to settimeofday will affect the value returned (which | ||
498 | * basically means that however wrong your real time clock is at boot time, | ||
499 | * you get the right time here). | ||
500 | */ | ||
501 | void getboottime(struct timespec *ts) | ||
502 | { | ||
503 | set_normalized_timespec(ts, | ||
504 | - (wall_to_monotonic.tv_sec + total_sleep_time), | ||
505 | - wall_to_monotonic.tv_nsec); | ||
506 | } | ||
507 | |||
508 | /** | ||
509 | * monotonic_to_bootbased - Convert the monotonic time to boot based. | ||
510 | * @ts: pointer to the timespec to be converted | ||
511 | */ | ||
512 | void monotonic_to_bootbased(struct timespec *ts) | ||
513 | { | ||
514 | ts->tv_sec += total_sleep_time; | ||
515 | } | ||