diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2016-03-04 02:12:27 -0500 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2016-03-04 02:12:27 -0500 |
commit | 69365272332a5cbef778c97b2337b4f79c509293 (patch) | |
tree | c03bd4d13c12ae3be7282d4624cf25b23e1c2d1c /kernel/time | |
parent | 82e88ff1ea948d83125a8aaa7c9809f03ccc500f (diff) | |
parent | 01d7ada57ee9c735bd71fbe44ec0bcb70847afd4 (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.c | 286 |
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; | |||
298 | static inline u32 arch_gettimeoffset(void) { return 0; } | 299 | static inline u32 arch_gettimeoffset(void) { return 0; } |
299 | #endif | 300 | #endif |
300 | 301 | ||
302 | static 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 | |||
301 | static inline s64 timekeeping_get_ns(struct tk_read_base *tkr) | 314 | static 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; | 322 | static 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 | */ | ||
882 | void 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 | } | ||
911 | EXPORT_SYMBOL_GPL(ktime_get_snapshot); | ||
912 | |||
913 | /* Scale base by mult/div checking for overflow */ | ||
914 | static 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 | */ |
872 | void ktime_get_raw_and_real_ts64(struct timespec64 *ts_raw, struct timespec64 *ts_real) | 948 | static 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 | */ | ||
1014 | static 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 | */ | ||
1034 | int 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 | } | ||
895 | EXPORT_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 | } | ||
1133 | EXPORT_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 |