aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/time/timekeeping.c
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2011-05-14 06:06:36 -0400
committerThomas Gleixner <tglx@linutronix.de>2011-05-14 06:06:36 -0400
commita18f22a968de17b29f2310cdb7ba69163e65ec15 (patch)
treea7d56d88fad5e444d7661484109758a2f436129e /kernel/time/timekeeping.c
parenta1c57e0fec53defe745e64417eacdbd3618c3e66 (diff)
parent798778b8653f64b7b2162ac70eca10367cff6ce8 (diff)
Merge branch 'consolidate-clksrc-i8253' of master.kernel.org:~rmk/linux-2.6-arm into timers/clocksource
Conflicts: arch/ia64/kernel/cyclone.c arch/mips/kernel/i8253.c arch/x86/kernel/i8253.c Reason: Resolve conflicts so further cleanups do not conflict further Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/time/timekeeping.c')
-rw-r--r--kernel/time/timekeeping.c168
1 files changed, 141 insertions, 27 deletions
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index d27c7562902c..8ad5d576755e 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -14,7 +14,7 @@
14#include <linux/init.h> 14#include <linux/init.h>
15#include <linux/mm.h> 15#include <linux/mm.h>
16#include <linux/sched.h> 16#include <linux/sched.h>
17#include <linux/sysdev.h> 17#include <linux/syscore_ops.h>
18#include <linux/clocksource.h> 18#include <linux/clocksource.h>
19#include <linux/jiffies.h> 19#include <linux/jiffies.h>
20#include <linux/time.h> 20#include <linux/time.h>
@@ -353,7 +353,7 @@ EXPORT_SYMBOL(do_gettimeofday);
353 * 353 *
354 * Sets the time of day to the new time and update NTP and notify hrtimers 354 * Sets the time of day to the new time and update NTP and notify hrtimers
355 */ 355 */
356int do_settimeofday(struct timespec *tv) 356int do_settimeofday(const struct timespec *tv)
357{ 357{
358 struct timespec ts_delta; 358 struct timespec ts_delta;
359 unsigned long flags; 359 unsigned long flags;
@@ -387,6 +387,42 @@ int do_settimeofday(struct timespec *tv)
387 387
388EXPORT_SYMBOL(do_settimeofday); 388EXPORT_SYMBOL(do_settimeofday);
389 389
390
391/**
392 * timekeeping_inject_offset - Adds or subtracts from the current time.
393 * @tv: pointer to the timespec variable containing the offset
394 *
395 * Adds or subtracts an offset value from the current time.
396 */
397int timekeeping_inject_offset(struct timespec *ts)
398{
399 unsigned long flags;
400
401 if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC)
402 return -EINVAL;
403
404 write_seqlock_irqsave(&xtime_lock, flags);
405
406 timekeeping_forward_now();
407
408 xtime = timespec_add(xtime, *ts);
409 wall_to_monotonic = timespec_sub(wall_to_monotonic, *ts);
410
411 timekeeper.ntp_error = 0;
412 ntp_clear();
413
414 update_vsyscall(&xtime, &wall_to_monotonic, timekeeper.clock,
415 timekeeper.mult);
416
417 write_sequnlock_irqrestore(&xtime_lock, flags);
418
419 /* signal hrtimers about time change */
420 clock_was_set();
421
422 return 0;
423}
424EXPORT_SYMBOL(timekeeping_inject_offset);
425
390/** 426/**
391 * change_clocksource - Swaps clocksources if a new one is available 427 * change_clocksource - Swaps clocksources if a new one is available
392 * 428 *
@@ -561,13 +597,12 @@ static struct timespec timekeeping_suspend_time;
561 597
562/** 598/**
563 * timekeeping_resume - Resumes the generic timekeeping subsystem. 599 * timekeeping_resume - Resumes the generic timekeeping subsystem.
564 * @dev: unused
565 * 600 *
566 * This is for the generic clocksource timekeeping. 601 * This is for the generic clocksource timekeeping.
567 * xtime/wall_to_monotonic/jiffies/etc are 602 * xtime/wall_to_monotonic/jiffies/etc are
568 * still managed by arch specific suspend/resume code. 603 * still managed by arch specific suspend/resume code.
569 */ 604 */
570static int timekeeping_resume(struct sys_device *dev) 605static void timekeeping_resume(void)
571{ 606{
572 unsigned long flags; 607 unsigned long flags;
573 struct timespec ts; 608 struct timespec ts;
@@ -596,11 +631,9 @@ static int timekeeping_resume(struct sys_device *dev)
596 631
597 /* Resume hrtimers */ 632 /* Resume hrtimers */
598 hres_timers_resume(); 633 hres_timers_resume();
599
600 return 0;
601} 634}
602 635
603static int timekeeping_suspend(struct sys_device *dev, pm_message_t state) 636static int timekeeping_suspend(void)
604{ 637{
605 unsigned long flags; 638 unsigned long flags;
606 639
@@ -618,26 +651,18 @@ static int timekeeping_suspend(struct sys_device *dev, pm_message_t state)
618} 651}
619 652
620/* sysfs resume/suspend bits for timekeeping */ 653/* sysfs resume/suspend bits for timekeeping */
621static struct sysdev_class timekeeping_sysclass = { 654static struct syscore_ops timekeeping_syscore_ops = {
622 .name = "timekeeping",
623 .resume = timekeeping_resume, 655 .resume = timekeeping_resume,
624 .suspend = timekeeping_suspend, 656 .suspend = timekeeping_suspend,
625}; 657};
626 658
627static struct sys_device device_timer = { 659static int __init timekeeping_init_ops(void)
628 .id = 0,
629 .cls = &timekeeping_sysclass,
630};
631
632static int __init timekeeping_init_device(void)
633{ 660{
634 int error = sysdev_class_register(&timekeeping_sysclass); 661 register_syscore_ops(&timekeeping_syscore_ops);
635 if (!error) 662 return 0;
636 error = sysdev_register(&device_timer);
637 return error;
638} 663}
639 664
640device_initcall(timekeeping_init_device); 665device_initcall(timekeeping_init_ops);
641 666
642/* 667/*
643 * If the error is already larger, we look ahead even further 668 * If the error is already larger, we look ahead even further
@@ -779,7 +804,7 @@ static cycle_t logarithmic_accumulation(cycle_t offset, int shift)
779 * 804 *
780 * Called from the timer interrupt, must hold a write on xtime_lock. 805 * Called from the timer interrupt, must hold a write on xtime_lock.
781 */ 806 */
782void update_wall_time(void) 807static void update_wall_time(void)
783{ 808{
784 struct clocksource *clock; 809 struct clocksource *clock;
785 cycle_t offset; 810 cycle_t offset;
@@ -871,7 +896,7 @@ void update_wall_time(void)
871 * getboottime - Return the real time of system boot. 896 * getboottime - Return the real time of system boot.
872 * @ts: pointer to the timespec to be set 897 * @ts: pointer to the timespec to be set
873 * 898 *
874 * Returns the time of day in a timespec. 899 * Returns the wall-time of boot in a timespec.
875 * 900 *
876 * This is based on the wall_to_monotonic offset and the total suspend 901 * This is based on the wall_to_monotonic offset and the total suspend
877 * time. Calls to settimeofday will affect the value returned (which 902 * time. Calls to settimeofday will affect the value returned (which
@@ -889,6 +914,55 @@ void getboottime(struct timespec *ts)
889} 914}
890EXPORT_SYMBOL_GPL(getboottime); 915EXPORT_SYMBOL_GPL(getboottime);
891 916
917
918/**
919 * get_monotonic_boottime - Returns monotonic time since boot
920 * @ts: pointer to the timespec to be set
921 *
922 * Returns the monotonic time since boot in a timespec.
923 *
924 * This is similar to CLOCK_MONTONIC/ktime_get_ts, but also
925 * includes the time spent in suspend.
926 */
927void get_monotonic_boottime(struct timespec *ts)
928{
929 struct timespec tomono, sleep;
930 unsigned int seq;
931 s64 nsecs;
932
933 WARN_ON(timekeeping_suspended);
934
935 do {
936 seq = read_seqbegin(&xtime_lock);
937 *ts = xtime;
938 tomono = wall_to_monotonic;
939 sleep = total_sleep_time;
940 nsecs = timekeeping_get_ns();
941
942 } while (read_seqretry(&xtime_lock, seq));
943
944 set_normalized_timespec(ts, ts->tv_sec + tomono.tv_sec + sleep.tv_sec,
945 ts->tv_nsec + tomono.tv_nsec + sleep.tv_nsec + nsecs);
946}
947EXPORT_SYMBOL_GPL(get_monotonic_boottime);
948
949/**
950 * ktime_get_boottime - Returns monotonic time since boot in a ktime
951 *
952 * Returns the monotonic time since boot in a ktime
953 *
954 * This is similar to CLOCK_MONTONIC/ktime_get, but also
955 * includes the time spent in suspend.
956 */
957ktime_t ktime_get_boottime(void)
958{
959 struct timespec ts;
960
961 get_monotonic_boottime(&ts);
962 return timespec_to_ktime(ts);
963}
964EXPORT_SYMBOL_GPL(ktime_get_boottime);
965
892/** 966/**
893 * monotonic_to_bootbased - Convert the monotonic time to boot based. 967 * monotonic_to_bootbased - Convert the monotonic time to boot based.
894 * @ts: pointer to the timespec to be converted 968 * @ts: pointer to the timespec to be converted
@@ -910,11 +984,6 @@ struct timespec __current_kernel_time(void)
910 return xtime; 984 return xtime;
911} 985}
912 986
913struct timespec __get_wall_to_monotonic(void)
914{
915 return wall_to_monotonic;
916}
917
918struct timespec current_kernel_time(void) 987struct timespec current_kernel_time(void)
919{ 988{
920 struct timespec now; 989 struct timespec now;
@@ -946,3 +1015,48 @@ struct timespec get_monotonic_coarse(void)
946 now.tv_nsec + mono.tv_nsec); 1015 now.tv_nsec + mono.tv_nsec);
947 return now; 1016 return now;
948} 1017}
1018
1019/*
1020 * The 64-bit jiffies value is not atomic - you MUST NOT read it
1021 * without sampling the sequence number in xtime_lock.
1022 * jiffies is defined in the linker script...
1023 */
1024void do_timer(unsigned long ticks)
1025{
1026 jiffies_64 += ticks;
1027 update_wall_time();
1028 calc_global_load(ticks);
1029}
1030
1031/**
1032 * get_xtime_and_monotonic_and_sleep_offset() - get xtime, wall_to_monotonic,
1033 * and sleep offsets.
1034 * @xtim: pointer to timespec to be set with xtime
1035 * @wtom: pointer to timespec to be set with wall_to_monotonic
1036 * @sleep: pointer to timespec to be set with time in suspend
1037 */
1038void get_xtime_and_monotonic_and_sleep_offset(struct timespec *xtim,
1039 struct timespec *wtom, struct timespec *sleep)
1040{
1041 unsigned long seq;
1042
1043 do {
1044 seq = read_seqbegin(&xtime_lock);
1045 *xtim = xtime;
1046 *wtom = wall_to_monotonic;
1047 *sleep = total_sleep_time;
1048 } while (read_seqretry(&xtime_lock, seq));
1049}
1050
1051/**
1052 * xtime_update() - advances the timekeeping infrastructure
1053 * @ticks: number of ticks, that have elapsed since the last call.
1054 *
1055 * Must be called with interrupts disabled.
1056 */
1057void xtime_update(unsigned long ticks)
1058{
1059 write_seqlock(&xtime_lock);
1060 do_timer(ticks);
1061 write_sequnlock(&xtime_lock);
1062}