aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/time/timekeeping.c52
1 files changed, 29 insertions, 23 deletions
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 41579e7fcf9d..f1a21ce491e6 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -154,7 +154,7 @@ __cacheline_aligned_in_smp DEFINE_SEQLOCK(xtime_lock);
154 */ 154 */
155struct timespec xtime __attribute__ ((aligned (16))); 155struct timespec xtime __attribute__ ((aligned (16)));
156struct timespec wall_to_monotonic __attribute__ ((aligned (16))); 156struct timespec wall_to_monotonic __attribute__ ((aligned (16)));
157static unsigned long total_sleep_time; /* seconds */ 157static struct timespec total_sleep_time;
158 158
159/* 159/*
160 * The raw monotonic time for the CLOCK_MONOTONIC_RAW posix clock. 160 * The raw monotonic time for the CLOCK_MONOTONIC_RAW posix clock.
@@ -487,17 +487,18 @@ int timekeeping_valid_for_hres(void)
487} 487}
488 488
489/** 489/**
490 * read_persistent_clock - Return time in seconds from the persistent clock. 490 * read_persistent_clock - Return time from the persistent clock.
491 * 491 *
492 * Weak dummy function for arches that do not yet support it. 492 * Weak dummy function for arches that do not yet support it.
493 * Returns seconds from epoch using the battery backed persistent clock. 493 * Reads the time from the battery backed persistent clock.
494 * Returns zero if unsupported. 494 * Returns a timespec with tv_sec=0 and tv_nsec=0 if unsupported.
495 * 495 *
496 * XXX - Do be sure to remove it once all arches implement it. 496 * XXX - Do be sure to remove it once all arches implement it.
497 */ 497 */
498unsigned long __attribute__((weak)) read_persistent_clock(void) 498void __attribute__((weak)) read_persistent_clock(struct timespec *ts)
499{ 499{
500 return 0; 500 ts->tv_sec = 0;
501 ts->tv_nsec = 0;
501} 502}
502 503
503/* 504/*
@@ -507,7 +508,9 @@ void __init timekeeping_init(void)
507{ 508{
508 struct clocksource *clock; 509 struct clocksource *clock;
509 unsigned long flags; 510 unsigned long flags;
510 unsigned long sec = read_persistent_clock(); 511 struct timespec now;
512
513 read_persistent_clock(&now);
511 514
512 write_seqlock_irqsave(&xtime_lock, flags); 515 write_seqlock_irqsave(&xtime_lock, flags);
513 516
@@ -518,19 +521,20 @@ void __init timekeeping_init(void)
518 clock->enable(clock); 521 clock->enable(clock);
519 timekeeper_setup_internals(clock); 522 timekeeper_setup_internals(clock);
520 523
521 xtime.tv_sec = sec; 524 xtime.tv_sec = now.tv_sec;
522 xtime.tv_nsec = 0; 525 xtime.tv_nsec = now.tv_nsec;
523 raw_time.tv_sec = 0; 526 raw_time.tv_sec = 0;
524 raw_time.tv_nsec = 0; 527 raw_time.tv_nsec = 0;
525 set_normalized_timespec(&wall_to_monotonic, 528 set_normalized_timespec(&wall_to_monotonic,
526 -xtime.tv_sec, -xtime.tv_nsec); 529 -xtime.tv_sec, -xtime.tv_nsec);
527 update_xtime_cache(0); 530 update_xtime_cache(0);
528 total_sleep_time = 0; 531 total_sleep_time.tv_sec = 0;
532 total_sleep_time.tv_nsec = 0;
529 write_sequnlock_irqrestore(&xtime_lock, flags); 533 write_sequnlock_irqrestore(&xtime_lock, flags);
530} 534}
531 535
532/* time in seconds when suspend began */ 536/* time in seconds when suspend began */
533static unsigned long timekeeping_suspend_time; 537static struct timespec timekeeping_suspend_time;
534 538
535/** 539/**
536 * timekeeping_resume - Resumes the generic timekeeping subsystem. 540 * timekeeping_resume - Resumes the generic timekeeping subsystem.
@@ -543,18 +547,19 @@ static unsigned long timekeeping_suspend_time;
543static int timekeeping_resume(struct sys_device *dev) 547static int timekeeping_resume(struct sys_device *dev)
544{ 548{
545 unsigned long flags; 549 unsigned long flags;
546 unsigned long now = read_persistent_clock(); 550 struct timespec ts;
551
552 read_persistent_clock(&ts);
547 553
548 clocksource_resume(); 554 clocksource_resume();
549 555
550 write_seqlock_irqsave(&xtime_lock, flags); 556 write_seqlock_irqsave(&xtime_lock, flags);
551 557
552 if (now && (now > timekeeping_suspend_time)) { 558 if (timespec_compare(&ts, &timekeeping_suspend_time) > 0) {
553 unsigned long sleep_length = now - timekeeping_suspend_time; 559 ts = timespec_sub(ts, timekeeping_suspend_time);
554 560 xtime = timespec_add_safe(xtime, ts);
555 xtime.tv_sec += sleep_length; 561 wall_to_monotonic = timespec_sub(wall_to_monotonic, ts);
556 wall_to_monotonic.tv_sec -= sleep_length; 562 total_sleep_time = timespec_add_safe(total_sleep_time, ts);
557 total_sleep_time += sleep_length;
558 } 563 }
559 update_xtime_cache(0); 564 update_xtime_cache(0);
560 /* re-base the last cycle value */ 565 /* re-base the last cycle value */
@@ -577,7 +582,7 @@ static int timekeeping_suspend(struct sys_device *dev, pm_message_t state)
577{ 582{
578 unsigned long flags; 583 unsigned long flags;
579 584
580 timekeeping_suspend_time = read_persistent_clock(); 585 read_persistent_clock(&timekeeping_suspend_time);
581 586
582 write_seqlock_irqsave(&xtime_lock, flags); 587 write_seqlock_irqsave(&xtime_lock, flags);
583 timekeeping_forward_now(); 588 timekeeping_forward_now();
@@ -801,9 +806,10 @@ void update_wall_time(void)
801 */ 806 */
802void getboottime(struct timespec *ts) 807void getboottime(struct timespec *ts)
803{ 808{
804 set_normalized_timespec(ts, 809 struct timespec boottime;
805 - (wall_to_monotonic.tv_sec + total_sleep_time), 810
806 - wall_to_monotonic.tv_nsec); 811 boottime = timespec_add_safe(wall_to_monotonic, total_sleep_time);
812 set_normalized_timespec(ts, -boottime.tv_sec, -boottime.tv_nsec);
807} 813}
808 814
809/** 815/**
@@ -812,7 +818,7 @@ void getboottime(struct timespec *ts)
812 */ 818 */
813void monotonic_to_bootbased(struct timespec *ts) 819void monotonic_to_bootbased(struct timespec *ts)
814{ 820{
815 ts->tv_sec += total_sleep_time; 821 *ts = timespec_add_safe(*ts, total_sleep_time);
816} 822}
817 823
818unsigned long get_seconds(void) 824unsigned long get_seconds(void)