From: Vincent Cheng <vincent.cheng...@renesas.com> When clock stepping is unable to happen instantaneously the subsequent timestamps after a clock step does not reflect the step result and undesired clock freq and step adjustments will occur.
When using ts2phc to synchronize timestamping clock using external 1 PPS, it could take up to 1 second for the timestamps to reflect the clock step. step_window, when set, indicates the time in seconds after a clock step in which the clock servo will not do any frequency or step adjustments. Signed-off-by: Vincent Cheng <vincent.cheng...@renesas.com> --- clock.c | 40 ++++++++++++++++++++++++++++++++++++++++ config.c | 1 + ptp4l.8 | 8 ++++++++ 3 files changed, 49 insertions(+) diff --git a/clock.c b/clock.c index a34737a..c03d548 100644 --- a/clock.c +++ b/clock.c @@ -20,6 +20,7 @@ #include <time.h> #include <linux/net_tstamp.h> #include <poll.h> +#include <signal.h> #include <stdlib.h> #include <string.h> #include <sys/ioctl.h> @@ -132,6 +133,8 @@ struct clock { struct interface *udsif; LIST_HEAD(clock_subscribers_head, clock_subscriber) subscribers; struct monitor *slave_event_monitor; + int step_window; + timer_t step_timer_id; }; struct clock the_clock; @@ -141,6 +144,13 @@ static int clock_resize_pollfd(struct clock *c, int new_nports); static void clock_remove_port(struct clock *c, struct port *p); static void clock_stats_display(struct clock_stats *s); +static void clock_clear_free_running(union sigval callback_data) +{ + struct clock *c = (struct clock *)(callback_data.sival_ptr); + + c->free_running = 0; +} + static void remove_subscriber(struct clock_subscriber *s) { LIST_REMOVE(s, list); @@ -286,6 +296,7 @@ void clock_destroy(struct clock *c) if (c->sanity_check) { clockcheck_destroy(c->sanity_check); } + timer_delete(c->step_timer_id); memset(c, 0, sizeof(*c)); msg_cleanup(); tc_cleanup(); @@ -897,6 +908,7 @@ struct clock *clock_create(enum clock_type type, struct config *config, unsigned char oui[OUI_LEN]; struct interface *iface; struct timespec ts; + struct sigevent se; int sfl; clock_gettime(CLOCK_REALTIME, &ts); @@ -1194,6 +1206,18 @@ struct clock *clock_create(enum clock_type type, struct config *config, return NULL; } + /* Set up timer expire notification mechanism */ + se.sigev_notify = SIGEV_THREAD; + se.sigev_value.sival_ptr = (void *)c; + se.sigev_notify_function = clock_clear_free_running; + se.sigev_notify_attributes = NULL; + + if (timer_create(CLOCK_MONOTONIC, &se, &c->step_timer_id)) { + pr_err("failed to create step timer_id"); + return NULL; + } + c->step_window = config_get_int(config, NULL, "step_window"); + /* Create the ports. */ STAILQ_FOREACH(iface, &config->interfaces, list) { if (clock_add_port(c, phc_device, phc_index, timestamping, iface)) { @@ -1696,6 +1720,21 @@ int clock_switch_phc(struct clock *c, int phc_index) return 0; } +static void clock_step_window(struct clock *c) +{ + struct itimerspec tmo = { + {0, 0}, {0, 0} + }; + + if (!c->step_window) + return; + + c->free_running = 1; + + tmo.it_value.tv_sec = c->step_window; + timer_settime(c->step_timer_id, 0, &tmo, 0); +} + static void clock_synchronize_locked(struct clock *c, double adj) { clockadj_set_freq(c->clkid, -adj); @@ -1748,6 +1787,7 @@ enum servo_state clock_synchronize(struct clock *c, tmv_t ingress, tmv_t origin) case SERVO_JUMP: clockadj_set_freq(c->clkid, -adj); clockadj_step(c->clkid, -tmv_to_nanoseconds(c->master_offset)); + clock_step_window(c); c->ingress_ts = tmv_zero(); if (c->sanity_check) { clockcheck_set_freq(c->sanity_check, -adj); diff --git a/config.c b/config.c index 4095b33..2b74bc8 100644 --- a/config.c +++ b/config.c @@ -303,6 +303,7 @@ struct config_item config_tab[] = { GLOB_ITEM_INT("slaveOnly", 0, 0, 1), /*deprecated*/ GLOB_ITEM_INT("socket_priority", 0, 0, 15), GLOB_ITEM_DBL("step_threshold", 0.0, 0.0, DBL_MAX), + GLOB_ITEM_INT("step_window", 0, 0, UINT8_MAX), GLOB_ITEM_INT("summary_interval", 0, INT_MIN, INT_MAX), PORT_ITEM_INT("syncReceiptTimeout", 0, 0, UINT8_MAX), GLOB_ITEM_INT("tc_spanning_tree", 0, 0, 1), diff --git a/ptp4l.8 b/ptp4l.8 index 260aae3..0923bf3 100644 --- a/ptp4l.8 +++ b/ptp4l.8 @@ -699,6 +699,14 @@ one-second offset slowly by changing the clock frequency (unless the option is set to correct such offset by stepping). Relevant only with software time stamping. The default is 1 (enabled). .TP +.B step_window +When set, indicates the time in seconds after a clock step that the clock will +not do any frequency or step adjustments. +This is used in situations where clock stepping is unable to happen +instantaneously and so there is a lag before the timestamps can settle +properly reflect the clock step. +The default is 0 (disabled). +.TP .B timeSource The time source is a single byte code that gives an idea of the kind of local clock in use. The value is purely informational, having no -- 2.7.4 _______________________________________________ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel