On 2/1/2021 2:55 PM, vincent.cheng...@renesas.com wrote:
> 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.


This seems like it could be useful in a number of circumstances!

> 
> 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;
> +}
> +

I'm not sure if we really want to overload free_running, but I can see
how this makes some sense.

>  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
> 


_______________________________________________
Linuxptp-devel mailing list
Linuxptp-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxptp-devel

Reply via email to