aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/time
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2016-03-04 02:12:27 -0500
committerThomas Gleixner <tglx@linutronix.de>2016-03-04 02:12:27 -0500
commit69365272332a5cbef778c97b2337b4f79c509293 (patch)
treec03bd4d13c12ae3be7282d4624cf25b23e1c2d1c /kernel/time
parent82e88ff1ea948d83125a8aaa7c9809f03ccc500f (diff)
parent01d7ada57ee9c735bd71fbe44ec0bcb70847afd4 (diff)
Merge branch 'fortglx/4.6/time' of https://git.linaro.org/people/john.stultz/linux into timers/core
Pull the cross-timestamp infrastructure from John Stultz. Allows precise correlation of device timestamps with system time. Primary use cases being PTP and audio.
Diffstat (limited to 'kernel/time')
-rw-r--r--kernel/time/timekeeping.c286
1 files changed, 261 insertions, 25 deletions
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 34b4cedfa80d..931b0b1a71e9 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -233,6 +233,7 @@ static void tk_setup_internals(struct timekeeper *tk, struct clocksource *clock)
233 u64 tmp, ntpinterval; 233 u64 tmp, ntpinterval;
234 struct clocksource *old_clock; 234 struct clocksource *old_clock;
235 235
236 ++tk->cs_was_changed_seq;
236 old_clock = tk->tkr_mono.clock; 237 old_clock = tk->tkr_mono.clock;
237 tk->tkr_mono.clock = clock; 238 tk->tkr_mono.clock = clock;
238 tk->tkr_mono.read = clock->read; 239 tk->tkr_mono.read = clock->read;
@@ -298,17 +299,34 @@ u32 (*arch_gettimeoffset)(void) = default_arch_gettimeoffset;
298static inline u32 arch_gettimeoffset(void) { return 0; } 299static inline u32 arch_gettimeoffset(void) { return 0; }
299#endif 300#endif
300 301
302static inline s64 timekeeping_delta_to_ns(struct tk_read_base *tkr,
303 cycle_t delta)
304{
305 s64 nsec;
306
307 nsec = delta * tkr->mult + tkr->xtime_nsec;
308 nsec >>= tkr->shift;
309
310 /* If arch requires, add in get_arch_timeoffset() */
311 return nsec + arch_gettimeoffset();
312}
313
301static inline s64 timekeeping_get_ns(struct tk_read_base *tkr) 314static inline s64 timekeeping_get_ns(struct tk_read_base *tkr)
302{ 315{
303 cycle_t delta; 316 cycle_t delta;
304 s64 nsec;
305 317
306 delta = timekeeping_get_delta(tkr); 318 delta = timekeeping_get_delta(tkr);
319 return timekeeping_delta_to_ns(tkr, delta);
320}
307 321
308 nsec = (delta * tkr->mult + tkr->xtime_nsec) >> tkr->shift; 322static inline s64 timekeeping_cycles_to_ns(struct tk_read_base *tkr,
323 cycle_t cycles)
324{
325 cycle_t delta;
309 326
310 /* If arch requires, add in get_arch_timeoffset() */ 327 /* calculate the delta since the last update_wall_time */
311 return nsec + arch_gettimeoffset(); 328 delta = clocksource_delta(cycles, tkr->cycle_last, tkr->mask);
329 return timekeeping_delta_to_ns(tkr, delta);
312} 330}
313 331
314/** 332/**
@@ -857,44 +875,262 @@ time64_t __ktime_get_real_seconds(void)
857 return tk->xtime_sec; 875 return tk->xtime_sec;
858} 876}
859 877
878/**
879 * ktime_get_snapshot - snapshots the realtime/monotonic raw clocks with counter
880 * @systime_snapshot: pointer to struct receiving the system time snapshot
881 */
882void ktime_get_snapshot(struct system_time_snapshot *systime_snapshot)
883{
884 struct timekeeper *tk = &tk_core.timekeeper;
885 unsigned long seq;
886 ktime_t base_raw;
887 ktime_t base_real;
888 s64 nsec_raw;
889 s64 nsec_real;
890 cycle_t now;
860 891
861#ifdef CONFIG_NTP_PPS 892 WARN_ON_ONCE(timekeeping_suspended);
893
894 do {
895 seq = read_seqcount_begin(&tk_core.seq);
896
897 now = tk->tkr_mono.read(tk->tkr_mono.clock);
898 systime_snapshot->cs_was_changed_seq = tk->cs_was_changed_seq;
899 systime_snapshot->clock_was_set_seq = tk->clock_was_set_seq;
900 base_real = ktime_add(tk->tkr_mono.base,
901 tk_core.timekeeper.offs_real);
902 base_raw = tk->tkr_raw.base;
903 nsec_real = timekeeping_cycles_to_ns(&tk->tkr_mono, now);
904 nsec_raw = timekeeping_cycles_to_ns(&tk->tkr_raw, now);
905 } while (read_seqcount_retry(&tk_core.seq, seq));
906
907 systime_snapshot->cycles = now;
908 systime_snapshot->real = ktime_add_ns(base_real, nsec_real);
909 systime_snapshot->raw = ktime_add_ns(base_raw, nsec_raw);
910}
911EXPORT_SYMBOL_GPL(ktime_get_snapshot);
912
913/* Scale base by mult/div checking for overflow */
914static int scale64_check_overflow(u64 mult, u64 div, u64 *base)
915{
916 u64 tmp, rem;
917
918 tmp = div64_u64_rem(*base, div, &rem);
919
920 if (((int)sizeof(u64)*8 - fls64(mult) < fls64(tmp)) ||
921 ((int)sizeof(u64)*8 - fls64(mult) < fls64(rem)))
922 return -EOVERFLOW;
923 tmp *= mult;
924 rem *= mult;
925
926 do_div(rem, div);
927 *base = tmp + rem;
928 return 0;
929}
862 930
863/** 931/**
864 * ktime_get_raw_and_real_ts64 - get day and raw monotonic time in timespec format 932 * adjust_historical_crosststamp - adjust crosstimestamp previous to current interval
865 * @ts_raw: pointer to the timespec to be set to raw monotonic time 933 * @history: Snapshot representing start of history
866 * @ts_real: pointer to the timespec to be set to the time of day 934 * @partial_history_cycles: Cycle offset into history (fractional part)
935 * @total_history_cycles: Total history length in cycles
936 * @discontinuity: True indicates clock was set on history period
937 * @ts: Cross timestamp that should be adjusted using
938 * partial/total ratio
867 * 939 *
868 * This function reads both the time of day and raw monotonic time at the 940 * Helper function used by get_device_system_crosststamp() to correct the
869 * same time atomically and stores the resulting timestamps in timespec 941 * crosstimestamp corresponding to the start of the current interval to the
870 * format. 942 * system counter value (timestamp point) provided by the driver. The
943 * total_history_* quantities are the total history starting at the provided
944 * reference point and ending at the start of the current interval. The cycle
945 * count between the driver timestamp point and the start of the current
946 * interval is partial_history_cycles.
871 */ 947 */
872void ktime_get_raw_and_real_ts64(struct timespec64 *ts_raw, struct timespec64 *ts_real) 948static int adjust_historical_crosststamp(struct system_time_snapshot *history,
949 cycle_t partial_history_cycles,
950 cycle_t total_history_cycles,
951 bool discontinuity,
952 struct system_device_crosststamp *ts)
873{ 953{
874 struct timekeeper *tk = &tk_core.timekeeper; 954 struct timekeeper *tk = &tk_core.timekeeper;
875 unsigned long seq; 955 u64 corr_raw, corr_real;
876 s64 nsecs_raw, nsecs_real; 956 bool interp_forward;
957 int ret;
877 958
878 WARN_ON_ONCE(timekeeping_suspended); 959 if (total_history_cycles == 0 || partial_history_cycles == 0)
960 return 0;
961
962 /* Interpolate shortest distance from beginning or end of history */
963 interp_forward = partial_history_cycles > total_history_cycles/2 ?
964 true : false;
965 partial_history_cycles = interp_forward ?
966 total_history_cycles - partial_history_cycles :
967 partial_history_cycles;
968
969 /*
970 * Scale the monotonic raw time delta by:
971 * partial_history_cycles / total_history_cycles
972 */
973 corr_raw = (u64)ktime_to_ns(
974 ktime_sub(ts->sys_monoraw, history->raw));
975 ret = scale64_check_overflow(partial_history_cycles,
976 total_history_cycles, &corr_raw);
977 if (ret)
978 return ret;
979
980 /*
981 * If there is a discontinuity in the history, scale monotonic raw
982 * correction by:
983 * mult(real)/mult(raw) yielding the realtime correction
984 * Otherwise, calculate the realtime correction similar to monotonic
985 * raw calculation
986 */
987 if (discontinuity) {
988 corr_real = mul_u64_u32_div
989 (corr_raw, tk->tkr_mono.mult, tk->tkr_raw.mult);
990 } else {
991 corr_real = (u64)ktime_to_ns(
992 ktime_sub(ts->sys_realtime, history->real));
993 ret = scale64_check_overflow(partial_history_cycles,
994 total_history_cycles, &corr_real);
995 if (ret)
996 return ret;
997 }
998
999 /* Fixup monotonic raw and real time time values */
1000 if (interp_forward) {
1001 ts->sys_monoraw = ktime_add_ns(history->raw, corr_raw);
1002 ts->sys_realtime = ktime_add_ns(history->real, corr_real);
1003 } else {
1004 ts->sys_monoraw = ktime_sub_ns(ts->sys_monoraw, corr_raw);
1005 ts->sys_realtime = ktime_sub_ns(ts->sys_realtime, corr_real);
1006 }
1007
1008 return 0;
1009}
1010
1011/*
1012 * cycle_between - true if test occurs chronologically between before and after
1013 */
1014static bool cycle_between(cycle_t before, cycle_t test, cycle_t after)
1015{
1016 if (test > before && test < after)
1017 return true;
1018 if (test < before && before > after)
1019 return true;
1020 return false;
1021}
1022
1023/**
1024 * get_device_system_crosststamp - Synchronously capture system/device timestamp
1025 * @get_time_fn: Callback to get simultaneous device time and
1026 * system counter from the device driver
1027 * @ctx: Context passed to get_time_fn()
1028 * @history_begin: Historical reference point used to interpolate system
1029 * time when counter provided by the driver is before the current interval
1030 * @xtstamp: Receives simultaneously captured system and device time
1031 *
1032 * Reads a timestamp from a device and correlates it to system time
1033 */
1034int get_device_system_crosststamp(int (*get_time_fn)
1035 (ktime_t *device_time,
1036 struct system_counterval_t *sys_counterval,
1037 void *ctx),
1038 void *ctx,
1039 struct system_time_snapshot *history_begin,
1040 struct system_device_crosststamp *xtstamp)
1041{
1042 struct system_counterval_t system_counterval;
1043 struct timekeeper *tk = &tk_core.timekeeper;
1044 cycle_t cycles, now, interval_start;
1045 unsigned int clock_was_set_seq;
1046 ktime_t base_real, base_raw;
1047 s64 nsec_real, nsec_raw;
1048 u8 cs_was_changed_seq;
1049 unsigned long seq;
1050 bool do_interp;
1051 int ret;
879 1052
880 do { 1053 do {
881 seq = read_seqcount_begin(&tk_core.seq); 1054 seq = read_seqcount_begin(&tk_core.seq);
1055 /*
1056 * Try to synchronously capture device time and a system
1057 * counter value calling back into the device driver
1058 */
1059 ret = get_time_fn(&xtstamp->device, &system_counterval, ctx);
1060 if (ret)
1061 return ret;
1062
1063 /*
1064 * Verify that the clocksource associated with the captured
1065 * system counter value is the same as the currently installed
1066 * timekeeper clocksource
1067 */
1068 if (tk->tkr_mono.clock != system_counterval.cs)
1069 return -ENODEV;
1070 cycles = system_counterval.cycles;
882 1071
883 *ts_raw = tk->raw_time; 1072 /*
884 ts_real->tv_sec = tk->xtime_sec; 1073 * Check whether the system counter value provided by the
885 ts_real->tv_nsec = 0; 1074 * device driver is on the current timekeeping interval.
1075 */
1076 now = tk->tkr_mono.read(tk->tkr_mono.clock);
1077 interval_start = tk->tkr_mono.cycle_last;
1078 if (!cycle_between(interval_start, cycles, now)) {
1079 clock_was_set_seq = tk->clock_was_set_seq;
1080 cs_was_changed_seq = tk->cs_was_changed_seq;
1081 cycles = interval_start;
1082 do_interp = true;
1083 } else {
1084 do_interp = false;
1085 }
886 1086
887 nsecs_raw = timekeeping_get_ns(&tk->tkr_raw); 1087 base_real = ktime_add(tk->tkr_mono.base,
888 nsecs_real = timekeeping_get_ns(&tk->tkr_mono); 1088 tk_core.timekeeper.offs_real);
1089 base_raw = tk->tkr_raw.base;
889 1090
1091 nsec_real = timekeeping_cycles_to_ns(&tk->tkr_mono,
1092 system_counterval.cycles);
1093 nsec_raw = timekeeping_cycles_to_ns(&tk->tkr_raw,
1094 system_counterval.cycles);
890 } while (read_seqcount_retry(&tk_core.seq, seq)); 1095 } while (read_seqcount_retry(&tk_core.seq, seq));
891 1096
892 timespec64_add_ns(ts_raw, nsecs_raw); 1097 xtstamp->sys_realtime = ktime_add_ns(base_real, nsec_real);
893 timespec64_add_ns(ts_real, nsecs_real); 1098 xtstamp->sys_monoraw = ktime_add_ns(base_raw, nsec_raw);
894}
895EXPORT_SYMBOL(ktime_get_raw_and_real_ts64);
896 1099
897#endif /* CONFIG_NTP_PPS */ 1100 /*
1101 * Interpolate if necessary, adjusting back from the start of the
1102 * current interval
1103 */
1104 if (do_interp) {
1105 cycle_t partial_history_cycles, total_history_cycles;
1106 bool discontinuity;
1107
1108 /*
1109 * Check that the counter value occurs after the provided
1110 * history reference and that the history doesn't cross a
1111 * clocksource change
1112 */
1113 if (!history_begin ||
1114 !cycle_between(history_begin->cycles,
1115 system_counterval.cycles, cycles) ||
1116 history_begin->cs_was_changed_seq != cs_was_changed_seq)
1117 return -EINVAL;
1118 partial_history_cycles = cycles - system_counterval.cycles;
1119 total_history_cycles = cycles - history_begin->cycles;
1120 discontinuity =
1121 history_begin->clock_was_set_seq != clock_was_set_seq;
1122
1123 ret = adjust_historical_crosststamp(history_begin,
1124 partial_history_cycles,
1125 total_history_cycles,
1126 discontinuity, xtstamp);
1127 if (ret)
1128 return ret;
1129 }
1130
1131 return 0;
1132}
1133EXPORT_SYMBOL_GPL(get_device_system_crosststamp);
898 1134
899/** 1135/**
900 * do_gettimeofday - Returns the time of day in a timeval 1136 * do_gettimeofday - Returns the time of day in a timeval