diff options
Diffstat (limited to 'kernel/time')
-rw-r--r-- | kernel/time/timekeeping.c | 52 |
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 | */ |
155 | struct timespec xtime __attribute__ ((aligned (16))); | 155 | struct timespec xtime __attribute__ ((aligned (16))); |
156 | struct timespec wall_to_monotonic __attribute__ ((aligned (16))); | 156 | struct timespec wall_to_monotonic __attribute__ ((aligned (16))); |
157 | static unsigned long total_sleep_time; /* seconds */ | 157 | static 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 | */ |
498 | unsigned long __attribute__((weak)) read_persistent_clock(void) | 498 | void __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 */ |
533 | static unsigned long timekeeping_suspend_time; | 537 | static 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; | |||
543 | static int timekeeping_resume(struct sys_device *dev) | 547 | static 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 | */ |
802 | void getboottime(struct timespec *ts) | 807 | void 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 | */ |
813 | void monotonic_to_bootbased(struct timespec *ts) | 819 | void 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 | ||
818 | unsigned long get_seconds(void) | 824 | unsigned long get_seconds(void) |