This commit adds functionality to increase the sync and pdelay request
intervals once gptp synchronization has been achieved. This is useful
while running Automotive Profile where the network is usually static.

Here, we are assuming that the gPTP synchronization is achieved whenever
the last 'n' offsets calculated using the Sync messages are below a
certain threshold. Both, the number of offsets to consider and the offset
threshold are configurable.

In order to support the interval update, a new clock servo state
CLOCK_SERVO_STABLE has been added. The clock will transition to this
state whenever the above condition is satisfied. When this transition
occurs, the slave will send an "interval request" signaling message
asking the master to change the sync interval. It will also update the
pdelay request interval locally.

Four new config options have been added to provide this functionality:

- servo_offset_threshold: All the offset values being considered should
  be below this value.
- servo_num_offset_values: number of previously received offset values
  to consider.
- operLogSyncInterval: slave will ask the master to switch to this
  interval for sending sync messages when the timer expires.
- operLogPdelayReqInterval: the slave will set this interval for pdelay
  request messages when the timer expires.

Signed-off-by: Vedang Patel <vedang.pa...@intel.com>
Change-Id: I6b846561ba712815be70aee8bb80936f51525843
---
 clock.c                      |  1 +
 config.c                     |  4 ++++
 configs/automotive-slave.cfg |  4 ++++
 configs/default.cfg          |  4 ++++
 phc2sys.c                    |  1 +
 port.c                       | 20 +++++++++++++++++++-
 port_private.h               |  2 ++
 ptp4l.8                      | 30 ++++++++++++++++++++++++++++++
 servo.c                      | 19 +++++++++++++++++++
 servo.h                      |  6 ++++++
 servo_private.h              |  3 +++
 11 files changed, 93 insertions(+), 1 deletion(-)

diff --git a/clock.c b/clock.c
index beca9d61e96a..642f6887eb2f 100644
--- a/clock.c
+++ b/clock.c
@@ -1690,6 +1690,7 @@ enum servo_state clock_synchronize(struct clock *c, tmv_t 
ingress, tmv_t origin)
                tsproc_reset(c->tsproc, 0);
                break;
        case SERVO_LOCKED:
