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