diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2011-05-14 06:06:36 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2011-05-14 06:06:36 -0400 |
commit | a18f22a968de17b29f2310cdb7ba69163e65ec15 (patch) | |
tree | a7d56d88fad5e444d7661484109758a2f436129e /kernel/time/timekeeping.c | |
parent | a1c57e0fec53defe745e64417eacdbd3618c3e66 (diff) | |
parent | 798778b8653f64b7b2162ac70eca10367cff6ce8 (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.c | 168 |
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 | */ |
356 | int do_settimeofday(struct timespec *tv) | 356 | int 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 | ||
388 | EXPORT_SYMBOL(do_settimeofday); | 388 | EXPORT_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 | */ | ||
397 | int 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 | } | ||
424 | EXPORT_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 | */ |
570 | static int timekeeping_resume(struct sys_device *dev) | 605 | static 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 | ||
603 | static int timekeeping_suspend(struct sys_device *dev, pm_message_t state) | 636 | static 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 */ |
621 | static struct sysdev_class timekeeping_sysclass = { | 654 | static 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 | ||
627 | static struct sys_device device_timer = { | 659 | static int __init timekeeping_init_ops(void) |
628 | .id = 0, | ||
629 | .cls = &timekeeping_sysclass, | ||
630 | }; | ||
631 | |||
632 | static 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 | ||
640 | device_initcall(timekeeping_init_device); | 665 | device_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 | */ |
782 | void update_wall_time(void) | 807 | static 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 | } |
890 | EXPORT_SYMBOL_GPL(getboottime); | 915 | EXPORT_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 | */ | ||
927 | void 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 | } | ||
947 | EXPORT_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 | */ | ||
957 | ktime_t ktime_get_boottime(void) | ||
958 | { | ||
959 | struct timespec ts; | ||
960 | |||
961 | get_monotonic_boottime(&ts); | ||
962 | return timespec_to_ktime(ts); | ||
963 | } | ||
964 | EXPORT_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 | ||
913 | struct timespec __get_wall_to_monotonic(void) | ||
914 | { | ||
915 | return wall_to_monotonic; | ||
916 | } | ||
917 | |||
918 | struct timespec current_kernel_time(void) | 987 | struct 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 | */ | ||
1024 | void 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 | */ | ||
1038 | void 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 | */ | ||
1057 | void xtime_update(unsigned long ticks) | ||
1058 | { | ||
1059 | write_seqlock(&xtime_lock); | ||
1060 | do_timer(ticks); | ||
1061 | write_sequnlock(&xtime_lock); | ||
1062 | } | ||