A PTP Master Clock, which is not the Best Master, may act as a master with the Alternate Master flag set on the messages it sends. Need to support Alternate Master, including using Slave Event Monitoring channel for the alternate connections (to pass along timestamps to external servo). See ITU-T G.8275.2 Appendix III & V.
Signed-off-by: Greg Armstrong <greg.armstrong...@renesas.com> Signed-off-by: Leon Goldin <leon.goldin...@renesas.com> Signed-off-by: Devasish Dey <devasish....@syncmonk.net> Signed-off-by: Vipin Sharma <vipin.sha...@syncmonk.net> --- clock.c | 5 +++ clock.h | 7 ++++ config.c | 1 + msg.h | 10 +++++ port.c | 100 ++++++++++++++++++++++++++++++++++++++++--------- port_private.h | 1 + 6 files changed, 107 insertions(+), 17 deletions(-) diff --git a/clock.c b/clock.c index d37bb87..428a1e5 100644 --- a/clock.c +++ b/clock.c @@ -1715,6 +1715,11 @@ int clock_slave_only(struct clock *c) return c->dds.flags & DDS_SLAVE_ONLY; } +bool clock_telecom_profile(struct clock *c) +{ + return (c->dscmp == telecom_dscmp); +} + UInteger8 clock_max_steps_removed(struct clock *c) { return c->max_steps_removed; diff --git a/clock.h b/clock.h index 0534f21..a869fae 100644 --- a/clock.h +++ b/clock.h @@ -289,6 +289,13 @@ int clock_slave_only(struct clock *c); */ UInteger8 clock_max_steps_removed(struct clock *c); +/** + * Obtain the clock is set for telecom profile . + * @param c The clock instance. + * @return True if the profile is telecom, false otherwise. + */ +bool clock_telecom_profile(struct clock *c); + /** * Obtain the clock class threshold field from a clock's default data set. * @param c The clock instance. diff --git a/config.c b/config.c index b5cf397..ce8a3ae 100644 --- a/config.c +++ b/config.c @@ -226,6 +226,7 @@ static struct config_enum bmca_enu[] = { }; struct config_item config_tab[] = { + PORT_ITEM_INT("altMaster", 0, 1, 1), 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), diff --git a/msg.h b/msg.h index b7423ee..22dfbeb 100644 --- a/msg.h +++ b/msg.h @@ -461,6 +461,16 @@ static inline Boolean one_step(struct ptp_message *m) return !field_is_set(m, 0, TWO_STEP); } +/** + * Test whether a message from ALTERNATE Master. + * @param m Message to test. + * @return One if the alt_master flag in message is set, zero otherwise. + */ +static inline Boolean alt_master(struct ptp_message *m) +{ + return field_is_set(m, 0, ALT_MASTER); +} + /** * Convert a 64 bit word into network byte order. */ diff --git a/port.c b/port.c index 871ad68..4ff3ab8 100644 --- a/port.c +++ b/port.c @@ -1293,11 +1293,16 @@ static void port_synchronize(struct port *p, t1c = tmv_add(t1, tmv_add(c1, c2)); switch (p->state) { + case PS_MASTER: + return; case PS_UNCALIBRATED: case PS_SLAVE: monitor_sync(p->slave_event_monitor, clock_parent_identity(p->clock), seqid, t1, tmv_add(c1, c2), t2); + monitor_computed(p->slave_event_monitor, + clock_parent_identity(p->clock), seqid, + tmv_sub(t2, t1c), tmv_sub(t2, t1c), 0, 1); break; default: break; @@ -1509,6 +1514,7 @@ out: int port_delay_request(struct port *p) { struct ptp_message *msg; + struct ptp_message *dst; /* Time to send a new request, forget current pdelay resp and fup */ if (p->peer_delay_resp) { @@ -1541,10 +1547,20 @@ int port_delay_request(struct port *p) msg->header.control = CTL_DELAY_REQ; msg->header.logMessageInterval = 0x7f; - if (p->hybrid_e2e) { - struct ptp_message *dst = TAILQ_FIRST(&p->best->messages); + if (p->hybrid_e2e && p->state != PS_MASTER) { + dst = TAILQ_FIRST(&p->best->messages); msg->address = dst->address; msg->header.flagField[0] |= UNICAST; + } else if (p->altMaster) { + struct foreign_clock *fc; + fc = LIST_FIRST(&p->foreign_masters); + if (fc) { + dst = TAILQ_FIRST(&fc->messages); + if (dst) { + msg->address = dst->address; + msg->header.flagField[0] |= UNICAST; + } + } } if (port_prepare_and_send(p, msg, TRANS_EVENT)) { @@ -1595,6 +1611,10 @@ int port_tx_announce(struct port *p, struct address *dst, uint16_t sequence_id) msg->header.flagField[1] = tp.flags; + if (p->state != PS_MASTER && clock_telecom_profile(p->clock)) { + msg->header.flagField[0] |= ALT_MASTER; + } + if (dst) { msg->address = *dst; msg->header.flagField[0] |= UNICAST; @@ -1674,6 +1694,10 @@ int port_tx_sync(struct port *p, struct address *dst, uint16_t sequence_id) msg->header.flagField[0] |= TWO_STEP; } + if (p->state != PS_MASTER && clock_telecom_profile(p->clock)) { + msg->header.flagField[0] |= ALT_MASTER; + } + if (dst) { msg->address = *dst; msg->header.flagField[0] |= UNICAST; @@ -1707,6 +1731,9 @@ int port_tx_sync(struct port *p, struct address *dst, uint16_t sequence_id) fup->header.logMessageInterval = p->logSyncInterval; fup->follow_up.preciseOriginTimestamp = tmv_to_Timestamp(msg->hwts.ts); + if (p->state != PS_MASTER && clock_telecom_profile(p->clock)) { + fup->header.flagField[0] |= ALT_MASTER; + } if (dst) { fup->address = *dst; @@ -1842,6 +1869,7 @@ int port_initialize(struct port *p) p->neighborPropDelayThresh = config_get_int(cfg, p->name, "neighborPropDelayThresh"); p->min_neighbor_prop_delay = config_get_int(cfg, p->name, "min_neighbor_prop_delay"); p->delay_response_timeout = config_get_int(cfg, p->name, "delay_response_timeout"); + p->altMaster = config_get_int(cfg, p->name, "altMaster"); if (config_get_int(cfg, p->name, "asCapable") == AS_CAPABLE_TRUE) { p->asCapable = ALWAYS_CAPABLE; @@ -1995,6 +2023,17 @@ int process_announce(struct port *p, struct ptp_message *m) return result; } + if (clock_telecom_profile(p->clock)) { + if ((alt_master(m))) { + pr_debug("(%s) Announce message ignored for %s", + p->name, + alt_master(m) ? "alternate master flag" : + "signal fail condition"); + return result; + } + + } + if (m->announce.grandmasterClockQuality.clockClass > clock_get_clock_class_threshold(p->clock)) { pl_err(60, "%s: Master clock quality received is " @@ -2030,10 +2069,12 @@ static int process_delay_req(struct port *p, struct ptp_message *m) nsm = port_nsm_reply(p, m); - if (!nsm && p->state != PS_MASTER && p->state != PS_GRAND_MASTER) { + if (!nsm && p->state != PS_MASTER && + p->state != PS_GRAND_MASTER && p->state != PS_PASSIVE) { return 0; } + if (p->delayMechanism == DM_P2P) { pr_warning("%s: delay request on P2P port", p->log_name); return 0; @@ -2065,6 +2106,11 @@ static int process_delay_req(struct port *p, struct ptp_message *m) msg->header.flagField[0] |= UNICAST; msg->header.logMessageInterval = 0x7f; } + + if (p->state != PS_MASTER && clock_telecom_profile(p->clock)) { + msg->header.flagField[0] |= ALT_MASTER; + } + if (nsm && net_sync_resp_append(p, msg)) { pr_err("%s: append NSM failed", p->log_name); err = -1; @@ -2089,15 +2135,24 @@ void process_delay_resp(struct port *p, struct ptp_message *m) struct ptp_message *req; tmv_t c3, t3, t4, t4c; - if (p->state != PS_UNCALIBRATED && p->state != PS_SLAVE) { + switch (p->state) { + case PS_MASTER: + if (!p->altMaster) { + return; + } + break; + case PS_UNCALIBRATED: + case PS_SLAVE: + if (check_source_identity(p, m)) { + return; + } + break; + default: return; } if (!pid_eq(&rsp->requestingPortIdentity, &p->portIdentity)) { return; } - if (check_source_identity(p, m)) { - return; - } TAILQ_FOREACH(req, &p->delay_req, list) { if (rsp->hdr.sequenceId == ntohs(req->delay_req.hdr.sequenceId)) { break; @@ -2151,19 +2206,22 @@ void process_follow_up(struct port *p, struct ptp_message *m) case PS_DISABLED: case PS_LISTENING: case PS_PRE_MASTER: - case PS_MASTER: case PS_GRAND_MASTER: case PS_PASSIVE: return; + case PS_MASTER: + if (!p->altMaster) { + return; + } + break; case PS_UNCALIBRATED: case PS_SLAVE: + if (check_source_identity(p, m)) { + return; + } break; } - if (check_source_identity(p, m)) { - return; - } - if (p->follow_up_info) { struct follow_up_info_tlv *fui = follow_up_info_extract(m); if (!fui) @@ -2455,19 +2513,22 @@ void process_sync(struct port *p, struct ptp_message *m) case PS_DISABLED: case PS_LISTENING: case PS_PRE_MASTER: - case PS_MASTER: case PS_GRAND_MASTER: case PS_PASSIVE: return; + case PS_MASTER: + if (!p->altMaster) { + return; + } + break; case PS_UNCALIBRATED: case PS_SLAVE: + if (check_source_identity(p, m)) { + return; + } break; } - if (check_source_identity(p, m)) { - return; - } - if (!msg_unicast(m) && m->header.logMessageInterval != p->log_sync_interval) { if (m->header.logMessageInterval < -10 || @@ -2584,6 +2645,10 @@ static void port_e2e_transition(struct port *p, enum port_state next) port_set_qualification_tmo(p); break; case PS_MASTER: + flush_last_sync(p); + if (p->altMaster) { + port_set_delay_tmo(p); + } case PS_GRAND_MASTER: if (!p->inhibit_announce) { set_tmo_log(p->fda.fd[FD_MANNO_TIMER], 1, -10); /*~1ms*/ @@ -2629,6 +2694,7 @@ static void port_p2p_transition(struct port *p, enum port_state next) port_set_qualification_tmo(p); break; case PS_MASTER: + flush_last_sync(p); case PS_GRAND_MASTER: if (!p->inhibit_announce) { set_tmo_log(p->fda.fd[FD_MANNO_TIMER], 1, -10); /*~1ms*/ diff --git a/port_private.h b/port_private.h index d27dceb..d74c59d 100644 --- a/port_private.h +++ b/port_private.h @@ -126,6 +126,7 @@ struct port { Integer8 operLogPdelayReqInterval; Integer8 logPdelayReqInterval; UInteger32 neighborPropDelayThresh; + UInteger8 altMaster; int follow_up_info; int freq_est_interval; int hybrid_e2e; -- 2.25.1 _______________________________________________ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel