From: Christopher S. Hall <hidden> Date: 2016-02-22 18:22:32
Modern Intel hardware adds an Always Running Timer (ART) that allows the
network and audio device clocks to precisely cross timestamp the device
clock with the system clock. This allows a precise correlation of the
device time and system time.
This patchset adds interfaces to the timekeeping code allowing drivers
to translate ART time to system time.
Changelog:
Changes from v7 to v8:
* Fix comments in timekeeping.c
* Re-use older TSC feature, removing "invariant" TSC in ART
detection code
Changes from v6 to v7:
* Reorder several patches
* Removed correlated clocksource
* Fixed 32-bit compile issues
* Added multiplication overflow detection to history computation
* Added invariant tsc CPU feature - this is related to ART, but
is a separate feature
Changes from v5 to v6:
* Pulled supporting code for snapshotting, correlated
clocksource, and cycles to nanoseconds translation to separate
patches. Added patches are marked as NEW below. There is,
however, very little *actually* new code, just reorganized
code
* Renamed and moved clocksource change sequence to timekeeper
struct (out of tk_read_base)
* Renamed structs for system counter and synced device time
callback to system_counterval_t and sync_device_time_cb,
respectively
* Changed PTP cross-timestamp callback name to getcrosststamp
for consistency with the timekeeping code - corresponding
function name changes in e1000e driver
* Simplified PTP time calculations making use of ktime_to_* code
Changes from v4 to v5:
* Changes the history mechanism to interpolate system time using
a single historic system time pair (monotonic raw, realtime)
rather than implementing a precise history using shadow
timekeeper (see v4 changes). The advantage of this approach is
that the history can be arbitrarily long. This approach may
also be simpler in terms of coding. The major disadvantage is
that the realtime clock can be adjusted. When adjusted, the
realtime clock time (when interpolating from history) is
always approximate. In general, the longer the interpolation
period the larger the potential error. There isn't any error
interpolating the monotonic raw clock time.
* This patchset also addresses objections to the previous
patchsets overly complex correlated timestamp structure. This
patchset splits that structure into several smaller
structures. The correlated timestamp interface is renamed
cross timestamp to avoid any confusion with the correlated
clocksource.
* The correlated clocksource is separated from the cross
timestamp mechanism.
* Add monotonic raw to the PTP user interface
* Add e1000e driver configuration option that wraps Intel PCH
specific code
Changes v3 to v4:
* Adds a history mechanism to accomodate slower devices. In this
case the response time for timestamp reads to the Intel DSP
are too slow to be accomodated by the original correlated time
mechanism. The history mechanism turns shadow timekeeper into
an array where the history is stored.
Christopher S. Hall (8):
time: Add cycles to nanoseconds translation
time: Add timekeeping snapshot code capturing system time and counter
time: Remove duplicated code in ktime_get_raw_and_real()
time: Add driver cross timestamp interface for higher precision time
synchronization
time: Add history to cross timestamp interface supporting slower
devices
x86: tsc: Always Running Timer (ART) correlated clocksource
ptp: Add PTP_SYS_OFFSET_PRECISE for driver crosstimestamping
net: e1000e: Adds hardware supported cross timestamp on e1000e nic
Documentation/ptp/testptp.c | 6 +-
arch/x86/include/asm/cpufeature.h | 2 +-
arch/x86/include/asm/tsc.h | 2 +
arch/x86/kernel/tsc.c | 49 +++++
drivers/net/ethernet/intel/Kconfig | 9 +
drivers/net/ethernet/intel/e1000e/defines.h | 5 +
drivers/net/ethernet/intel/e1000e/ptp.c | 85 ++++++++
drivers/net/ethernet/intel/e1000e/regs.h | 4 +
drivers/ptp/ptp_chardev.c | 27 +++
include/linux/pps_kernel.h | 17 +-
include/linux/ptp_clock_kernel.h | 8 +
include/linux/timekeeper_internal.h | 2 +
include/linux/timekeeping.h | 58 ++++++
include/uapi/linux/ptp_clock.h | 13 +-
kernel/time/timekeeping.c | 290 +++++++++++++++++++++++++---
15 files changed, 537 insertions(+), 40 deletions(-)
--
2.1.4
From: Christopher S. Hall <hidden> Date: 2016-02-22 18:22:28
The timekeeping code does not currently provide a way to translate
externally provided clocksource cycles to system time. The cycle count
is always provided by the result clocksource read() method internal to
the timekeeping code. The added function timekeeping_cycles_to_ns()
calculated a nanosecond value from a cycle count that can be added to
tk_read_base.base value yielding the current system time. This allows
clocksource cycle values external to the timekeeping code to provide a
cycle count that can be transformed to system time.
Signed-off-by: Christopher S. Hall <redacted>
Signed-off-by: John Stultz <redacted>
---
kernel/time/timekeeping.c | 25 +++++++++++++++++++++----
1 file changed, 21 insertions(+), 4 deletions(-)
@@ -298,17 +298,34 @@ u32 (*arch_gettimeoffset)(void) = default_arch_gettimeoffset;staticinlineu32arch_gettimeoffset(void){return0;}#endif+staticinlines64timekeeping_delta_to_ns(structtk_read_base*tkr,+cycle_tdelta)+{+s64nsec;++nsec=delta*tkr->mult+tkr->xtime_nsec;+nsec>>=tkr->shift;++/* If arch requires, add in get_arch_timeoffset() */+returnnsec+arch_gettimeoffset();+}+staticinlines64timekeeping_get_ns(structtk_read_base*tkr){cycle_tdelta;-s64nsec;delta=timekeeping_get_delta(tkr);+returntimekeeping_delta_to_ns(tkr,delta);+}-nsec=(delta*tkr->mult+tkr->xtime_nsec)>>tkr->shift;+staticinlines64timekeeping_cycles_to_ns(structtk_read_base*tkr,+cycle_tcycles)+{+cycle_tdelta;-/* If arch requires, add in get_arch_timeoffset() */-returnnsec+arch_gettimeoffset();+/* calculate the delta since the last update_wall_time */+delta=clocksource_delta(cycles,tkr->cycle_last,tkr->mask);+returntimekeeping_delta_to_ns(tkr,delta);}/**
From: Christopher S. Hall <hidden> Date: 2016-02-22 18:22:30
In the current timekeeping code there isn't any interface to
atomically capture the current relationship between the system counter
and system time. ktime_get_snapshot() returns this triple (counter,
monotonic raw, realtime) in the system_time_snapshot struct.
Signed-off-by: Christopher S. Hall <redacted>
[jstultz: Moved structure definitions around to clean things up]
Signed-off-by: John Stultz <redacted>
---
include/linux/timekeeping.h | 18 ++++++++++++++++++
kernel/time/timekeeping.c | 30 ++++++++++++++++++++++++++++++
2 files changed, 48 insertions(+)
From: Christopher S. Hall <hidden> Date: 2016-02-22 18:22:31
The code in ktime_get_snapshot() is a superset of the code in
ktime_get_raw_and_real() code. Further, ktime_get_raw_and_real() is
called only by the PPS code, pps_get_ts(). Consolidate the
pps_get_ts() code into a single function calling ktime_get_snapshot()
and eliminate ktime_get_raw_and_real(). A side effect of this is that
the raw and real results of pps_get_ts() correspond to exactly the
same clock cycle. Previously these values represented separate reads
of the system clock.
Signed-off-by: Christopher S. Hall <redacted>
Signed-off-by: John Stultz <redacted>
---
include/linux/pps_kernel.h | 17 ++++++-----------
kernel/time/timekeeping.c | 40 ++--------------------------------------
2 files changed, 8 insertions(+), 49 deletions(-)
From: Christopher S. Hall <hidden> Date: 2016-02-22 18:23:27
Modern Intel systems supports cross timestamping of the network device
clock and Always Running Timer (ART) in hardware. This allows the
device time and system time to be precisely correlated. The timestamp
pair is returned through e1000e_phc_get_syncdevicetime() used by
get_system_device_crosststamp(). The hardware cross-timestamp result
is made available to applications through the PTP_SYS_OFFSET_PRECISE
ioctl which calls e1000e_phc_getcrosststamp().
Signed-off-by: Christopher S. Hall <redacted>
[jstultz: Reworked to use new interface, commit message tweaks]
Signed-off-by: John Stultz <redacted>
---
drivers/net/ethernet/intel/Kconfig | 9 +++
drivers/net/ethernet/intel/e1000e/defines.h | 5 ++
drivers/net/ethernet/intel/e1000e/ptp.c | 85 +++++++++++++++++++++++++++++
drivers/net/ethernet/intel/e1000e/regs.h | 4 ++
4 files changed, 103 insertions(+)
@@ -236,6 +314,13 @@ void e1000e_ptp_init(struct e1000_adapter *adapter)break;}+#ifdef CONFIG_E1000E_HWTS+/* CPU must have ART and GBe must be from Sunrise Point or greater */+if(hw->mac.type>=e1000_pch_spt&&boot_cpu_has(X86_FEATURE_ART))+adapter->ptp_clock_info.getcrosststamp=+e1000e_phc_getcrosststamp;+#endif/*CONFIG_E1000E_HWTS*/+INIT_DELAYED_WORK(&adapter->systim_overflow_work,e1000e_systim_overflow_work);
From: Christopher S. Hall <hidden> Date: 2016-02-22 18:23:53
Currently, network /system cross-timestamping is performed in the
PTP_SYS_OFFSET ioctl. The PTP clock driver reads gettimeofday() and
the gettime64() callback provided by the driver. The cross-timestamp
is best effort where the latency between the capture of system time
(getnstimeofday()) and the device time (driver callback) may be
significant.
The getcrosststamp() callback and corresponding PTP_SYS_OFFSET_PRECISE
ioctl allows the driver to perform this device/system correlation when
for example cross timestamp hardware is available. Modern Intel
systems can do this for onboard Ethernet controllers using the ART
counter. There is virtually zero latency between captures of the ART
and network device clock.
The capabilities ioctl (PTP_CLOCK_GETCAPS), is augmented allowing
applications to query whether or not drivers implement the
getcrosststamp callback, providing more precise cross timestamping.
Acked-by: Richard Cochran <richardcochran@gmail.com>
Signed-off-by: Christopher S. Hall <redacted>
[jstultz: Commit subject tweaks]
Signed-off-by: John Stultz <redacted>
---
Documentation/ptp/testptp.c | 6 ++++--
drivers/ptp/ptp_chardev.c | 27 +++++++++++++++++++++++++++
include/linux/ptp_clock_kernel.h | 8 ++++++++
include/uapi/linux/ptp_clock.h | 13 ++++++++++++-
4 files changed, 51 insertions(+), 3 deletions(-)
@@ -120,11 +121,13 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg)structptp_clock_capscaps;structptp_clock_requestreq;structptp_sys_offset*sysoff=NULL;+structptp_sys_offset_preciseprecise_offset;structptp_pin_descpd;structptp_clock*ptp=container_of(pc,structptp_clock,clock);structptp_clock_info*ops=ptp->info;structptp_clock_time*pct;structtimespec64ts;+structsystem_device_crosststampxtstamp;intenable,err=0;unsignedinti,pin_index;
@@ -138,6 +141,7 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg)caps.n_per_out=ptp->info->n_per_out;caps.pps=ptp->info->pps;caps.n_pins=ptp->info->n_pins;+caps.cross_timestamping=ptp->info->getcrosststamp!=NULL;if(copy_to_user((void__user*)arg,&caps,sizeof(caps)))err=-EFAULT;break;
@@ -180,6 +184,29 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg)err=ops->enable(ops,&req,enable);break;+casePTP_SYS_OFFSET_PRECISE:+if(!ptp->info->getcrosststamp){+err=-EOPNOTSUPP;+break;+}+err=ptp->info->getcrosststamp(ptp->info,&xtstamp);+if(err)+break;++ts=ktime_to_timespec64(xtstamp.device);+precise_offset.device.sec=ts.tv_sec;+precise_offset.device.nsec=ts.tv_nsec;+ts=ktime_to_timespec64(xtstamp.sys_realtime);+precise_offset.sys_realtime.sec=ts.tv_sec;+precise_offset.sys_realtime.nsec=ts.tv_nsec;+ts=ktime_to_timespec64(xtstamp.sys_monoraw);+precise_offset.sys_monoraw.sec=ts.tv_sec;+precise_offset.sys_monoraw.nsec=ts.tv_nsec;+if(copy_to_user((void__user*)arg,&precise_offset,+sizeof(precise_offset)))+err=-EFAULT;+break;+casePTP_SYS_OFFSET:sysoff=kmalloc(sizeof(*sysoff),GFP_KERNEL);if(!sysoff){
@@ -51,7 +51,9 @@ struct ptp_clock_caps {intn_per_out;/* Number of programmable periodic signals. */intpps;/* Whether the clock supports a PPS callback. */intn_pins;/* Number of input/output pins. */-intrsv[14];/* Reserved for future use. */+/* Whether the clock supports precise system-device cross timestamps */+intcross_timestamping;+intrsv[13];/* Reserved for future use. */};structptp_extts_request{
From: Christopher S. Hall <hidden> Date: 2016-02-22 18:24:33
On modern Intel systems TSC is derived from the new Always Running Timer
(ART). ART can be captured simultaneous to the capture of
audio and network device clocks, allowing a correlation between timebases
to be constructed. Upon capture, the driver converts the captured ART
value to the appropriate system clock using the correlated clocksource
mechanism.
On systems that support ART a new CPUID leaf (0x15) returns parameters
“m” and “n” such that:
TSC_value = (ART_value * m) / n + k [n >= 2]
[k is an offset that can adjusted by a privileged agent. The
IA32_TSC_ADJUST MSR is an example of an interface to adjust k.
See 17.14.4 of the Intel SDM for more details]
Signed-off-by: Christopher S. Hall <redacted>
[jstultz: Tweaked to fix build issue, also reworked math for
64bit division on 32bit systems]
Signed-off-by: John Stultz <redacted>
---
arch/x86/include/asm/cpufeature.h | 2 +-
arch/x86/include/asm/tsc.h | 2 ++
arch/x86/kernel/tsc.c | 49 +++++++++++++++++++++++++++++++++++++++
3 files changed, 52 insertions(+), 1 deletion(-)
From: Christopher S. Hall <hidden> Date: 2016-02-22 18:24:34
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.
Signed-off-by: Christopher S. Hall <redacted>
Signed-off-by: John Stultz <redacted>
---
include/linux/timekeeper_internal.h | 2 +
include/linux/timekeeping.h | 5 ++
kernel/time/timekeeping.c | 173 +++++++++++++++++++++++++++++++++++-
3 files changed, 179 insertions(+), 1 deletion(-)
@@ -907,10 +910,123 @@ void ktime_get_snapshot(struct system_time_snapshot *systime_snapshot)}EXPORT_SYMBOL_GPL(ktime_get_snapshot);+/* Scale base by mult/div checking for overflow */+staticintscale64_check_overflow(u64mult,u64div,u64*base)+{+u64tmp,rem;++tmp=div64_u64_rem(*base,div,&rem);++if(((int)sizeof(u64)*8-fls64(mult)<fls64(tmp))||+((int)sizeof(u64)*8-fls64(mult)<fls64(rem)))+return-EOVERFLOW;+tmp*=mult;+rem*=mult;++do_div(rem,div);+*base=tmp+rem;+return0;+}++/**+*adjust_historical_crosststamp-adjustcrosstimestampprevioustocurrentinterval+*@history:Snapshotrepresentingstartofhistory+*@partial_history_cycles:Cycleoffsetintohistory(fractionalpart)+*@total_history_cycles:Totalhistorylengthincycles+*@discontinuity:Trueindicatesclockwassetonhistoryperiod+*@ts:Crosstimestampthatshouldbeadjustedusing+*partial/totalratio+*+*Helperfunctionusedbyget_device_system_crosststamp()tocorrectthe+*crosstimestampcorrespondingtothestartofthecurrentintervaltothe+*systemcountervalue(timestamppoint)providedbythedriver.The+*total_history_*quantitiesarethetotalhistorystartingattheprovided+*referencepointandendingatthestartofthecurrentinterval.Thecycle+*countbetweenthedrivertimestamppointandthestartofthecurrent+*intervalispartial_history_cycles.+*/+staticintadjust_historical_crosststamp(structsystem_time_snapshot*history,+cycle_tpartial_history_cycles,+cycle_ttotal_history_cycles,+booldiscontinuity,+structsystem_device_crosststamp*ts)+{+structtimekeeper*tk=&tk_core.timekeeper;+boolinterp_forward;+u64corr_raw,corr_real;+intret;++if(total_history_cycles==0||partial_history_cycles==0)+return0;++/* Interpolate shortest distance from beginning or end of history */+interp_forward=partial_history_cycles>total_history_cycles/2?+true:false;+partial_history_cycles=interp_forward?+total_history_cycles-partial_history_cycles:+partial_history_cycles;++/*+*Scalethemonotonicrawtimedeltaby:+*partial_history_cycles/total_history_cycles+*/+corr_raw=(u64)ktime_to_ns(+ktime_sub(ts->sys_monoraw,history->raw));+ret=scale64_check_overflow(partial_history_cycles,+total_history_cycles,&corr_raw);+if(ret)+returnret;++/*+*Ifthereisadiscontinuityinthehistory,scalemonotonicraw+*correctionby:+*mult(real)/mult(raw)yieldingtherealtimecorrection+*Otherwise,calculatetherealtimecorrectionsimilartomonotonic+*rawcalculation+*/+if(discontinuity){+corr_real=mul_u64_u32_div+(corr_raw,tk->tkr_mono.mult,tk->tkr_raw.mult);+}else{+corr_real=(u64)ktime_to_ns(+ktime_sub(ts->sys_realtime,history->real));+ret=scale64_check_overflow(partial_history_cycles,+total_history_cycles,&corr_real);+if(ret)+returnret;+}++/* Fixup monotonic raw and real time time values */+if(interp_forward){+ts->sys_monoraw=ktime_add_ns(history->raw,corr_raw);+ts->sys_realtime=ktime_add_ns(history->real,corr_real);+}else{+ts->sys_monoraw=ktime_sub_ns(ts->sys_monoraw,corr_raw);+ts->sys_realtime=ktime_sub_ns(ts->sys_realtime,corr_real);+}++return0;+}++/*+*cycle_between-trueiftestoccurschronologicallybetweenbeforeandafter+*/+staticboolcycle_between(cycles_tbefore,cycles_ttest,cycles_tafter)+{+if(test>before&&test<after)+returntrue;+if(test<before&&before>after)+returntrue;+returnfalse;+}+/***get_device_system_crosststamp-Synchronouslycapturesystem/devicetimestamp-*@sync_devicetime:Callbacktogetsimultaneousdevicetimeand+*@get_time_fn:Callbacktogetsimultaneousdevicetimeand*systemcounterfromthedevicedriver+*@ctx:Contextpassedtoget_time_fn()+*@history_begin:Historicalreferencepointusedtointerpolatesystem+*timewhencounterprovidedbythedriverisbeforethecurrentinterval*@xtstamp:Receivessimultaneouslycapturedsystemanddevicetime**Readsatimestampfromadeviceandcorrelatesittosystemtime
@@ -920,6 +1036,7 @@ int get_device_system_crosststamp(int (*get_time_fn)structsystem_counterval_t*sys_counterval,void*ctx),void*ctx,+structsystem_time_snapshot*history_begin,structsystem_device_crosststamp*xtstamp){structtimekeeper*tk=&tk_core.timekeeper;
@@ -929,6 +1046,12 @@ int get_device_system_crosststamp(int (*get_time_fn)ktime_tbase_real;s64nsec_raw;s64nsec_real;+cycles_tcycles;+cycle_tnow;+cycle_tinterval_start;+unsignedintclock_was_set_seq;+u8cs_was_changed_seq;+booldo_interp;intret;do{
@@ -948,6 +1071,22 @@ int get_device_system_crosststamp(int (*get_time_fn)*/if(tk->tkr_mono.clock!=system_counterval.cs)return-ENODEV;+cycles=system_counterval.cycles;++/*+*Checkwhetherthesystemcountervalueprovidedbythe+*devicedriverisonthecurrenttimekeepinginterval.+*/+now=tk->tkr_mono.read(tk->tkr_mono.clock);+interval_start=tk->tkr_mono.cycle_last;+if(!cycle_between(interval_start,cycles,now)){+clock_was_set_seq=tk->clock_was_set_seq;+cs_was_changed_seq=tk->cs_was_changed_seq;+cycles=interval_start;+do_interp=true;+}else{+do_interp=false;+}base_real=ktime_add(tk->tkr_mono.base,tk_core.timekeeper.offs_real);
@@ -961,6 +1100,38 @@ int get_device_system_crosststamp(int (*get_time_fn)xtstamp->sys_realtime=ktime_add_ns(base_real,nsec_real);xtstamp->sys_monoraw=ktime_add_ns(base_raw,nsec_raw);++/*+*Interpolateifnecessary,adjustingbackfromthestartofthe+*currentinterval+*/+if(do_interp){+cycle_tpartial_history_cycles,total_history_cycles;+booldiscontinuity;++/*+*Checkthatthecountervalueoccursaftertheprovided+*historyreferenceandthatthehistorydoesn'tcrossa+*clocksourcechange+*/+if(!history_begin||+!cycle_between(history_begin->cycles,+system_counterval.cycles,cycles)||+history_begin->cs_was_changed_seq!=cs_was_changed_seq)+return-EINVAL;+partial_history_cycles=cycles-system_counterval.cycles;+total_history_cycles=cycles-history_begin->cycles;+discontinuity=+history_begin->clock_was_set_seq!=clock_was_set_seq;++ret=adjust_historical_crosststamp(history_begin,+partial_history_cycles,+total_history_cycles,+discontinuity,xtstamp);+if(ret)+returnret;+}+return0;}EXPORT_SYMBOL_GPL(get_device_system_crosststamp);
From: Christopher S. Hall <hidden> Date: 2016-02-22 18:25:16
ACKNOWLEDGMENT: cross timestamp code was developed by Thomas Gleixner
[off-list ref]. It has changed considerably and any mistakes are
mine.
The precision with which events on multiple networked systems can be
synchronized using, as an example, PTP (IEEE 1588, 802.1AS) is limited
by the precision of the cross timestamps between the system clock and
the device (timestamp) clock. Precision here is the degree of
simultaneity when capturing the cross timestamp.
Currently the PTP cross timestamp is captured in software using the
PTP device driver ioctl PTP_SYS_OFFSET. Reads of the device clock are
interleaved with reads of the realtime clock. At best, the precision
of this cross timestamp is on the order of several microseconds due to
software latencies. Sub-microsecond precision is required for
industrial control and some media applications. To achieve this level
of precision hardware supported cross timestamping is needed.
The function get_device_system_crosstimestamp() allows device drivers
to return a cross timestamp with system time properly scaled to
nanoseconds. The realtime value is needed to discipline that clock
using PTP and the monotonic raw value is used for applications that
don't require a "real" time, but need an unadjusted clock time. The
get_device_system_crosstimestamp() code calls back into the driver to
ensure that the system counter is within the current timekeeping
update interval.
Modern Intel hardware provides an Always Running Timer (ART) which is
exactly related to TSC through a known frequency ratio. The ART is
routed to devices on the system and is used to precisely and
simultaneously capture the device clock with the ART.
Signed-off-by: Christopher S. Hall <redacted>
[jstultz: Reworked to remove extra structures and simplify calling]
Signed-off-by: John Stultz <redacted>
---
include/linux/timekeeping.h | 35 +++++++++++++++++++++++++++
kernel/time/timekeeping.c | 58 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 93 insertions(+)
From: Thomas Gleixner <hidden> Date: 2016-02-24 10:50:42
On Mon, 22 Feb 2016, Christopher S. Hall wrote:
The timekeeping code does not currently provide a way to translate
externally provided clocksource cycles to system time. The cycle count
is always provided by the result clocksource read() method internal to
the timekeeping code. The added function timekeeping_cycles_to_ns()
calculated a nanosecond value from a cycle count that can be added to
tk_read_base.base value yielding the current system time. This allows
clocksource cycle values external to the timekeeping code to provide a
cycle count that can be transformed to system time.
From: Thomas Gleixner <hidden> Date: 2016-02-24 10:52:42
On Mon, 22 Feb 2016, Christopher S. Hall wrote:
In the current timekeeping code there isn't any interface to
atomically capture the current relationship between the system counter
and system time. ktime_get_snapshot() returns this triple (counter,
monotonic raw, realtime) in the system_time_snapshot struct.
+/**
+ * ktime_get_snapshot - snapshots the realtime/monotonic raw clocks with counter
+ * @systime_snapshot: pointer to struct receiving the system time snapshot
+ */
+void ktime_get_snapshot(struct system_time_snapshot *systime_snapshot)
+{
+ struct timekeeper *tk = &tk_core.timekeeper;
+ unsigned long seq;
+ ktime_t base_raw;
+ ktime_t base_real;
+ s64 nsec_raw;
+ s64 nsec_real;
I'd prefer to have the variables of the same type in a single line. Other than
that:
Reviewed-by: Thomas Gleixner <redacted>
Single lines for same and desceding length ordered, which makes it simpler to
parse, please.
Other than that: Reviewed-by: Thomas Gleixner [off-list ref]
From: Thomas Gleixner <hidden> Date: 2016-02-24 11:02:04
On Mon, 22 Feb 2016, Christopher S. Hall wrote:
On modern Intel systems TSC is derived from the new Always Running Timer
(ART). ART can be captured simultaneous to the capture of
audio and network device clocks, allowing a correlation between timebases
to be constructed. Upon capture, the driver converts the captured ART
value to the appropriate system clock using the correlated clocksource
mechanism.
On systems that support ART a new CPUID leaf (0x15) returns parameters
“m” and “n” such that:
TSC_value = (ART_value * m) / n + k [n >= 2]
[k is an offset that can adjusted by a privileged agent. The
IA32_TSC_ADJUST MSR is an example of an interface to adjust k.
See 17.14.4 of the Intel SDM for more details]
Signed-off-by: Christopher S. Hall <redacted>
[jstultz: Tweaked to fix build issue, also reworked math for
64bit division on 32bit systems]
Signed-off-by: John Stultz <redacted>
From: Jeff Kirsher <hidden> Date: 2016-02-24 20:22:46
On Mon, 2016-02-22 at 03:15 -0800, Christopher S. Hall wrote:
Modern Intel systems supports cross timestamping of the network
device
clock and Always Running Timer (ART) in hardware. This allows the
device time and system time to be precisely correlated. The timestamp
pair is returned through e1000e_phc_get_syncdevicetime() used by
get_system_device_crosststamp(). The hardware cross-timestamp result
is made available to applications through the PTP_SYS_OFFSET_PRECISE
ioctl which calls e1000e_phc_getcrosststamp().
Signed-off-by: Christopher S. Hall <redacted>
[jstultz: Reworked to use new interface, commit message tweaks]
Signed-off-by: John Stultz <redacted>
---
drivers/net/ethernet/intel/Kconfig | 9 +++
drivers/net/ethernet/intel/e1000e/defines.h | 5 ++
drivers/net/ethernet/intel/e1000e/ptp.c | 85
+++++++++++++++++++++++++++++
drivers/net/ethernet/intel/e1000e/regs.h | 4 ++
4 files changed, 103 insertions(+)
I just noticed this train-wreck: cycles_t and cycle_t are obnoxiously
different types. (One is an int on some arches and the other is a
u64).
You very much want to use cycle_t here. And I think that goes for the
introduced cycle_between() function.
So I'm fixing that up as well in this patch, but there's a few other
spots in this series too.
Sigh. Going to have to find some time to go through and try to zap
cycles_t in the kernel because having both is just asking for
trouble. :P
thanks
-john