This adds a config option to specify static roles for master and slave in the Best Master Clock Algorithm. This is the case for AVnu Automotive Profile [1] 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. This commit adds functionality equivalent to the 'isGM' variable defined in Section 6.2.1.1 of the AVnu Automotive Profile[1]. [1] - http://avnu.org/wp-content/uploads/2014/05/ Automotive-Ethernet-AVB-Func-Interop-Spec-v1.5-Public.pdf Signed-off-by: Vedang Patel <vedang.pa...@intel.com> Change-Id: I85ed0484ffed2f3136f333c03611f1983099ce7b --- bmc.c | 11 ++++++ config.c | 7 ++++ configs/default.cfg | 1 + fsm.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++ fsm.h | 26 ++++++++++++++ port.c | 38 ++++++++++++++++++-- port.h | 8 +++++ port_private.h | 1 + ptp4l.8 | 17 ++++++--- 9 files changed, 203 insertions(+), 6 deletions(-) diff --git a/bmc.c b/bmc.c index 3c3db828764b..b0a80c2198cb 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_UNCALIBRATED state. In this scenario, there is no + * other foriegn 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 7914ba4b5166..47cad7ab6632 100644 --- a/config.c +++ b/config.c @@ -188,10 +188,17 @@ static struct config_enum tsproc_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), 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 c5a8b57c9314..02714150fbab 100644 --- a/configs/default.cfg +++ b/configs/default.cfg @@ -31,6 +31,7 @@ fault_reset_interval 4 neighborPropDelayThresh 20000000 masterOnly 0 G.8275.portDS.localPriority 128 +BMCA ptp # # Run time options # diff --git a/fsm.c b/fsm.c index ce6efad30937..a0c98891e39f 100644 --- a/fsm.c +++ b/fsm.c @@ -335,3 +335,103 @@ enum port_state ptp_slave_fsm(enum port_state state, enum fsm_event event, return next; } + +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_UNCALIBRATED: + if (event == EV_MASTER_CLOCK_SELECTED) { + next = PS_SLAVE; + } + break; + + case PS_SLAVE: + switch (event) { + case EV_FAULT_DETECTED: + next = PS_FAULTY; + break; + /* + * Go to PS_UNCALIBRATED when there is a loss of sync messages. + * This will also be useful in changing the Sync Interval (to + * be implemented). + */ + case EV_ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES: + next = PS_UNCALIBRATED; + break; + default: + break; + } + break; + + default: + break; + } + return next; +} diff --git a/fsm.h b/fsm.h index 0616daa2ab7b..f8a1cbf2d2bf 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. @@ -74,4 +79,25 @@ enum port_state ptp_fsm(enum port_state state, enum fsm_event event, int mdiff); enum port_state ptp_slave_fsm(enum port_state state, enum fsm_event event, int mdiff); +/** + * 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/port.c b/port.c index 1a0e910a1151..6144b1a05de5 100644 --- a/port.c +++ b/port.c @@ -1593,7 +1593,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"); @@ -2339,6 +2338,14 @@ static void port_p2p_transition(struct port *p, enum port_state next) break; case PS_MASTER: case PS_GRAND_MASTER: + /* + * If BMCA is set to 'noop', we are skipping the PS_LISTENING + * state and directly going to PS_MASTER. So, set the delay + * timeout here. + */ + if (p->bmca == BMCA_NOOP) { + port_set_delay_tmo(p); + } set_tmo_log(p->fda.fd[FD_MANNO_TIMER], 1, -10); /*~1ms*/ port_set_sync_tx_tmo(p); break; @@ -2350,6 +2357,14 @@ static void port_p2p_transition(struct port *p, enum port_state next) flush_peer_delay(p); /* fall through */ case PS_SLAVE: + /* + * If BMCA is set to 'noop', we are skipping the PS_LISTENING + * state and directly going to PS_SLAVE. So, set the delay + * timeout here. + */ + if (p->bmca == BMCA_NOOP) { + port_set_delay_tmo(p); + } port_set_announce_tmo(p); break; }; @@ -2853,10 +2868,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 atleast 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. */ @@ -3014,3 +3043,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 19d1d7beaae8..8b5525a2122a 100644 --- a/port_private.h +++ b/port_private.h @@ -96,6 +96,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 10c5c2f967cb..8c19d1d276ee 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. @@ -661,6 +658,18 @@ 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 effect on the outcome of the Best Master Clock algorithm, and is advertised when the clock becomes grand master. +.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 AVnu +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 ------------------------------------------------------------------------------ Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot _______________________________________________ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel