From: Christopher S. Hall <hidden> Date: 2016-01-13 19:18:42
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 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 (9):
Add cycles to nanoseconds translation (NEW)
Add driver cross timestamp interface for higher precision time
synchronization
Add correlated clocksource relating aliased auxiliary and system
clocks (NEW)
Always Running Timer (ART) correlated clocksource
Add timekeeping snapshot code capturing system time and counter (NEW)
Add history to cross timestamp interface supporting slower devices
Remove duplicated code in ktime_get_raw_and_real()
Add PTP_SYS_OFFSET_PRECISE for driver crosstimestamping
Adds hardware supported cross timestamp
Documentation/ptp/testptp.c | 6 +-
arch/x86/include/asm/cpufeature.h | 2 +-
arch/x86/include/asm/tsc.h | 2 +
arch/x86/kernel/tsc.c | 46 ++++++
drivers/net/ethernet/intel/Kconfig | 9 +
drivers/net/ethernet/intel/e1000e/defines.h | 5 +
drivers/net/ethernet/intel/e1000e/ptp.c | 88 ++++++++++
drivers/net/ethernet/intel/e1000e/regs.h | 4 +
drivers/ptp/ptp_chardev.c | 27 +++
include/linux/clocksource.h | 43 +++++
include/linux/pps_kernel.h | 17 +-
include/linux/ptp_clock_kernel.h | 8 +
include/linux/timekeeper_internal.h | 2 +
include/linux/timekeeping.h | 42 +++++
include/uapi/linux/ptp_clock.h | 13 +-
kernel/time/timekeeping.c | 247 +++++++++++++++++++++++++---
16 files changed, 521 insertions(+), 40 deletions(-)
--
2.1.4
From: Christopher S. Hall <hidden> Date: 2016-01-13 19:18:44
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>
---
kernel/time/timekeeping.c | 24 ++++++++++++++++++++----
1 file changed, 20 insertions(+), 4 deletions(-)
@@ -312,6 +310,24 @@ static inline s64 timekeeping_get_ns(struct tk_read_base *tkr)returnnsec+arch_gettimeoffset();}+staticinlines64timekeeping_get_ns(structtk_read_base*tkr)+{+cycle_tdelta;++delta=timekeeping_get_delta(tkr);+returntimekeeping_delta_to_ns(tkr,delta);+}++staticinlines64timekeeping_cycles_to_ns(structtk_read_base*tkr,+cycle_tcycles)+{+cycle_tdelta;++/* calculate the delta since the last update_wall_time */+delta=clocksource_delta(cycles,tkr->cycle_last,tkr->mask);+returntimekeeping_delta_to_ns(tkr,delta);+}+/***update_fast_timekeeper-UpdatethefastandNMIsafemonotonictimekeeper.*@tkr:Timekeepingreadoutbasefromwhichwetaketheupdate
From: Christopher S. Hall <hidden> Date: 2016-01-13 19:18:46
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>
---
include/linux/clocksource.h | 13 +++++++++++++
include/linux/timekeeping.h | 6 ++++++
kernel/time/timekeeping.c | 31 +++++++++++++++++++++++++++++++
3 files changed, 50 insertions(+)
From: Christopher S. Hall <hidden> Date: 2016-01-13 19:19:06
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>
---
drivers/net/ethernet/intel/Kconfig | 9 +++
drivers/net/ethernet/intel/e1000e/defines.h | 5 ++
drivers/net/ethernet/intel/e1000e/ptp.c | 88 +++++++++++++++++++++++++++++
drivers/net/ethernet/intel/e1000e/regs.h | 4 ++
4 files changed, 106 insertions(+)
@@ -236,6 +317,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-01-13 19:19:08
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.
Signed-off-by: Christopher S. Hall <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-01-13 19:20:58
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>
---
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-01-13 19:20:59
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]
Such audio applications make use of some existing ALSA library calls
that provide audio/system cross-timestamps (e.g.
snd_pcm_status_get_htstamp()). Previous driver implementations capture
these cross timestamps by reading the system clock (raw/mono/real) and
the device clock with greatest degree of simultaneity possible in
software.
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.
If update_wall_time() is called while waiting for a response within
get_device_system_crosststamp() (from previous patch), a retry is
attempted. This will occur if the cycle_interval (determined by
CONFIG_HZ and mult/shift values) cycles elapse.
Adding a history allows these slow devices the option of providing an
ART value outside of the retry loop. 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.
When the history is used to interpolate timestamp values, the realtime
clock time may be inaccurate to some degree. In general, the
longer the length of history the larger the interpolation error. If
there are discontinuities (large step changes) to the time, the error
can be very large.
Signed-off-by: Christopher S. Hall <redacted>
---
include/linux/clocksource.h | 4 ++
include/linux/timekeeper_internal.h | 2 +
include/linux/timekeeping.h | 3 +-
kernel/time/timekeeping.c | 130 ++++++++++++++++++++++++++++++++++++
4 files changed, 138 insertions(+), 1 deletion(-)
@@ -932,14 +935,83 @@ EXPORT_SYMBOL(ktime_get_raw_and_real_ts64);#endif /* CONFIG_NTP_PPS *//**+*adjust_historical_crosststamp-adjustcrosstimestampprevioustocurrentinterval+*@total_history_cycles:Totalhistorylengthincycles+*@partial_history_cycles:Cycleoffsetintohistory(fractionalpart)+*@total_history_monoraw:Totalhistorylengthinmonotonicrawns+*@total_history_realtime:Totalhistorylengthinrealtimens+*@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.+*/+staticvoidadjust_historical_crosststamp(cycle_ttotal_history_cycles,+cycle_tpartial_history_cycles,+ktime_ttotal_history_monoraw,+ktime_ttotal_history_realtime,+booldiscontinuity,+structsystem_device_crosststamp*ts)+{+structtimekeeper*tk=&tk_core.timekeeper;+u64corr_monoraw;+u64corr_realtime;++/*+*Scalethemonotonicrawtimedeltaby:+*partial_history_cycles/total_history_cycles+*/+corr_monoraw=(ktime_to_ns(total_history_monoraw)*+partial_history_cycles)/total_history_cycles;+/*+*Ifthereisadiscontinuityinthehistory,scalemonotonicraw+*correctionby:+*mult(real)/mult(raw)yieldingtherealtimecorrection+*Otherwise,calculatetherealtimecorrectionsimilartomonotonic+*rawcalculation+*/+if(discontinuity)+corr_realtime=(corr_monoraw*tk->tkr_mono.mult)/+tk->tkr_raw.mult;+else+corr_realtime=(ktime_to_ns(total_history_realtime)*+partial_history_cycles)/total_history_cycles;++/* Fixup monotonic raw and real time time values */+ts->sys_monoraw=ktime_sub_ns(ts->sys_monoraw,corr_monoraw);+ts->sys_realtime=ktime_sub_ns(ts->sys_realtime,corr_realtime);+}++/*+*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*systemcounterfromthedevicedriver+*@history_ref:Historicalreferencepointusedtointerpolatesystem+*timewhencounterprovidedbythedriverisbeforethecurrentinterval*@xtstamp:Receivessimultaneouslycapturedsystemanddevicetime**Readsatimestampfromadeviceandcorrelatesittosystemtime*/intget_device_system_crosststamp(structsync_device_time_cb*sync_devicetime,+structsystem_time_snapshot*history_ref,structsystem_device_crosststamp*xtstamp){structtimekeeper*tk=&tk_core.timekeeper;
@@ -949,6 +1021,12 @@ int get_device_system_crosststamp(struct sync_device_time_cb *sync_devicetime,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{
@@ -970,6 +1048,23 @@ int get_device_system_crosststamp(struct sync_device_time_cb *sync_devicetime,*/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)){+cs_was_changed_seq=tk->cs_was_changed_seq;+clock_was_set_seq=tk->clock_was_set_seq;+cycles=interval_start;+do_interp=true;+}else{+do_interp=false;+}+base_real=ktime_add(tk->tkr_mono.base,tk_core.timekeeper.offs_real);
@@ -983,6 +1078,41 @@ int get_device_system_crosststamp(struct sync_device_time_cb *sync_devicetime,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_ttotal_history_cycles,partial_history_cycles;+ktime_thistory_monoraw,history_realtime;+booldiscontinuity;++/*+*Checkthatthecountervalueoccursaftertheprovided+*historyreferenceandthatthehistorydoesn'tcrossa+*clocksourcechange+*/+if(!history_ref||+!cycle_between(history_ref->cycles,+system_counterval.cycles,interval_start)||+history_ref->cs_was_changed_seq!=cs_was_changed_seq)+return-EINVAL;+partial_history_cycles=cycles-system_counterval.cycles;+history_monoraw=ktime_sub(xtstamp->sys_monoraw,+history_ref->raw);+history_realtime=ktime_sub(xtstamp->sys_realtime,+history_ref->real);+total_history_cycles=cycles-history_ref->cycles;+discontinuity=+history_ref->clock_was_set_seq!=clock_was_set_seq;+adjust_historical_crosststamp(total_history_cycles,+partial_history_cycles,+history_monoraw,+history_realtime,discontinuity,+xtstamp);+}+return0;}EXPORT_SYMBOL_GPL(get_device_system_crosststamp);
From: Christopher S. Hall <hidden> Date: 2016-01-13 19:21:50
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>
---
arch/x86/include/asm/cpufeature.h | 2 +-
arch/x86/include/asm/tsc.h | 2 ++
arch/x86/kernel/tsc.c | 46 +++++++++++++++++++++++++++++++++++++++
3 files changed, 49 insertions(+), 1 deletion(-)
@@ -949,10 +949,36 @@ static struct notifier_block time_cpufreq_notifier_block = {.notifier_call=time_cpufreq_notifier};+#define ART_CPUID_LEAF (0x15)+/* The denominator will never be less that 2 */+#define ART_MIN_DENOMINATOR (2)++staticu32art_to_tsc_numerator;+staticu32art_to_tsc_denominator;++/*+*IfARTispresentdetectthenumerator:denominatortoconverttoTSC+*/+staticvoiddetect_art(void)+{+unsignedintunused[2];++if(boot_cpu_data.cpuid_level>=ART_CPUID_LEAF){+cpuid(ART_CPUID_LEAF,&art_to_tsc_denominator,+&art_to_tsc_numerator,unused,unused+1);++if(art_to_tsc_denominator>=ART_MIN_DENOMINATOR)+set_cpu_cap(&boot_cpu_data,X86_FEATURE_ART);+}+}+staticint__initcpufreq_tsc(void){if(!cpu_has_tsc)return0;++detect_art();+if(boot_cpu_has(X86_FEATURE_CONSTANT_TSC))return0;cpufreq_register_notifier(&time_cpufreq_notifier_block,
@@ -1071,6 +1097,24 @@ int unsynchronized_tsc(void)return0;}+/*+*ConvertARTtoTSCgivennumerator/denominatorfoundindetect_art()+*/+staticu64convert_art_to_tsc(structcorrelated_cs*cs,u64cycles)+{+u64tmp,res;++res=(cycles/art_to_tsc_denominator)*art_to_tsc_numerator;+tmp=(cycles%art_to_tsc_denominator)*art_to_tsc_numerator;+res+=tmp/art_to_tsc_denominator;++returnres;+}++structcorrelated_csart_timestamper={+.convert=convert_art_to_tsc,+};+EXPORT_SYMBOL(art_timestamper);staticvoidtsc_refine_calibration_work(structwork_struct*work);staticDECLARE_DELAYED_WORK(tsc_irqwork,tsc_refine_calibration_work);
From: Christopher S. Hall <hidden> Date: 2016-01-13 19:22:18
ACKNOWLEDGMENT: The original correlated clock source and cross
timestamp code was developed by Thomas Gleixner
[off-list ref]. It has changed considerably and any mistakes are
mine.
The timekeeping and clocksource code don't currently comprehend two
clocks that are aliases of one another. That is clocks that are
*exactly* related. The correlated_cs struct encapsulated this
relationship between a clocksource and its alias clock. Modern Intel
hardware provides an Always Running Timer (ART) which is exactly
related to TSC through a known frequency ratio. The ART is an example
of a correlated clocksource.
Signed-off-by: Christopher S. Hall <redacted>
---
include/linux/clocksource.h | 14 ++++++++++++++
1 file changed, 14 insertions(+)
From: Christopher S. Hall <hidden> Date: 2016-01-13 19:22:44
ACKNOWLEDGMENT: The original correlated clock source and 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.
Hardware cross timestamps are derived from simultaneously capturing
the device clock and the system clock. Applications use timestamps in
nanoseconds rather than clock ticks. The device driver can scale
device clock ticks to device time in nanoseconds, but cannot transform
system clock ticks. Only the kernel timekeeping code can do this. The
function get_device_system_crosstimestamp() allows device drivers to
return a cross timestamp with system time properly scaled to
nanoseconds.
The cross timestamps contain the realtime and monotonic raw clock
times. 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. Because of possible NTP/PTP frequency adjustments,
extrapolating a realtime clock time outside the current interval with
a potentially different scaling factor can result in a small amount of
error.
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>
---
include/linux/clocksource.h | 12 ++++++++++
include/linux/timekeeping.h | 35 ++++++++++++++++++++++++++++
kernel/time/timekeeping.c | 56 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 103 insertions(+)
From: Richard Cochran <richardcochran@gmail.com> Date: 2016-01-13 21:30:44
The series is a lot easier to follow now. However, the
sync_device_time_cb structure isn't serving any useful purpose:
+/*
+ * struct get_sync_device_time_cb - Provides method to capture device time
+ * synchronized with raw system counter value
+ * @get_time: Callback providing synchronized capture of device time
+ * and system counter. Returns 0 on success, < 0 on failure
+ * @ctx: Context provided to callback function
+ */
+struct sync_device_time_cb {
+ int (*get_time)(ktime_t *device_time,
+ struct system_counterval_t *system_counterval,
+ void *ctx);
+ void *ctx;
+};
Why not simply pass the function and context pointers as separate
arguments to get_device_system_crosststamp?
+/*
+ * Get cross timestamp between system clock and device clock
+ */
+extern int get_device_system_crosststamp(struct sync_device_time_cb *cb,
+ struct system_device_crosststamp *ts);
Here is how it looks at the call site (from the last patch):
It is really just busy work to assign the fields of 'sync_devicetime'.
If you don't foresee the need of storing the sync_device_time_cb
object, then I would just remove the structure altogether. Then the
call site will be cleaner, for example:
static int e1000e_phc_getcrosststamp(struct ptp_clock_info *ptp,
struct system_device_crosststamp *xtstamp)
{
struct e1000_adapter *adapter = container_of(ptp, struct e1000_adapter,
ptp_clock_info);
return get_device_system_crosststamp(e1000e_phc_get_syncdevicetime,
adapter, NULL, xtstamp);
}
Thanks,
Richard
From: Richard Cochran <richardcochran@gmail.com> Date: 2016-01-13 21:32:09
On Wed, Jan 13, 2016 at 04:12:28AM -0800, Christopher S. Hall wrote:
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.
Looks good to me.
Acked-by: Richard Cochran <richardcochran@gmail.com>
@@ -949,10 +949,36 @@ static struct notifier_block time_cpufreq_notifier_block = {.notifier_call=time_cpufreq_notifier};+#define ART_CPUID_LEAF (0x15)+/* The denominator will never be less that 2 */+#define ART_MIN_DENOMINATOR (2)++staticu32art_to_tsc_numerator;+staticu32art_to_tsc_denominator;
This is declared in a #ifdef CONFIG_CPU_FREQ
quoted hunk
@@ -1071,6 +1097,24 @@ int unsynchronized_tsc(void) return 0; }+/*+ * Convert ART to TSC given numerator/denominator found in detect_art()+ */+static u64 convert_art_to_tsc(struct correlated_cs *cs, u64 cycles)+{+ u64 tmp, res;++ res = (cycles / art_to_tsc_denominator) * art_to_tsc_numerator;+ tmp = (cycles % art_to_tsc_denominator) * art_to_tsc_numerator;+ res += tmp / art_to_tsc_denominator;
Then used outside of that block.
So this won't build if CPU_FREQ is disabled.
But don't bother to fix that, as I've already done so and I've got a
bunch of tweaks I'm making to the code (I figured I'd done enough
nit-picking reviews, and probably should just roll my sleeves up and
take a swing at how I'd prefer the code look - including Richard's
suggestions as well).
I'll send you my revisions here shortly and hopefully you can let me
know if anything goes too far and hopefully do some testing with it.
thanks
-john
From: John Stultz <hidden> Date: 2016-01-15 00:24:21
On Wed, Jan 13, 2016 at 4:12 AM, Christopher S. Hall
[off-list ref] wrote:
quoted hunk
ACKNOWLEDGMENT: The original correlated clock source and cross
timestamp code was developed by Thomas Gleixner
[off-list ref]. It has changed considerably and any mistakes are
mine.
The timekeeping and clocksource code don't currently comprehend two
clocks that are aliases of one another. That is clocks that are
*exactly* related. The correlated_cs struct encapsulated this
relationship between a clocksource and its alias clock. Modern Intel
hardware provides an Always Running Timer (ART) which is exactly
related to TSC through a known frequency ratio. The ART is an example
of a correlated clocksource.
Signed-off-by: Christopher S. Hall <redacted>
---
include/linux/clocksource.h | 14 ++++++++++++++
1 file changed, 14 insertions(+)
So.. In reworking your patch set, I've preserved this, but I'm still
not totally convinced. Its a generic structure, but not used by any
generic code and its only used by hardware specific implementations
(ie: the tsc and e1000e_hwts logic). It seems like this could be a
tsc.h specific structure w/o a real issue.
And really this doesn't seem to be a generic thing. The e1000e hwts is
always the ART based. Its not likely these sorts of cross hardware
timestamps are going to be completely abstract and interchangeable,
is it?
thanks
-john
From: John Stultz <hidden> Date: 2016-01-15 00:49:26
On Wed, Jan 13, 2016 at 4:12 AM, Christopher S. Hall
[off-list ref] wrote:
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.
So thanks again for sending this out. Instead of sending you a bunch
of nitpicky changes as I've done in the past, I figured I'd try to
more directly help out and try to rework some of the patches to be
more to my own liking.
I've pushed them here:
https://git.linaro.org/people/john.stultz/linux.git dev/xtimestamp
My main changes have been:
* Reordered the patches, putting all the timekeeping core changes
first, then the usage of those interfaces last.
* Implemented Richard's suggestion to drop one of the helper
structures that didn't provide much value
* Moved structures defined in clocksource.h but only used in
timekeeping.h to timekeeping.h
* Fixed a few build issues I caught (as well as some of the ones
kbuild bot found)
* Reworked the tsc logic to avoid 64bit divisions (which don't build
on 32bit systems)
I still have not:
* Done *any* testing at all with this. Please verify I didn't break anything. :)
* Fixed the 64bit div on 32bit systems build issue in
get_device_system_crosststamp()/adjust_historical_crosststamp()
* Done another review/edit pass on the commit messages, as they've
gotten a bit long (I know, I know.. "be verbose" I said!), but they
can probably be tweaked to be better and more contextual to the
patches.
Still on the fence:
* Probably should zap the correlated_cs structure or move it to tsc.h,
as mentioned in my other email
Anyway, I'll let you take a look at this and feel free to integrate
and adapt these ideas as you please into your patchset. Look forward
to your next revision!
thanks
-john
From: Thomas Gleixner <hidden> Date: 2016-01-15 10:30:37
On Thu, 14 Jan 2016, John Stultz wrote:
On Wed, Jan 13, 2016 at 4:12 AM, Christopher S. Hall
[off-list ref] wrote:
quoted
+/*
+ * struct correlated_cs - Descriptor for a clocksource correlated to another
+ * clocksource
+ * @related_cs: Pointer to the related timekeeping clocksource
+ * @convert: Conversion function to convert a timestamp from
+ * the correlated clocksource to cycles of the related
+ * timekeeping clocksource
+ */
+struct correlated_cs {
+ struct clocksource *related_cs;
+ cycle_t (*convert)(struct correlated_cs *cs,
+ cycle_t cycles);
+};
+
So.. In reworking your patch set, I've preserved this, but I'm still
not totally convinced. Its a generic structure, but not used by any
generic code and its only used by hardware specific implementations
(ie: the tsc and e1000e_hwts logic). It seems like this could be a
tsc.h specific structure w/o a real issue.
That correlated_cs is my fault. I invented that when I had that first stab on
the cross time stamp thing.
And really this doesn't seem to be a generic thing. The e1000e hwts is
always the ART based. Its not likely these sorts of cross hardware
timestamps are going to be completely abstract and interchangeable,
is it?
They might be in future. I guess other archs will provide similar means to
distribute an always on timer to PCIe for timestamping purposes.
So the question is whether we should expose that timestamp reference via a
generic mechanism, e.g. store it somewhere in the pci root complex or wherever
the appropriate point for it is.
Though for now, we certainly can make that x86 private and deal with it when
others come along.
Thanks,
tglx