diff options
| author | john stultz <johnstul@us.ibm.com> | 2006-06-26 03:25:08 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-26 12:58:20 -0400 |
| commit | cf3c769b4b0dd1146da84d5cf045dcfe53bd0f13 (patch) | |
| tree | caeb91eff6538ed5910e673a40a9f2bd9a022afa /kernel/timer.c | |
| parent | 5eb6d20533d14a432df714520939a6181e28f099 (diff) | |
[PATCH] Time: Introduce arch generic time accessors
Introduces clocksource switching code and the arch generic time accessor
functions that use the clocksource infrastructure.
Signed-off-by: John Stultz <johnstul@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel/timer.c')
| -rw-r--r-- | kernel/timer.c | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/kernel/timer.c b/kernel/timer.c index 6811436a031..e5adb9e2e7a 100644 --- a/kernel/timer.c +++ b/kernel/timer.c | |||
| @@ -795,6 +795,169 @@ u64 current_tick_length(long shift) | |||
| 795 | #include <linux/clocksource.h> | 795 | #include <linux/clocksource.h> |
| 796 | static struct clocksource *clock; /* pointer to current clocksource */ | 796 | static struct clocksource *clock; /* pointer to current clocksource */ |
| 797 | static cycle_t last_clock_cycle; /* cycle value at last update_wall_time */ | 797 | static cycle_t last_clock_cycle; /* cycle value at last update_wall_time */ |
| 798 | |||
| 799 | #ifdef CONFIG_GENERIC_TIME | ||
| 800 | /** | ||
| 801 | * __get_nsec_offset - Returns nanoseconds since last call to periodic_hook | ||
| 802 | * | ||
| 803 | * private function, must hold xtime_lock lock when being | ||
| 804 | * called. Returns the number of nanoseconds since the | ||
| 805 | * last call to update_wall_time() (adjusted by NTP scaling) | ||
| 806 | */ | ||
| 807 | static inline s64 __get_nsec_offset(void) | ||
| 808 | { | ||
| 809 | cycle_t cycle_now, cycle_delta; | ||
| 810 | s64 ns_offset; | ||
| 811 | |||
| 812 | /* read clocksource: */ | ||
| 813 | cycle_now = read_clocksource(clock); | ||
| 814 | |||
| 815 | /* calculate the delta since the last update_wall_time: */ | ||
| 816 | cycle_delta = (cycle_now - last_clock_cycle) & clock->mask; | ||
| 817 | |||
| 818 | /* convert to nanoseconds: */ | ||
| 819 | ns_offset = cyc2ns(clock, cycle_delta); | ||
| 820 | |||
| 821 | return ns_offset; | ||
| 822 | } | ||
| 823 | |||
| 824 | /** | ||
| 825 | * __get_realtime_clock_ts - Returns the time of day in a timespec | ||
| 826 | * @ts: pointer to the timespec to be set | ||
| 827 | * | ||
| 828 | * Returns the time of day in a timespec. Used by | ||
| 829 | * do_gettimeofday() and get_realtime_clock_ts(). | ||
| 830 | */ | ||
| 831 | static inline void __get_realtime_clock_ts(struct timespec *ts) | ||
| 832 | { | ||
| 833 | unsigned long seq; | ||
| 834 | s64 nsecs; | ||
| 835 | |||
| 836 | do { | ||
| 837 | seq = read_seqbegin(&xtime_lock); | ||
| 838 | |||
| 839 | *ts = xtime; | ||
| 840 | nsecs = __get_nsec_offset(); | ||
| 841 | |||
| 842 | } while (read_seqretry(&xtime_lock, seq)); | ||
| 843 | |||
| 844 | timespec_add_ns(ts, nsecs); | ||
| 845 | } | ||
| 846 | |||
| 847 | /** | ||
| 848 | * get_realtime_clock_ts - Returns the time of day in a timespec | ||
| 849 | * @ts: pointer to the timespec to be set | ||
| 850 | * | ||
| 851 | * Returns the time of day in a timespec. | ||
| 852 | */ | ||
| 853 | void getnstimeofday(struct timespec *ts) | ||
| 854 | { | ||
| 855 | __get_realtime_clock_ts(ts); | ||
| 856 | } | ||
| 857 | |||
| 858 | EXPORT_SYMBOL(getnstimeofday); | ||
| 859 | |||
| 860 | /** | ||
| 861 | * do_gettimeofday - Returns the time of day in a timeval | ||
| 862 | * @tv: pointer to the timeval to be set | ||
| 863 | * | ||
| 864 | * NOTE: Users should be converted to using get_realtime_clock_ts() | ||
| 865 | */ | ||
| 866 | void do_gettimeofday(struct timeval *tv) | ||
| 867 | { | ||
| 868 | struct timespec now; | ||
| 869 | |||
| 870 | __get_realtime_clock_ts(&now); | ||
| 871 | tv->tv_sec = now.tv_sec; | ||
| 872 | tv->tv_usec = now.tv_nsec/1000; | ||
| 873 | } | ||
| 874 | |||
| 875 | EXPORT_SYMBOL(do_gettimeofday); | ||
| 876 | /** | ||
| 877 | * do_settimeofday - Sets the time of day | ||
| 878 | * @tv: pointer to the timespec variable containing the new time | ||
| 879 | * | ||
| 880 | * Sets the time of day to the new time and update NTP and notify hrtimers | ||
| 881 | */ | ||
| 882 | int do_settimeofday(struct timespec *tv) | ||
| 883 | { | ||
| 884 | unsigned long flags; | ||
| 885 | time_t wtm_sec, sec = tv->tv_sec; | ||
| 886 | long wtm_nsec, nsec = tv->tv_nsec; | ||
| 887 | |||
| 888 | if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) | ||
| 889 | return -EINVAL; | ||
| 890 | |||
| 891 | write_seqlock_irqsave(&xtime_lock, flags); | ||
| 892 | |||
| 893 | nsec -= __get_nsec_offset(); | ||
| 894 | |||
| 895 | wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); | ||
| 896 | wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); | ||
| 897 | |||
| 898 | set_normalized_timespec(&xtime, sec, nsec); | ||
| 899 | set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); | ||
| 900 | |||
| 901 | ntp_clear(); | ||
| 902 | |||
| 903 | write_sequnlock_irqrestore(&xtime_lock, flags); | ||
| 904 | |||
| 905 | /* signal hrtimers about time change */ | ||
| 906 | clock_was_set(); | ||
| 907 | |||
| 908 | return 0; | ||
| 909 | } | ||
| 910 | |||
| 911 | EXPORT_SYMBOL(do_settimeofday); | ||
| 912 | |||
| 913 | /** | ||
| 914 | * change_clocksource - Swaps clocksources if a new one is available | ||
| 915 | * | ||
| 916 | * Accumulates current time interval and initializes new clocksource | ||
| 917 | */ | ||
| 918 | static int change_clocksource(void) | ||
| 919 | { | ||
| 920 | struct clocksource *new; | ||
| 921 | cycle_t now; | ||
| 922 | u64 nsec; | ||
| 923 | new = get_next_clocksource(); | ||
| 924 | if (clock != new) { | ||
| 925 | now = read_clocksource(new); | ||
| 926 | nsec = __get_nsec_offset(); | ||
| 927 | timespec_add_ns(&xtime, nsec); | ||
| 928 | |||
| 929 | clock = new; | ||
| 930 | last_clock_cycle = now; | ||
| 931 | printk(KERN_INFO "Time: %s clocksource has been installed.\n", | ||
| 932 | clock->name); | ||
| 933 | return 1; | ||
| 934 | } else if (clock->update_callback) { | ||
| 935 | return clock->update_callback(); | ||
| 936 | } | ||
| 937 | return 0; | ||
| 938 | } | ||
| 939 | #else | ||
| 940 | #define change_clocksource() (0) | ||
| 941 | #endif | ||
| 942 | |||
| 943 | /** | ||
| 944 | * timeofday_is_continuous - check to see if timekeeping is free running | ||
| 945 | */ | ||
| 946 | int timekeeping_is_continuous(void) | ||
| 947 | { | ||
| 948 | unsigned long seq; | ||
| 949 | int ret; | ||
| 950 | |||
| 951 | do { | ||
| 952 | seq = read_seqbegin(&xtime_lock); | ||
| 953 | |||
| 954 | ret = clock->is_continuous; | ||
| 955 | |||
| 956 | } while (read_seqretry(&xtime_lock, seq)); | ||
| 957 | |||
| 958 | return ret; | ||
| 959 | } | ||
| 960 | |||
| 798 | /* | 961 | /* |
| 799 | * timekeeping_init - Initializes the clocksource and common timekeeping values | 962 | * timekeeping_init - Initializes the clocksource and common timekeeping values |
| 800 | */ | 963 | */ |
| @@ -901,6 +1064,13 @@ static void update_wall_time(void) | |||
| 901 | /* store full nanoseconds into xtime */ | 1064 | /* store full nanoseconds into xtime */ |
| 902 | xtime.tv_nsec = remainder_snsecs >> clock->shift; | 1065 | xtime.tv_nsec = remainder_snsecs >> clock->shift; |
| 903 | remainder_snsecs -= (s64)xtime.tv_nsec << clock->shift; | 1066 | remainder_snsecs -= (s64)xtime.tv_nsec << clock->shift; |
| 1067 | |||
| 1068 | /* check to see if there is a new clocksource to use */ | ||
| 1069 | if (change_clocksource()) { | ||
| 1070 | error = 0; | ||
| 1071 | remainder_snsecs = 0; | ||
| 1072 | calculate_clocksource_interval(clock, tick_nsec); | ||
| 1073 | } | ||
| 904 | } | 1074 | } |
| 905 | 1075 | ||
| 906 | /* | 1076 | /* |
