diff --git a/include/netutils/ptpd.h b/include/netutils/ptpd.h index ae397d57c..f418e6892 100644 --- a/include/netutils/ptpd.h +++ b/include/netutils/ptpd.h @@ -53,6 +53,7 @@ struct ptpd_config_s enum ptp_delay_mechanism_e delay_mechanism; bool bmca; sa_family_t af; + int32_t ingress_latency_ns; /* Hardware RX timestamp latency (ns) */ }; /* PTPD status information structure */ diff --git a/netutils/ptpd/Kconfig b/netutils/ptpd/Kconfig index 0bd2389fd..fc26e821b 100644 --- a/netutils/ptpd/Kconfig +++ b/netutils/ptpd/Kconfig @@ -219,4 +219,24 @@ config NETUTILS_PTPD_STATUSFILE memory, making it work across all build modes (Flat, Protected, Kernel). Written atomically via temp + rename. +config NETUTILS_PTPD_INGRESS_LATENCY_NS + int "PTP hardware receive timestamp latency (ns)" + default 0 + range -1000000 1000000 + ---help--- + Fixed delay, in nanoseconds, between a frame reaching the wire + reference plane and the moment the MAC latches its hardware + receive timestamp. This is the ingressLatency port parameter of + IEEE 1588: the PHY and the MAC clock-domain crossing make the + timestamp point lag the true arrival of the frame. + + The latency is subtracted from every hardware receive timestamp, + so a positive value moves the timestamps earlier. It has no + effect with software timestamping. It can be overridden at + run time with the -I option. + + The value depends on the PHY and board and has to be measured, + for example by comparing a physical PPS output against a + reference. The default of 0 applies no compensation. + endif # NETUTILS_PTPD diff --git a/netutils/ptpd/ptpd.c b/netutils/ptpd/ptpd.c index e8d08c5d3..ae56660b6 100644 --- a/netutils/ptpd/ptpd.c +++ b/netutils/ptpd/ptpd.c @@ -314,6 +314,22 @@ static int64_t timespec_to_ms(FAR const struct timespec *ts) return ts->tv_sec * MSEC_PER_SEC + (ts->tv_nsec / NSEC_PER_MSEC); } +/* Add a positive or negative number of nanoseconds to a timespec value. */ + +static void timespec_add_ns(FAR struct timespec *ts, int64_t ns) +{ + int64_t total = ts->tv_sec * NSEC_PER_SEC + ts->tv_nsec + ns; + + ts->tv_sec = total / NSEC_PER_SEC; + ts->tv_nsec = total % NSEC_PER_SEC; + + if (ts->tv_nsec < 0) + { + ts->tv_sec--; + ts->tv_nsec += NSEC_PER_SEC; + } +} + /* Get positive or negative delta between two timespec values. * If value would exceed int64 limit (292 years), return INT64_MAX/MIN. */ @@ -500,6 +516,11 @@ static int ptp_getrxtime(FAR struct ptp_state_s *state, if (ts->tv_sec > 0 || ts->tv_nsec > 0) { + /* The MAC latches the timestamp later than the frame + * reaches the wire: compensate the ingress latency. + */ + + timespec_add_ns(ts, -state->config->ingress_latency_ns); return OK; } } diff --git a/system/ptpd/ptpd_main.c b/system/ptpd/ptpd_main.c index 516b75b5f..370f915e1 100644 --- a/system/ptpd/ptpd_main.c +++ b/system/ptpd/ptpd_main.c @@ -164,6 +164,7 @@ static void usage(FAR const char *progname) " -P P2P, support peer delay request-response\n" " -i [dev] interface device to use, for example 'eth0'\n" " -p [dev] clock device to use\n" + " -I [ns] hardware RX timestamp latency to compensate\n" " -t [pid] look the status of ptp daemon\n" " -d [pid] stop ptp daemon\n", progname); @@ -195,8 +196,9 @@ int main(int argc, FAR char *argv[]) #endif config.bmca = false; config.af = AF_INET; + config.ingress_latency_ns = CONFIG_NETUTILS_PTPD_INGRESS_LATENCY_NS; - while ((option = getopt(argc, argv, "p:i:t:d:rs246BEHSP")) != ERROR) + while ((option = getopt(argc, argv, "p:i:t:d:I:rs246BEHSP")) != ERROR) { switch (option) { @@ -251,6 +253,9 @@ int main(int argc, FAR char *argv[]) case 'p': config.clock = optarg; break; + case 'I': + config.ingress_latency_ns = atoi(optarg); + break; case 'r': config.clock = "realtime"; break;