+       case SERVO_LOCKED_STABLE:
                clockadj_set_freq(c->clkid, -adj);
                if (c->clkid == CLOCK_REALTIME) {
                        sysclk_set_sync();
diff --git a/config.c b/config.c
index 232131082b2e..eaa083306d75 100644
--- a/config.c
+++ b/config.c
@@ -263,6 +263,8 @@ struct config_item config_tab[] = {
        PORT_ITEM_ENU("network_transport", TRANS_UDP_IPV4, nw_trans_enu),
        GLOB_ITEM_INT("ntpshm_segment", 0, INT_MIN, INT_MAX),
        GLOB_ITEM_INT("offsetScaledLogVariance", 0xffff, 0, UINT16_MAX),
+       PORT_ITEM_INT("operLogSyncInterval", 0, INT8_MIN, INT8_MAX),
+       PORT_ITEM_INT("operLogPdelayReqInterval", 0, INT8_MIN, INT8_MAX),
        PORT_ITEM_INT("path_trace_enabled", 0, 0, 1),
        GLOB_ITEM_DBL("pi_integral_const", 0.0, 0.0, DBL_MAX),
        GLOB_ITEM_DBL("pi_integral_exponent", 0.4, -DBL_MAX, DBL_MAX),
@@ -279,6 +281,8 @@ struct config_item config_tab[] = {
        PORT_ITEM_STR("p2p_dst_mac", "01:80:C2:00:00:0E"),
        GLOB_ITEM_STR("revisionData", ";;"),
        GLOB_ITEM_INT("sanity_freq_limit", 200000000, 0, INT_MAX),
+       GLOB_ITEM_INT("servo_num_offset_values", 10, 0, INT_MAX),
+       GLOB_ITEM_INT("servo_offset_threshold", 0, 0, INT_MAX),
        GLOB_ITEM_INT("slaveOnly", 0, 0, 1),
        GLOB_ITEM_DBL("step_threshold", 0.0, 0.0, DBL_MAX),
        GLOB_ITEM_INT("summary_interval", 0, INT_MIN, INT_MAX),
diff --git a/configs/automotive-slave.cfg b/configs/automotive-slave.cfg
index 94d45b640ae5..8cc7221eaa3a 100644
--- a/configs/automotive-slave.cfg
+++ b/configs/automotive-slave.cfg
@@ -31,3 +31,7 @@ asCapable               true
 ignore_source_id       1
 # Required to quickly correct Time Jumps in master
 step_threshold          1
+operLogSyncInterval     0
+operLogPdelayReqInterval 2
+servo_offset_threshold   30
+servo_num_offset_values  10
diff --git a/configs/default.cfg b/configs/default.cfg
index 3ee3a9b57fed..243355357829 100644
--- a/configs/default.cfg
+++ b/configs/default.cfg
@@ -23,8 +23,10 @@ maxStepsRemoved              255
 #
 logAnnounceInterval    1
 logSyncInterval                0
+operLogSyncInterval    0
 logMinDelayReqInterval 0
 logMinPdelayReqInterval        0
+operLogPdelayReqInterval 0
 announceReceiptTimeout 3
 syncReceiptTimeout     0
 delayAsymmetry         0
@@ -73,6 +75,8 @@ max_frequency         900000000
 clock_servo            pi
 sanity_freq_limit      200000000
 ntpshm_segment         0
+servo_num_offset_values 10
+servo_offset_threshold  0
 #
 # Transport options
 #
diff --git a/phc2sys.c b/phc2sys.c
index a476e63a59cc..cc48f18d92c3 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -619,6 +619,7 @@ static void update_clock(struct node *node, struct clock 
*clock,
                        clockcheck_step(clock->sanity_check, -offset);
                /* Fall through. */
        case SERVO_LOCKED:
+       case SERVO_LOCKED_STABLE:
                clockadj_set_freq(clock->clkid, -ppb);
                if (clock->clkid == CLOCK_REALTIME)
                        sysclk_set_sync();
diff --git a/port.c b/port.c
index 6512c43b7896..373bc886eb27 100644
--- a/port.c
+++ b/port.c
@@ -1112,7 +1112,7 @@ static void port_synchronize(struct port *p,
                             struct timestamp origin_ts,
                             Integer64 correction1, Integer64 correction2)
 {
-       enum servo_state state;
+       enum servo_state state, last_state;
        tmv_t t1, t1c, t2, c1, c2;
 
        port_set_sync_rx_tmo(p);
@@ -1123,10 +1123,16 @@ static void port_synchronize(struct port *p,
        c2 = correction_to_tmv(correction2);
        t1c = tmv_add(t1, tmv_add(c1, c2));
 
+       last_state = clock_servo_state(p->clock);
        state = clock_synchronize(p->clock, t2, t1c);
        switch (state) {
        case SERVO_UNLOCKED:
                port_dispatch(p, EV_SYNCHRONIZATION_FAULT, 0);
+               p->logPdelayReqInterval = p->logMinPdelayReqInterval;
+               p->logSyncInterval = p->initialLogSyncInterval;
+               port_tx_interval_request(p, SIGNAL_NO_CHANGE,
+                                        p->logSyncInterval,
+                                        SIGNAL_NO_CHANGE);
                break;
        case SERVO_JUMP:
                port_dispatch(p, EV_SYNCHRONIZATION_FAULT, 0);
@@ -1139,6 +1145,16 @@ static void port_synchronize(struct port *p,
        case SERVO_LOCKED:
                port_dispatch(p, EV_MASTER_CLOCK_SELECTED, 0);
                break;
+       case SERVO_LOCKED_STABLE:
+               if (last_state == SERVO_LOCKED) {
+                       p->logPdelayReqInterval = p->operLogPdelayReqInterval;
+                       p->logSyncInterval = p->operLogSyncInterval;
+                       port_tx_interval_request(p, SIGNAL_NO_CHANGE,
+                                                p->logSyncInterval,
+                                                SIGNAL_NO_CHANGE);
+               }
+               port_dispatch(p, EV_MASTER_CLOCK_SELECTED, 0);
+               break;
        }
 }
 
@@ -1613,8 +1629,10 @@ int port_initialize(struct port *p)
        p->localPriority           = config_get_int(cfg, p->name, 
"G.8275.portDS.localPriority");
        p->initialLogSyncInterval  = config_get_int(cfg, p->name, 
"logSyncInterval");
        p->logSyncInterval         = p->initialLogSyncInterval;
+       p->operLogSyncInterval     = config_get_int(cfg, p->name, 
"operLogSyncInterval");
        p->logMinPdelayReqInterval = config_get_int(cfg, p->name, 
"logMinPdelayReqInterval");
        p->logPdelayReqInterval    = p->logMinPdelayReqInterval;
+       p->operLogPdelayReqInterval = config_get_int(cfg, p->name, 
"operLogPdelayReqInterval");
        p->neighborPropDelayThresh = config_get_int(cfg, p->name, 
"neighborPropDelayThresh");
        p->min_neighbor_prop_delay = config_get_int(cfg, p->name, 
"min_neighbor_prop_delay");
 
diff --git a/port_private.h b/port_private.h
index 89328e72aa9c..47a4c4f9e48a 100644
--- a/port_private.h
+++ b/port_private.h
@@ -115,9 +115,11 @@ struct port {
        UInteger8           transportSpecific;
        UInteger8           localPriority;
        Integer8            initialLogSyncInterval;
+       Integer8            operLogSyncInterval;
        Integer8            logSyncInterval;
        Enumeration8        delayMechanism;
        Integer8            logMinPdelayReqInterval;
+       Integer8            operLogPdelayReqInterval;
        Integer8            logPdelayReqInterval;
        UInteger32          neighborPropDelayThresh;
        int                 follow_up_info;
diff --git a/ptp4l.8 b/ptp4l.8
index 99b085c148c9..fad21bf57724 100644
--- a/ptp4l.8
+++ b/ptp4l.8
@@ -161,6 +161,13 @@ The mean time interval between Sync messages. A shorter 
interval may improve
 accuracy of the local clock. It's specified as a power of two in seconds.
 The default is 0 (1 second).
 .TP
+.B operLogSyncInterval
+The mean time interval between Sync messages. This value is only used by the
+slave device when interval_update_timer is enabled. Slave will send this
+interval to the master to switch to. This is done via a signaling message after
+interval_update_timer expires. It's specified as a power of two in seconds. The
+default value is 0 (1 second).
+.TP
 .B logMinDelayReqInterval
 The minimum permitted mean time interval between Delay_Req messages. A shorter
 interval makes ptp4l react faster to the changes in the path delay. It's
@@ -172,6 +179,13 @@ The minimum permitted mean time interval between 
Pdelay_Req messages. It's
 specified as a power of two in seconds.
 The default is 0 (1 second).
 .TP
+.B operLogPdelayReqInterval
+The mean time interval between Pdelay Request messages. This value is only used
+by the slave device when interval_update_timer is enabled. Slave will switch to
+the interval specified by this config option after the interval_update_timer
+expires. It's specified as a power of two in seconds. The default value is 0 (1
+second).
+.TP
 .B announceReceiptTimeout
 The number of missed Announce messages before the last Announce messages
 expires.
@@ -715,6 +729,22 @@ This will disable source port identity checking for Sync 
and Follow_Up
 messages. This is useful when the announce messages are disabled in the master
 and the slave does not have any way to know it's identity. The default is 0
 (disabled).
+.TP
+.B servo_num_offset_values
+The number of offset values calculated in previously received Sync messages to
+consider when adjusting the Sync and Pdelay request intervals. More information
+provided in the description of 'offset_threshold'. The default value is 10.
+.TP
+.B servo_offset_threshold
+This value is used by the slave for adjusting the intervals for Sync and Pdelay
+request messages. The slave will check the last 'num_offset_values' offsets and
+if all those offsets are less than the offset_threshold, it will adjust both
+the intervals. The Sync interval is adjusted via the signaling mechanism and
+the pdelay request interval is just adjusted locally. The new values to use for
+sync message intervals and pdelay request intervals can be indicated by
+operLogSyncInterval and operLogPdelayReqInterval respectively. This mechanism
+is currently only supported when BMCA == 'noop'. The default
+value of offset_threshold is 0 (disabled).
 
 .SH UNICAST DISCOVERY OPTIONS
 
diff --git a/servo.c b/servo.c
index 8be4b92875de..6e137defdc49 100644
--- a/servo.c
+++ b/servo.c
@@ -17,6 +17,7 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 #include <string.h>
+#include <stdlib.h>
 
 #include "config.h"
 #include "linreg.h"
@@ -79,6 +80,8 @@ struct servo *servo_create(struct config *cfg, enum 
servo_type type,
        }
 
        servo->first_update = 1;
+       servo->offset_threshold = config_get_int(cfg, NULL, 
"servo_offset_threshold");
+       servo->num_offset_values = config_get_int(cfg, NULL, 
"servo_num_offset_values");
 
        return servo;
 }
@@ -88,6 +91,16 @@ void servo_destroy(struct servo *servo)
        servo->destroy(servo);
 }
 
+int check_offset_threshold(struct servo *s, int64_t offset)
+{
+       if (s->offset_threshold && offset) {
+               if (abs(offset) < s->offset_threshold && s->curr_offset_values)
+                       s->curr_offset_values--;
+               return s->curr_offset_values ? 0 : 1;
+       }
+       return 0;
+}
+
 double servo_sample(struct servo *servo,
                    int64_t offset,
                    uint64_t local_ts,
@@ -100,6 +113,12 @@ double servo_sample(struct servo *servo,
 
        if (*state != SERVO_UNLOCKED)
                servo->first_update = 0;
+       else
+               servo->curr_offset_values = servo->num_offset_values;
+
+       if (*state == SERVO_LOCKED && check_offset_threshold(servo, offset)) {
+               *state = SERVO_LOCKED_STABLE;
+       }
 
        return r;
 }
diff --git a/servo.h b/servo.h
index f90befd9976a..220f4feca288 100644
--- a/servo.h
+++ b/servo.h
@@ -57,6 +57,12 @@ enum servo_state {
         * The servo is tracking the master clock.
         */
        SERVO_LOCKED,
+
+       /**
+        * The Servo has stabilized. The last 'servo_num_offset_values' values
+        * of the estimated threshold are less than servo_offset_threshold.
+        */
+       SERVO_LOCKED_STABLE,
 };
 
 /**
diff --git a/servo_private.h b/servo_private.h
index 1c5cfdfa18d1..48bdd1662715 100644
--- a/servo_private.h
+++ b/servo_private.h
@@ -29,6 +29,9 @@ struct servo {
        double step_threshold;
        double first_step_threshold;
        int first_update;
+       int offset_threshold;
+       int num_offset_values;
+       int curr_offset_values;
 
        void (*destroy)(struct servo *servo);
 
-- 
2.7.3



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

Reply via email to