Add BMCA config option.
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.patel@intel.com>master
parent
3f764aec6a
commit
83be05256b
11
bmc.c
11
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;
|
||||
|
||||
|
|
7
config.c
7
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),
|
||||
|
|
|
@ -33,6 +33,7 @@ neighborPropDelayThresh 20000000
|
|||
masterOnly 0
|
||||
G.8275.portDS.localPriority 128
|
||||
asCapable auto
|
||||
BMCA ptp
|
||||
#
|
||||
# Run time options
|
||||
#
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
5
fsm.h
5
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.
|
||||
|
|
11
makefile
11
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
|
||||
|
|
41
port.c
41
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;
|
||||
}
|
||||
|
|
8
port.h
8
port.h
|
@ -322,6 +322,14 @@ enum fault_type last_fault_type(struct port *port);
|
|||
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.
|
||||
*/
|
||||
|
|
|
@ -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*/
|
||||
|
|
17
ptp4l.8
17
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
|
||||
|
||||
|
|
Loading…
Reference in New Issue