aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristopher S. Hall <christopher.s.hall@intel.com>2016-02-22 06:15:23 -0500
committerJohn Stultz <john.stultz@linaro.org>2016-03-02 20:13:17 -0500
commit2c756feb18d9ec258dbb3a3d11c47e28820690d7 (patch)
tree3a11c7c1df31d7aeb42475f8793293075c7493c9
parent8006c24595cab106bcb9da12d35e32e14ff492df (diff)
time: Add history to cross timestamp interface supporting slower devices
Another representative use case of time sync and the correlated clocksource (in addition to PTP noted above) is PTP synchronized audio. In a streaming application, as an example, samples will be sent and/or received by multiple devices with a presentation time that is in terms of the PTP master clock. Synchronizing the audio output on these devices requires correlating the audio clock with the PTP master clock. The more precise this correlation is, the better the audio quality (i.e. out of sync audio sounds bad). From an application standpoint, to correlate the PTP master clock with the audio device clock, the system clock is used as a intermediate timebase. The transforms such an application would perform are: System Clock <-> Audio clock System Clock <-> Network Device Clock [<-> PTP Master Clock] Modern Intel platforms can perform a more accurate cross timestamp in hardware (ART,audio device clock). The audio driver requires ART->system time transforms -- the same as required for the network driver. These platforms offload audio processing (including cross-timestamps) to a DSP which to ensure uninterrupted audio processing, communicates and response to the host only once every millsecond. As a result is takes up to a millisecond for the DSP to receive a request, the request is processed by the DSP, the audio output hardware is polled for completion, the result is copied into shared memory, and the host is notified. All of these operation occur on a millisecond cadence. This transaction requires about 2 ms, but under heavier workloads it may take up to 4 ms. Adding a history allows these slow devices the option of providing an ART value outside of the current interval. In this case, the callback provided is an accessor function for the previously obtained counter value. If get_system_device_crosststamp() receives a counter value previous to cycle_last, it consults the history provided as an argument in history_ref and interpolates the realtime and monotonic raw system time using the provided counter value. If there are any clock discontinuities, e.g. from calling settimeofday(), the monotonic raw time is interpolated in the usual way, but the realtime clock time is adjusted by scaling the monotonic raw adjustment. When an accessor function is used a history argument *must* be provided. The history is initialized using ktime_get_snapshot() and must be called before the counter values are read. Cc: Prarit Bhargava <prarit@redhat.com> Cc: Richard Cochran <richardcochran@gmail.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Ingo Molnar <mingo@kernel.org> Cc: Andy Lutomirski <luto@amacapital.net> Cc: kevin.b.stanton@intel.com Cc: kevin.j.clarke@intel.com Cc: hpa@zytor.com Cc: jeffrey.t.kirsher@intel.com Cc: netdev@vger.kernel.org Reviewed-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Christopher S. Hall <christopher.s.hall@intel.com> [jstultz: Fixed up cycles_t/cycle_t type confusion] Signed-off-by: John Stultz <john.stultz@linaro.org>
-rw-r--r--include/linux/timekeeper_internal.h2
-rw-r--r--include/linux/timekeeping.h5
-rw-r--r--kernel/time/timekeeping.c171
3 files changed, 177 insertions, 1 deletions
diff --git a/include/linux/timekeeper_internal.h b/include/linux/timekeeper_internal.h
index 25247220b4b7..e88005459035 100644
--- a/include/linux/timekeeper_internal.h
+++ b/include/linux/timekeeper_internal.h
@@ -50,6 +50,7 @@ struct tk_read_base {
50 * @offs_tai: Offset clock monotonic -> clock tai 50 * @offs_tai: Offset clock monotonic -> clock tai
51 * @tai_offset: The current UTC to TAI offset in seconds 51 * @tai_offset: The current UTC to TAI offset in seconds
52 * @clock_was_set_seq: The sequence number of clock was set events 52 * @clock_was_set_seq: The sequence number of clock was set events
53 * @cs_was_changed_seq: The sequence number of clocksource change events
53 * @next_leap_ktime: CLOCK_MONOTONIC time value of a pending leap-second 54 * @next_leap_ktime: CLOCK_MONOTONIC time value of a pending leap-second
54 * @raw_time: Monotonic raw base time in timespec64 format 55 * @raw_time: Monotonic raw base time in timespec64 format
55 * @cycle_interval: Number of clock cycles in one NTP interval 56 * @cycle_interval: Number of clock cycles in one NTP interval
@@ -91,6 +92,7 @@ struct timekeeper {
91 ktime_t offs_tai; 92 ktime_t offs_tai;
92 s32 tai_offset; 93 s32 tai_offset;
93 unsigned int clock_was_set_seq; 94 unsigned int clock_was_set_seq;
95 u8 cs_was_changed_seq;
94 ktime_t next_leap_ktime; 96 ktime_t next_leap_ktime;
95 struct timespec64 raw_time; 97 struct timespec64 raw_time;
96 98
diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h
index 4a2ca65fc778..96f37bee3bc1 100644
--- a/include/linux/timekeeping.h
+++ b/include/linux/timekeeping.h
@@ -272,11 +272,15 @@ extern void ktime_get_raw_and_real_ts64(struct timespec64 *ts_raw,
272 * @cycles: Clocksource counter value to produce the system times 272 * @cycles: Clocksource counter value to produce the system times
273 * @real: Realtime system time 273 * @real: Realtime system time
274 * @raw: Monotonic raw system time 274 * @raw: Monotonic raw system time
275 * @clock_was_set_seq: The sequence number of clock was set events
276 * @cs_was_changed_seq: The sequence number of clocksource change events
275 */ 277 */
276struct system_time_snapshot { 278struct system_time_snapshot {
277 cycle_t cycles; 279 cycle_t cycles;
278 ktime_t real; 280 ktime_t real;
279 ktime_t raw; 281 ktime_t raw;
282 unsigned int clock_was_set_seq;
283 u8 cs_was_changed_seq;
280}; 284};
281 285
282/* 286/*
@@ -312,6 +316,7 @@ extern int get_device_system_crosststamp(
312 struct system_counterval_t *system_counterval, 316 struct system_counterval_t *system_counterval,
313 void *ctx), 317 void *ctx),
314 void *ctx, 318 void *ctx,
319 struct system_time_snapshot *history,
315 struct system_device_crosststamp *xtstamp); 320 struct system_device_crosststamp *xtstamp);
316 321
317/* 322/*
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index dba595cdb200..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;
@@ -894,6 +895,8 @@ void ktime_get_snapshot(struct system_time_snapshot *systime_snapshot)
894 seq = read_seqcount_begin(&tk_core.seq); 895 seq = read_seqcount_begin(&tk_core.seq);
895 896
896 now = tk->tkr_mono.read(tk->tkr_mono.clock); 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;
897 base_real = ktime_add(tk->tkr_mono.base, 900 base_real = ktime_add(tk->tkr_mono.base,
898 tk_core.timekeeper.offs_real); 901 tk_core.timekeeper.offs_real);
899 base_raw = tk->tkr_raw.base; 902 base_raw = tk->tkr_raw.base;
@@ -907,10 +910,123 @@ void ktime_get_snapshot(struct system_time_snapshot *systime_snapshot)
907} 910}
908EXPORT_SYMBOL_GPL(ktime_get_snapshot); 911EXPORT_SYMBOL_GPL(ktime_get_snapshot);
909 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}
930
931/**
932 * adjust_historical_crosststamp - adjust crosstimestamp previous to current interval
933 * @history: Snapshot representing start of history
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
939 *
940 * Helper function used by get_device_system_crosststamp() to correct the
941 * crosstimestamp corresponding to the start of the current interval to the
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.
947 */
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)
953{
954 struct timekeeper *tk = &tk_core.timekeeper;
955 u64 corr_raw, corr_real;
956 bool interp_forward;
957 int ret;
958
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
910/** 1023/**
911 * get_device_system_crosststamp - Synchronously capture system/device timestamp 1024 * get_device_system_crosststamp - Synchronously capture system/device timestamp
912 * @sync_devicetime: Callback to get simultaneous device time and 1025 * @get_time_fn: Callback to get simultaneous device time and
913 * system counter from the device driver 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
914 * @xtstamp: Receives simultaneously captured system and device time 1030 * @xtstamp: Receives simultaneously captured system and device time
915 * 1031 *
916 * Reads a timestamp from a device and correlates it to system time 1032 * Reads a timestamp from a device and correlates it to system time
@@ -920,13 +1036,18 @@ int get_device_system_crosststamp(int (*get_time_fn)
920 struct system_counterval_t *sys_counterval, 1036 struct system_counterval_t *sys_counterval,
921 void *ctx), 1037 void *ctx),
922 void *ctx, 1038 void *ctx,
1039 struct system_time_snapshot *history_begin,
923 struct system_device_crosststamp *xtstamp) 1040 struct system_device_crosststamp *xtstamp)
924{ 1041{
925 struct system_counterval_t system_counterval; 1042 struct system_counterval_t system_counterval;
926 struct timekeeper *tk = &tk_core.timekeeper; 1043 struct timekeeper *tk = &tk_core.timekeeper;
1044 cycle_t cycles, now, interval_start;
1045 unsigned int clock_was_set_seq;
927 ktime_t base_real, base_raw; 1046 ktime_t base_real, base_raw;
928 s64 nsec_real, nsec_raw; 1047 s64 nsec_real, nsec_raw;
1048 u8 cs_was_changed_seq;
929 unsigned long seq; 1049 unsigned long seq;
1050 bool do_interp;
930 int ret; 1051 int ret;
931 1052
932 do { 1053 do {
@@ -946,6 +1067,22 @@ int get_device_system_crosststamp(int (*get_time_fn)
946 */ 1067 */
947 if (tk->tkr_mono.clock != system_counterval.cs) 1068 if (tk->tkr_mono.clock != system_counterval.cs)
948 return -ENODEV; 1069 return -ENODEV;
1070 cycles = system_counterval.cycles;
1071
1072 /*
1073 * Check whether the system counter value provided by the
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 }
949 1086
950 base_real = ktime_add(tk->tkr_mono.base, 1087 base_real = ktime_add(tk->tkr_mono.base,
951 tk_core.timekeeper.offs_real); 1088 tk_core.timekeeper.offs_real);
@@ -959,6 +1096,38 @@ int get_device_system_crosststamp(int (*get_time_fn)
959 1096
960 xtstamp->sys_realtime = ktime_add_ns(base_real, nsec_real); 1097 xtstamp->sys_realtime = ktime_add_ns(base_real, nsec_real);
961 xtstamp->sys_monoraw = ktime_add_ns(base_raw, nsec_raw); 1098 xtstamp->sys_monoraw = ktime_add_ns(base_raw, nsec_raw);
1099
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
962 return 0; 1131 return 0;
963} 1132}
964EXPORT_SYMBOL_GPL(get_device_system_crosststamp); 1133EXPORT_SYMBOL_GPL(get_device_system_crosststamp);