This adds config option to specify static roles for master and slave
in the Best Master Clock Algorithm. This is the case for Automotive
Profile where networks are mostly static and role for each device is
known in advance.

masterOnly and slaveOnly will be used to determine the roles for the
devices. Since masterOnly is a per-port config and slaveOnly is a global
config option, role assignment will be slightly odd in case of bridges.
If slaveOnly is set to 1, all the ports will be in slave roles except
for the ones where masterOnly is set to 1. These ports will assume the
master role.

Two new FSMs which will be used for master and slave roles for this
config option have also been added.

Signed-off-by: Vedang Patel <vedang.pa...@intel.com>
---
 bmc.c               |  11 ++++++
 config.c            |   7 ++++
 configs/default.cfg |   1 +
 designated_fsm.c    | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 designated_fsm.h    |  43 +++++++++++++++++++++
 fsm.h               |   5 +++
 makefile            |  11 +++---
 port.c              |  41 +++++++++++++++++++-
 port.h              |   8 ++++
 port_private.h      |   1 +
 ptp4l.8             |  17 +++++++--
 11 files changed, 241 insertions(+), 11 deletions(-)
 create mode 100644 designated_fsm.c
 create mode 100644 designated_fsm.h

diff --git a/bmc.c b/bmc.c
index 3c3db828764b..6ac7aa0f4fe8 100644
--- a/bmc.c
+++ b/bmc.c
@@ -126,6 +126,17 @@ enum port_state bmc_state_decision(struct clock *c, struct 
port *r,
        port_best = port_best_foreign(r);
        ps = port_state(r);
 
+       /*
+        * This scenario is particularly important in the designated_slave_fsm
+        * when it is in PS_SLAVE state. In this scenario, there is no other
+        * foreign master and it will elect itself as master ultimately
+        * resulting in printing out some unnecessary warnings (see
+        * port_slave_priority_warning()).
+        */
+       if (!port_best && port_bmca(r) == BMCA_NOOP) {
+               return ps;
+       }
+
        if (!port_best && PS_LISTENING == ps)
                return ps;
 
diff --git a/config.c b/config.c
index c55bd51aaee6..78b578b8bc8c 100644
--- a/config.c
+++ b/config.c
@@ -202,11 +202,18 @@ static struct config_enum as_capable_enu[] = {
        { NULL, 0 },
 };
 
+static struct config_enum bmca_enu[] = {
+       { "ptp",  BMCA_PTP  },
+       { "noop", BMCA_NOOP },
+       { NULL, 0 },
+};
+
 struct config_item config_tab[] = {
        PORT_ITEM_INT("announceReceiptTimeout", 3, 2, UINT8_MAX),
        PORT_ITEM_ENU("asCapable", AS_CAPABLE_AUTO, as_capable_enu),
        GLOB_ITEM_INT("assume_two_step", 0, 0, 1),
        PORT_ITEM_INT("boundary_clock_jbod", 0, 0, 1),
+       PORT_ITEM_ENU("BMCA", BMCA_PTP, bmca_enu),
        GLOB_ITEM_INT("check_fup_sync", 0, 0, 1),
        GLOB_ITEM_INT("clockAccuracy", 0xfe, 0, UINT8_MAX),
        GLOB_ITEM_INT("clockClass", 248, 0, UINT8_MAX),
diff --git a/configs/default.cfg b/configs/default.cfg
index d2b8c8fb55cb..de346a3741f2 100644
--- a/configs/default.cfg
+++ b/configs/default.cfg
@@ -33,6 +33,7 @@ neighborPropDelayThresh       20000000
 masterOnly             0
 G.8275.portDS.localPriority    128
 asCapable               auto
+BMCA                    ptp
 #
 # Run time options
 #
diff --git a/designated_fsm.c b/designated_fsm.c
new file mode 100644
index 000000000000..d19158b0b8a1
--- /dev/null
+++ b/designated_fsm.c
@@ -0,0 +1,107 @@
+/**
+ * @file designated_fsm.c
+ * @brief Implements designated Finite State Machines.
+ * @note Copyright (C) 2018 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA.
+ */
+#include "fsm.h"
+#include "designated_fsm.h"
+
+enum port_state designated_master_fsm(enum port_state state,
+                                     enum fsm_event event,
+                                     int mdiff)
+{
+       enum port_state next = state;
+
+       if (EV_INITIALIZE == event || EV_POWERUP == event)
+               return PS_INITIALIZING;
+
+       switch (state) {
+       case PS_INITIALIZING:
+               switch (event) {
+               case EV_FAULT_DETECTED:
+                       next = PS_FAULTY;
+                       break;
+               case EV_INIT_COMPLETE:
+                       next = PS_MASTER;
+                       break;
+               default:
+                       break;
+               }
+               break;
+
+       case PS_FAULTY:
+               if (event == EV_FAULT_CLEARED) {
+                       next = PS_INITIALIZING;
+               }
+               break;
+
+       case PS_MASTER:
+               if (event == EV_FAULT_DETECTED) {
+                       next = PS_FAULTY;
+               }
+               break;
+
+       default:
+               break;
+       }
+       return next;
+}
+
+enum port_state designated_slave_fsm(enum port_state state,
+                                    enum fsm_event event,
+                                    int mdiff)
+{
+       enum port_state next = state;
+
+       if (EV_INITIALIZE == event || EV_POWERUP == event)
+               return PS_INITIALIZING;
+
+       switch (state) {
+       case PS_INITIALIZING:
+               switch (event) {
+               case EV_FAULT_DETECTED:
+                       next = PS_FAULTY;
+                       break;
+               case EV_INIT_COMPLETE:
+                       next =  PS_SLAVE;
+                       break;
+               default:
+                       break;
+               }
+               break;
+
+       case PS_FAULTY:
+               if (event == EV_FAULT_CLEARED) {
+                       next = PS_INITIALIZING;
+               }
+               break;
+
+       case PS_SLAVE:
+               switch (event) {
+               case EV_FAULT_DETECTED:
+                       next = PS_FAULTY;
+                       break;
+               default:
+                       break;
+               }
+               break;
+
+       default:
+               break;
+       }
+       return next;
+}
diff --git a/designated_fsm.h b/designated_fsm.h
new file mode 100644
index 000000000000..b1c0eae06281
--- /dev/null
+++ b/designated_fsm.h
@@ -0,0 +1,43 @@
+/**
+ * @file designated_fsm.c
+ * @brief Implements designated Finite State Machines.
+ * @note Copyright (C) 2018 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA.
+ */
+#ifndef HAVE_DESIGNATED_FSM_H
+#define HAVE_DESIGNATED_FSM_H
+/**
+ * Run the state machine for a clock which is designated as master port.
+ * @param state  The current state of the port.
+ * @param event  The event to be processed.
+ * @param mdiff  This param is not used by this function.
+ * @return       The new state for the port.
+ */
+enum port_state designated_master_fsm(enum port_state state,
+                                     enum fsm_event event,
+                                     int mdiff);
+
+/**
+ * Run the state machine for a clock designated as slave port.
+ * @param state  The current state of the port.
+ * @param event  The event to be processed.
+ * @param mdiff  This param is not used by this function.
+ * @return       The new state for the port.
+ */
+enum port_state designated_slave_fsm(enum port_state state,
+                                    enum fsm_event event,
+                                    int mdiff);
+#endif
diff --git a/fsm.h b/fsm.h
index 0616daa2ab7b..857af0522c97 100644
--- a/fsm.h
+++ b/fsm.h
@@ -55,6 +55,11 @@ enum fsm_event {
        EV_RS_PASSIVE,
 };
 
+enum bmca_select {
+       BMCA_PTP,
+       BMCA_NOOP,
+};
+
 /**
  * Run the state machine for a BC or OC port.
  * @param state  The current state of the port.
diff --git a/makefile b/makefile
index 6995e70393ea..d09a4a9f56cc 100644
--- a/makefile
+++ b/makefile
@@ -23,11 +23,12 @@ VER     = -DVER=$(version)
 CFLAGS = -Wall $(VER) $(incdefs) $(DEBUG) $(EXTRA_CFLAGS)
 LDLIBS = -lm -lrt $(EXTRA_LDFLAGS)
 PRG    = ptp4l hwstamp_ctl nsm phc2sys phc_ctl pmc timemaster
-OBJ     = bmc.o clock.o clockadj.o clockcheck.o config.o e2e_tc.o fault.o \
- filter.o fsm.o hash.o linreg.o mave.o mmedian.o msg.o ntpshm.o nullf.o phc.o \
- pi.o port.o port_signaling.o pqueue.o print.o ptp4l.o p2p_tc.o raw.o rtnl.o \
- servo.o sk.o stats.o tc.o telecom.o tlv.o transport.o tsproc.o udp.o udp6.o \
- uds.o unicast_client.o unicast_fsm.o unicast_service.o util.o version.o
+OBJ     = bmc.o clock.o clockadj.o clockcheck.o config.o designated_fsm.o \
+e2e_tc.o fault.o filter.o fsm.o hash.o linreg.o mave.o mmedian.o msg.o 
ntpshm.o \
+nullf.o phc.o pi.o port.o port_signaling.o pqueue.o print.o ptp4l.o p2p_tc.o \
+raw.o rtnl.o servo.o sk.o stats.o tc.o telecom.o tlv.o transport.o tsproc.o \
+udp.o udp6.o uds.o unicast_client.o unicast_fsm.o unicast_service.o util.o \
+version.o
 
 OBJECTS        = $(OBJ) hwstamp_ctl.o nsm.o phc2sys.o phc_ctl.o pmc.o 
pmc_common.o \
  sysoff.o timemaster.o
diff --git a/port.c b/port.c
index cd875538bdbd..96e536f05d8c 100644
--- a/port.c
+++ b/port.c
@@ -27,6 +27,7 @@
 
 #include "bmc.h"
 #include "clock.h"
+#include "designated_fsm.h"
 #include "filter.h"
 #include "missing.h"
 #include "msg.h"
@@ -1596,7 +1597,6 @@ int port_initialize(struct port *p)
        p->transportSpecific       = config_get_int(cfg, p->name, 
"transportSpecific");
        p->transportSpecific     <<= 4;
        p->match_transport_specific = !config_get_int(cfg, p->name, 
"ignore_transport_specific");
-       p->master_only             = config_get_int(cfg, p->name, "masterOnly");
        p->localPriority           = config_get_int(cfg, p->name, 
"G.8275.portDS.localPriority");
        p->logSyncInterval         = config_get_int(cfg, p->name, 
"logSyncInterval");
        p->logMinPdelayReqInterval = config_get_int(cfg, p->name, 
"logMinPdelayReqInterval");
@@ -1635,6 +1635,14 @@ int port_initialize(struct port *p)
 
        /* No need to open rtnl socket on UDS port. */
        if (transport_type(p->trp) != TRANS_UDS) {
+               /*
+                * The delay timer is usually started when the device
+                * transitions to PS_LISTENING. But, we are skipping the state
+                * when BMCA == 'noop'. So, start the timer here.
+                */
+               if (p->bmca == BMCA_NOOP) {
+                       port_set_delay_tmo(p);
+               }
                if (p->fda.fd[FD_RTNL] == -1)
                        p->fda.fd[FD_RTNL] = rtnl_open();
                if (p->fda.fd[FD_RTNL] >= 0)
@@ -2469,6 +2477,16 @@ static enum fsm_event bc_event(struct port *p, int 
fd_index)
                if (p->best)
                        fc_clear(p->best);
                port_set_announce_tmo(p);
+
+               /*
+                * Clear out the event returned by poll(). It is only cleared
+                * in port_*_transition(). But, when BMCA == 'noop', there is no
+                * state transition. So, it won't be cleared anywhere else.
+                */
+               if (p->bmca == BMCA_NOOP) {
+                       port_clr_tmo(p->fda.fd[FD_SYNC_RX_TIMER]);
+               }
+
                delay_req_prune(p);
                if (clock_slave_only(p->clock) && p->delayMechanism != DM_P2P &&
                    port_renew_transport(p)) {
@@ -2859,10 +2877,24 @@ struct port *port_open(int phc_index,
                goto err_port;
        }
 
-       p->state_machine = clock_slave_only(clock) ? ptp_slave_fsm : ptp_fsm;
        p->phc_index = phc_index;
        p->jbod = config_get_int(cfg, interface->name, "boundary_clock_jbod");
        transport = config_get_int(cfg, interface->name, "network_transport");
+       p->master_only = config_get_int(cfg, p->name, "masterOnly");
+       p->bmca = config_get_int(cfg, p->name, "BMCA");
+
+       if (p->bmca == BMCA_NOOP && transport != TRANS_UDS) {
+               if (p->master_only) {
+                       p->state_machine = designated_master_fsm;
+               } else if (clock_slave_only(clock)) {
+                       p->state_machine = designated_slave_fsm;
+               } else {
+                       pr_err("Please enable at least one of masterOnly or 
slaveOnly when BMCA == noop.\n");
+                       goto err_port;
+               }
+       } else {
+               p->state_machine = clock_slave_only(clock) ? ptp_slave_fsm : 
ptp_fsm;
+       }
 
        if (transport == TRANS_UDS) {
                ; /* UDS cannot have a PHC. */
@@ -3020,3 +3052,8 @@ int port_state_update(struct port *p, enum fsm_event 
event, int mdiff)
 
        return 0;
 }
+
+enum bmca_select port_bmca(struct port *p)
+{
+       return p->bmca;
+}
diff --git a/port.h b/port.h
index 9639193d23d1..aa3b1ecf2529 100644
--- a/port.h
+++ b/port.h
@@ -323,6 +323,14 @@ void fault_interval(struct port *port, enum fault_type ft,
                    struct fault_interval *i);
 
 /**
+ * Obtain the BMCA type of the port.
+ *
+ * @param port        A port instance.
+ * @return            bmca type.
+ */
+enum bmca_select port_bmca(struct port *p);
+
+/**
  * Release all of the memory in the TC transmit descriptor cache.
  */
 void tc_cleanup(void);
diff --git a/port_private.h b/port_private.h
index 91e79867bf38..4b22976b57eb 100644
--- a/port_private.h
+++ b/port_private.h
@@ -97,6 +97,7 @@ struct port {
        unsigned int multiple_pdr_detected;
        enum port_state (*state_machine)(enum port_state state,
                                         enum fsm_event event, int mdiff);
+       int bmca;
        /* portDS */
        struct PortIdentity portIdentity;
        enum port_state     state; /*portState*/
diff --git a/ptp4l.8 b/ptp4l.8
index 8e9b9a274daa..a4a31a346b59 100644
--- a/ptp4l.8
+++ b/ptp4l.8
@@ -363,10 +363,7 @@ hardware time stamping.
 The default is 1 (enabled).
 .TP
 .B slaveOnly
-The local clock is a slave-only clock if enabled.
-This option is only for use with 1588 clocks and should not be enabled
-for 802.1AS clocks.
-The default is 0 (disabled).
+The local clock is a slave-only clock if enabled. The default is 0 (disabled).
 .TP
 .B gmCapable
 If this option is enabled, then the local clock is able to become grand master.
@@ -692,6 +689,18 @@ If set to 'true', all the checks which can unset asCapable 
variable (as
 described in Section 10.2.4.1 of 802.1AS) are skipped. If set to 'auto',
 asCapable is initialized to 'false' and will be set to 'true' after the
 relevant checks have passed. The default value is 'auto'.
+.TP
+.B BMCA
+This option enables use of static roles for master and slave devices instead of
+running the best master clock algorithm (BMCA) described in 1588 profile. This
+is useful when you know the roles of the devices in advance. When set to
+\'noop', the traditional BMCA algorithm used by 1588 is skipped. masterOnly and
+slaveOnly will be used to determine master or slave role for the device. In a
+bridge, slaveOnly (which is a global option) can be set to make all ports
+assume the slave role. masterOnly (which is a per-port config option) can then
+be used to set individual ports to take master role. BMCA is used in the
+Automotive profile to speed up the start time for grand master and slaves. The
+default value is 'ptp' which runs the BMCA related state machines.
 
 .SH UNICAST DISCOVERY OPTIONS
 
-- 
2.7.3



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

Reply via email to