aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorPatrick Ohly <patrick.ohly@intel.com>2009-02-12 00:03:35 -0500
committerDavid S. Miller <davem@davemloft.net>2009-02-16 01:43:32 -0500
commita75244c3d519fcb490ca2bf3f123c98017f1e8d0 (patch)
treedee5b6a3589cfaae698a11297667e9e0c8b01ef5 /include
parenta038a353c3de4040d8445ec568acebdac144436f (diff)
timecompare: generic infrastructure to map between two time bases
Mapping from a struct timecounter to a time returned by functions like ktime_get_real() is implemented. This is sufficient to use this code in a network device driver which wants to support hardware time stamping and transformation of hardware time stamps to system time. The interface could have been made more versatile by not depending on a time counter, but this wasn't done to avoid writing glue code elsewhere. The method implemented here is the one used and analyzed under the name "assisted PTP" in the LCI PTP paper: http://www.linuxclustersinstitute.org/conferences/archive/2008/PDF/Ohly_92221.pdf Acked-by: John Stultz <johnstul@us.ibm.com> Signed-off-by: Patrick Ohly <patrick.ohly@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'include')
-rw-r--r--include/linux/timecompare.h125
1 files changed, 125 insertions, 0 deletions
diff --git a/include/linux/timecompare.h b/include/linux/timecompare.h
new file mode 100644
index 000000000000..546e2234e4b3
--- /dev/null
+++ b/include/linux/timecompare.h
@@ -0,0 +1,125 @@
1/*
2 * Utility code which helps transforming between two different time
3 * bases, called "source" and "target" time in this code.
4 *
5 * Source time has to be provided via the timecounter API while target
6 * time is accessed via a function callback whose prototype
7 * intentionally matches ktime_get() and ktime_get_real(). These
8 * interfaces where chosen like this so that the code serves its
9 * initial purpose without additional glue code.
10 *
11 * This purpose is synchronizing a hardware clock in a NIC with system
12 * time, in order to implement the Precision Time Protocol (PTP,
13 * IEEE1588) with more accurate hardware assisted time stamping. In
14 * that context only synchronization against system time (=
15 * ktime_get_real()) is currently needed. But this utility code might
16 * become useful in other situations, which is why it was written as
17 * general purpose utility code.
18 *
19 * The source timecounter is assumed to return monotonically
20 * increasing time (but this code does its best to compensate if that
21 * is not the case) whereas target time may jump.
22 *
23 * The target time corresponding to a source time is determined by
24 * reading target time, reading source time, reading target time
25 * again, then assuming that average target time corresponds to source
26 * time. In other words, the assumption is that reading the source
27 * time is slow and involves equal time for sending the request and
28 * receiving the reply, whereas reading target time is assumed to be
29 * fast.
30 *
31 * Copyright (C) 2009 Intel Corporation.
32 * Author: Patrick Ohly <patrick.ohly@intel.com>
33 *
34 * This program is free software; you can redistribute it and/or modify it
35 * under the terms and conditions of the GNU General Public License,
36 * version 2, as published by the Free Software Foundation.
37 *
38 * This program is distributed in the hope it will be useful, but WITHOUT
39 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
40 * FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for
41 * more details.
42 *
43 * You should have received a copy of the GNU General Public License along with
44 * this program; if not, write to the Free Software Foundation, Inc.,
45 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
46 */
47#ifndef _LINUX_TIMECOMPARE_H
48#define _LINUX_TIMECOMPARE_H
49
50#include <linux/clocksource.h>
51#include <linux/ktime.h>
52
53/**
54 * struct timecompare - stores state and configuration for the two clocks
55 *
56 * Initialize to zero, then set source/target/num_samples.
57 *
58 * Transformation between source time and target time is done with:
59 * target_time = source_time + offset +
60 * (source_time - last_update) * skew /
61 * TIMECOMPARE_SKEW_RESOLUTION
62 *
63 * @source: used to get source time stamps via timecounter_read()
64 * @target: function returning target time (for example, ktime_get
65 * for monotonic time, or ktime_get_real for wall clock)
66 * @num_samples: number of times that source time and target time are to
67 * be compared when determining their offset
68 * @offset: (target time - source time) at the time of the last update
69 * @skew: average (target time - source time) / delta source time *
70 * TIMECOMPARE_SKEW_RESOLUTION
71 * @last_update: last source time stamp when time offset was measured
72 */
73struct timecompare {
74 struct timecounter *source;
75 ktime_t (*target)(void);
76 int num_samples;
77
78 s64 offset;
79 s64 skew;
80 u64 last_update;
81};
82
83/**
84 * timecompare_transform - transform source time stamp into target time base
85 * @sync: context for time sync
86 * @source_tstamp: the result of timecounter_read() or
87 * timecounter_cyc2time()
88 */
89extern ktime_t timecompare_transform(struct timecompare *sync,
90 u64 source_tstamp);
91
92/**
93 * timecompare_offset - measure current (target time - source time) offset
94 * @sync: context for time sync
95 * @offset: average offset during sample period returned here
96 * @source_tstamp: average source time during sample period returned here
97 *
98 * Returns number of samples used. Might be zero (= no result) in the
99 * unlikely case that target time was monotonically decreasing for all
100 * samples (= broken).
101 */
102extern int timecompare_offset(struct timecompare *sync,
103 s64 *offset,
104 u64 *source_tstamp);
105
106extern void __timecompare_update(struct timecompare *sync,
107 u64 source_tstamp);
108
109/**
110 * timecompare_update - update offset and skew by measuring current offset
111 * @sync: context for time sync
112 * @source_tstamp: the result of timecounter_read() or
113 * timecounter_cyc2time(), pass zero to force update
114 *
115 * Updates are only done at most once per second.
116 */
117static inline void timecompare_update(struct timecompare *sync,
118 u64 source_tstamp)
119{
120 if (!source_tstamp ||
121 (s64)(source_tstamp - sync->last_update) >= NSEC_PER_SEC)
122 __timecompare_update(sync, source_tstamp);
123}
124
125#endif /* _LINUX_TIMECOMPARE_H */