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

Reply via email to