aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjohn stultz <johnstul@us.ibm.com>2006-06-26 03:25:08 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-26 12:58:20 -0400
commitcf3c769b4b0dd1146da84d5cf045dcfe53bd0f13 (patch)
treecaeb91eff6538ed5910e673a40a9f2bd9a022afa
parent5eb6d20533d14a432df714520939a6181e28f099 (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>
-rw-r--r--include/linux/time.h15
-rw-r--r--kernel/time.c2
-rw-r--r--kernel/timer.c170
3 files changed, 187 insertions, 0 deletions
diff --git a/include/linux/time.h b/include/linux/time.h
index 88d3b812841e..65dd85b2105e 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -102,6 +102,7 @@ extern int do_getitimer(int which, struct itimerval *value);
102extern void getnstimeofday(struct timespec *tv); 102extern void getnstimeofday(struct timespec *tv);
103 103
104extern struct timespec timespec_trunc(struct timespec t, unsigned gran); 104extern struct timespec timespec_trunc(struct timespec t, unsigned gran);
105extern int timekeeping_is_continuous(void);
105 106
106/** 107/**
107 * timespec_to_ns - Convert timespec to nanoseconds 108 * timespec_to_ns - Convert timespec to nanoseconds
@@ -144,6 +145,20 @@ extern struct timespec ns_to_timespec(const s64 nsec);
144 */ 145 */
145extern struct timeval ns_to_timeval(const s64 nsec); 146extern struct timeval ns_to_timeval(const s64 nsec);
146 147
148/**
149 * timespec_add_ns - Adds nanoseconds to a timespec
150 * @a: pointer to timespec to be incremented
151 * @ns: unsigned nanoseconds value to be added
152 */
153static inline void timespec_add_ns(struct timespec *a, u64 ns)
154{
155 ns += a->tv_nsec;
156 while(unlikely(ns >= NSEC_PER_SEC)) {
157 ns -= NSEC_PER_SEC;
158 a->tv_sec++;
159 }
160 a->tv_nsec = ns;
161}
147#endif /* __KERNEL__ */ 162#endif /* __KERNEL__ */
148 163
149#define NFDBITS __NFDBITS 164#define NFDBITS __NFDBITS
diff --git a/kernel/time.c b/kernel/time.c
index b00ddc71cedb..5bd489747643 100644
--- a/kernel/time.c
+++ b/kernel/time.c
@@ -523,6 +523,7 @@ EXPORT_SYMBOL(do_gettimeofday);
523 523
524 524
525#else 525#else
526#ifndef CONFIG_GENERIC_TIME
526/* 527/*
527 * Simulate gettimeofday using do_gettimeofday which only allows a timeval 528 * Simulate gettimeofday using do_gettimeofday which only allows a timeval
528 * and therefore only yields usec accuracy 529 * and therefore only yields usec accuracy
@@ -537,6 +538,7 @@ void getnstimeofday(struct timespec *tv)
537} 538}
538EXPORT_SYMBOL_GPL(getnstimeofday); 539EXPORT_SYMBOL_GPL(getnstimeofday);
539#endif 540#endif
541#endif
540 542
541/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. 543/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
542 * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 544 * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
diff --git a/kernel/timer.c b/kernel/timer.c
index 6811436a031d..e5adb9e2e7a7 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>
796static struct clocksource *clock; /* pointer to current clocksource */ 796static struct clocksource *clock; /* pointer to current clocksource */
797static cycle_t last_clock_cycle; /* cycle value at last update_wall_time */ 797static 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 */
807static 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 */
831static 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 */
853void getnstimeofday(struct timespec *ts)
854{
855 __get_realtime_clock_ts(ts);
856}
857
858EXPORT_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 */
866void 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
875EXPORT_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 */
882int 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
911EXPORT_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 */
918static 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 */
946int 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/*