From 2e455518717a5259baa327e659debfb551b84f87 Mon Sep 17 00:00:00 2001 From: "Christopher S. Hall" Date: Mon, 8 Aug 2016 07:19:20 -0700 Subject: [PATCH 1/2] gptp: Add support for HW supported cross timestamp Linux kernel version 4.6+ adds an additional cross timestamp ioctl for hardware that supports it. The cross-timestamp is exposed through the PTP driver interface. Intel PCH hardware reliably provides sub microsecond accuracy. Add error check for existing (legacy) PTP cross-timestamp ioctl() ifdef guards around code and capabilities check guarantee that any combination of header files and kernel version will compile and execute correctly defaulting to legacy (SW based) cross-timestamping --- daemons/gptp/linux/build/Makefile | 13 +++++ daemons/gptp/linux/src/linux_hal_generic.cpp | 51 +++++++++++++++----- daemons/gptp/linux/src/linux_hal_generic.hpp | 3 ++ 3 files changed, 56 insertions(+), 11 deletions(-) diff --git a/daemons/gptp/linux/build/Makefile b/daemons/gptp/linux/build/Makefile index 02d082f19f..21048c060c 100644 --- a/daemons/gptp/linux/build/Makefile +++ b/daemons/gptp/linux/build/Makefile @@ -33,6 +33,19 @@ ALTERNATE_LINUX_INCPATH=$(HOME)/header/include/ CFLAGS_G = -Wall -std=c++0x -g -I. -I../../common -I../src \ -I$(ALTERNATE_LINUX_INCPATH) +# Check to see if PTP cross-timestamping is supported in hardware/driver +# and, if so, add flag to compile in support + +PRECISE_TIME_TEST = "\#include \\n\ +\#ifdef PTP_SYS_OFFSET_PRECISE\\nint main(){return 0;}\\n\#endif" + +HAS_PRECISE_TIME = $(shell echo $(PRECISE_TIME_TEST) | gcc -xc - \ +-I$(ALTERNATE_LINUX_INCPATH) -o /dev/null > /dev/null 2>&1 ; echo $$?) + +ifeq ($(HAS_PRECISE_TIME),0) + CFLAGS_G += -DPTP_HW_CROSSTSTAMP +endif + CPPFLAGS_G = $(CFLAGS_G) -Wnon-virtual-dtor LDFLAGS_G = -lpthread -lrt diff --git a/daemons/gptp/linux/src/linux_hal_generic.cpp b/daemons/gptp/linux/src/linux_hal_generic.cpp index b1dc24857e..1dbcbc184d 100644 --- a/daemons/gptp/linux/src/linux_hal_generic.cpp +++ b/daemons/gptp/linux/src/linux_hal_generic.cpp @@ -222,7 +222,9 @@ bool LinuxTimestamperGeneric::HWTimestamper_init cross_stamp_good = false; int phc_index; char ptp_device[] = PTP_DEVICE; - +#ifdef PTP_HW_CROSSTSTAMP + struct ptp_clock_caps ptp_capability; +#endif _private = new LinuxTimestamperGenericPrivate; pthread_mutex_init( &_private->cross_stamp_lock, NULL ); @@ -244,6 +246,16 @@ bool LinuxTimestamperGeneric::HWTimestamper_init return false; } +#ifdef PTP_HW_CROSSTSTAMP + // Query PTP stack for availability of HW cross-timestamp + if( ioctl( phc_fd, PTP_CLOCK_GETCAPS, &ptp_capability ) == -1 ) + { + GPTP_LOG_ERROR( "Failed to query PTP clock capabilities" ); + return false; + } + precise_timestamp_enabled = ptp_capability.cross_timestamping; +#endif + if( !resetFrequencyAdjustment() ) { GPTP_LOG_ERROR( "Failed to reset (zero) frequency adjustment" ); return false; @@ -411,20 +423,39 @@ static inline Timestamp pctTimestamp( struct ptp_clock_time *t ) { return result; } +// Use HW cross-timestamp if available bool LinuxTimestamperGeneric::HWTimestamper_gettime ( Timestamp *system_time, Timestamp *device_time, uint32_t *local_clock, uint32_t *nominal_clock_rate ) { - unsigned i; - struct ptp_sys_offset offset; - struct ptp_clock_time *pct; - struct ptp_clock_time *system_time_l, *device_time_l; + if( phc_fd == -1 ) + return false; - int64_t interval = LLONG_MAX; +#ifdef PTP_HW_CROSSTSTAMP + if( precise_timestamp_enabled ) + { + struct ptp_sys_offset_precise offset; + memset( &offset, 0, sizeof(offset)); + if( ioctl( phc_fd, PTP_SYS_OFFSET_PRECISE, &offset ) == 0 ) + { + *device_time = pctTimestamp( &offset.device ); + *system_time = pctTimestamp( &offset.sys_realtime ); + + return true; + } + } +#endif + + { + unsigned i; + struct ptp_clock_time *pct; + struct ptp_clock_time *system_time_l, *device_time_l; + int64_t interval = LLONG_MAX; + struct ptp_sys_offset offset; - if( phc_fd != -1 ) { memset( &offset, 0, sizeof(offset)); offset.n_samples = PTP_MAX_SAMPLES; - ioctl( phc_fd, PTP_SYS_OFFSET, &offset ); + if( ioctl( phc_fd, PTP_SYS_OFFSET, &offset ) == -1 ) + return false; pct = &offset.ts[0]; for( i = 0; i < offset.n_samples; ++i ) { @@ -439,9 +470,7 @@ bool LinuxTimestamperGeneric::HWTimestamper_gettime *device_time = pctTimestamp( device_time_l ); *system_time = pctTimestamp( system_time_l ); - - return true; } - return false; + return true; } diff --git a/daemons/gptp/linux/src/linux_hal_generic.hpp b/daemons/gptp/linux/src/linux_hal_generic.hpp index 5b33dad510..abe1f2760c 100644 --- a/daemons/gptp/linux/src/linux_hal_generic.hpp +++ b/daemons/gptp/linux/src/linux_hal_generic.hpp @@ -62,6 +62,9 @@ class LinuxTimestamperGeneric : public LinuxTimestamper { bool cross_stamp_good; std::list rxTimestampList; LinuxNetworkInterfaceList iface_list; +#ifdef PTP_HW_CROSSTSTAMP + bool precise_timestamp_enabled; +#endif TicketingLock *net_lock; From f269814d08196cf02ec053b20d94cfdb11ad7f7d Mon Sep 17 00:00:00 2001 From: "Christopher S. Hall" Date: Thu, 25 Aug 2016 08:12:26 -0700 Subject: [PATCH 2/2] gptp: Fixup PHY delay parameter parsing for .ini file Move port initialization where PHY delay is provided *after* parsing of .ini file --- daemons/gptp/linux/src/daemon_cl.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/daemons/gptp/linux/src/daemon_cl.cpp b/daemons/gptp/linux/src/daemon_cl.cpp index 35282e9be4..b5b46a10b3 100644 --- a/daemons/gptp/linux/src/daemon_cl.cpp +++ b/daemons/gptp/linux/src/daemon_cl.cpp @@ -363,10 +363,6 @@ int main(int argc, char **argv) portInit.lock_factory = lock_factory; pPort = new IEEE1588Port(&portInit); - if (!pPort->init_port(phy_delay)) { - printf("failed to initialize port \n"); - return -1; - } if(use_config_file) { @@ -408,6 +404,11 @@ int main(int argc, char **argv) } + if (!pPort->init_port(phy_delay)) { + printf("failed to initialize port \n"); + return -1; + } + if( restoredataptr != NULL ) { if( !restorefailed ) { restorefailed = !pPort->restoreSerializedState( restoredataptr, &restoredatacount );