Commit 39244edb authored by Jean-Claude BAU's avatar Jean-Claude BAU

WR extension: Change how a new parent is detected

The detection of a new parent has been moved in a call back of the S1
treatment. The previous implementation had some side effect due to the
fact that the detection was coming too late in some cases (pb with
erbest calculation)

The doRestart called by the servo is now extension specific. It help to
make a more cleaner restart.
parent 591ece89
......@@ -159,6 +159,7 @@ typedef struct MsgAnnounce {
ClockIdentity grandmasterIdentity;
UInteger16 stepsRemoved;
Enumeration8 timeSource;
UInteger16 ext_specific[4]; /* Extension specific. Must be UInteger16 to align it in the structure*/
} MsgAnnounce;
/* Sync Message (table 26, page 129) */
......
......@@ -94,7 +94,7 @@ struct pp_frgn_master {
Boolean qualified; // TRUE if qualified
unsigned long lastAnnounceMsgMs; // Last time in ms when the announce message was received
/* used by extension */
unsigned long ext_specific;
UInteger16 ext_specific[4]; /* Extension specific. Must be UInteger16 to align it in the structure*/
};
/*
......
......@@ -227,6 +227,8 @@ struct pp_ext_hooks {
int (*require_precise_timestamp)(struct pp_instance *ppi);
int (*get_tmo_lstate_detection) (struct pp_instance *ppi);
int (*extension_state_changed)(struct pp_instance *ppi); /* Called when extension state as changed */
int (*bmca_s1)(struct pp_instance *ppi,
struct pp_frgn_master *frgn_master); /* Called at the end of the S1 treatment in the BMCA */
};
#define is_ext_hook_available(p, c) ( /*p->ext_enabled && */ p->ext_hooks->c)
......
......@@ -14,11 +14,14 @@ void wr_reset_process(struct pp_instance *ppi, wr_role_t role) {
wrp->wrMode = role;
wrp->wrModeOn=FALSE;
wrp->calibrated = !WR_DEFAULT_PHY_CALIBRATION_REQUIRED;
/* Reset parent data */
wrp->parentWrConfig = NON_WR;
wrp->parentIsWRnode =
wrp->parentWrModeOn =
wrp->parentCalibrated = FALSE;
if ( role != WR_SLAVE ) {
/* Reset parent data */
/* For a SLAVE, these info are updated when an Announce message is received */
wrp->parentWrConfig = NON_WR;
wrp->parentIsWRnode =
wrp->parentWrModeOn =
wrp->parentCalibrated = FALSE;
}
}
/* The handshake failed: go master or slave in normal PTP mode */
......
......@@ -2,8 +2,30 @@
/* ext-whiterabbit must offer its own hooks */
// Used to store data in the ext_specific field of the pp_frgn_master an MsgAnnounce structure
// This structure must not exceed the size of an 'MsgAnnounce.ext_specific'
typedef struct {
UInteger16 notTreated; /* The WR flags must be treated only one time */
UInteger16 wrFlags;
}wr_announce_field_t;
int wrTmoIdx=0; /* TimeOut Index */
#if 0
// Useful function used for debugging
#include <stdio.h>
static char * getPortIdentityAsString ( PortIdentity *pid, UInteger16 seqId) {
static char text[52];
sprintf(text,"%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x %04x %d",
pid->clockIdentity.id[0], pid->clockIdentity.id[1],
pid->clockIdentity.id[2], pid->clockIdentity.id[3],
pid->clockIdentity.id[4], pid->clockIdentity.id[5],
pid->clockIdentity.id[6], pid->clockIdentity.id[7],
pid->portNumber, seqId);
return text;
}
#endif
static int wr_init(struct pp_instance *ppi, void *buf, int len)
{
pp_diag(ppi, ext, 2, "hook: %s\n", __func__);
......@@ -121,87 +143,95 @@ static int wr_pack_announce(struct pp_instance *ppi)
static void wr_unpack_announce(struct pp_instance *ppi,void *buf, MsgAnnounce *ann)
{
MsgHeader *hdr = &ppi->received_ptp_header;
int msg_len = ntohs(*(UInteger16 *) (buf + 2));
Boolean parentIsWRnode=FALSE;
Boolean resetWrProtocol=FALSE;
int slaveUncalState=ppi->state==PPS_UNCALIBRATED || ppi->state==PPS_SLAVE;
struct wr_dsport *wrp = WR_DSPOR(ppi);
wr_announce_field_t *wrExtSpec=(wr_announce_field_t *)&ann->ext_specific[0];
pp_diag(NULL, ext, 2, "hook: %s\n", __func__);
pp_diag(ppi, ext, 2, "hook: %s\n", __func__);
UInteger16 wr_flags=0;
// If the message is not coming from erbest, it must be discarded
if ( !bmc_is_erbest(ppi,&hdr->sourcePortIdentity))
return;
if ( msg_len >= WR_ANNOUNCE_LENGTH )
msg_unpack_announce_wr_tlv(buf, ann, &wr_flags);
wrExtSpec->notTreated=TRUE;
wrExtSpec->wrFlags=wr_flags;
}
if (msg_len >= WR_ANNOUNCE_LENGTH) {
UInteger16 wr_flags;
MsgHeader *hdr = &ppi->received_ptp_header;
struct PortIdentity *pid = &hdr->sourcePortIdentity;
// Called by S1 treatment (BMCA or slave state)
// Assumptions when this hook is called
// - State= Slave or Uncalibrated
// - frgn_master passed in parameter is the erBest
// - WR data field of the announce message is stored in the field ext_specific of the frgn_master
msg_unpack_announce_wr_tlv(buf, ann, &wr_flags);
parentIsWRnode=(wr_flags & WR_NODE_MODE)!=NON_WR;
// Check if a new parent is detected.
// This part is needed to cover the following use case :
// on the master side, the WR extension is disabled (WR calibration failure or PTP profile selected)
// then the PPSi process is restarted using the WR profile. On the slave side, if the timeout ANN_RECEIPT has not fired,
// we must detect that the PPSi process has been restarted and then replay the calibration protocol.
// Checked parameters :
// - The parent is a WR node
// - ptp state=(slave|uncalibrated|listening)
// - Same parent port ID but with a not continuous sequence ID (With a margin of 1)
// - The port identity is different
if ( parentIsWRnode &&
(slaveUncalState || ppi->state==PPS_LISTENING)) {
Boolean samePid=!bmc_pidcmp(pid, &wrp->parentAnnPortIdentity);
if ( !samePid ||
(samePid &&
(hdr->sequenceId!=(UInteger16) (wrp->parentAnnSequenceId+1) &&
hdr->sequenceId!=(UInteger16) (wrp->parentAnnSequenceId+2))
)) {
/* For other states, it is done in the state_change hook */
resetWrProtocol=slaveUncalState;
pdstate_enable_extension(ppi);
static int wr_bmca_s1( struct pp_instance * ppi,
struct pp_frgn_master *frgn_master) {
struct wr_dsport *wrp = WR_DSPOR(ppi);
Boolean newParentDectected;
pp_diag(ppi, ext, 2, "hook: %s\n", __func__);
wr_announce_field_t *wrExtSpec=(wr_announce_field_t *)frgn_master->ext_specific;
if ( wrExtSpec->notTreated ) {
wrh_servo_t *s=WRH_SRV(ppi);
UInteger16 wr_flags=wrExtSpec->wrFlags;
Boolean parentIsWRnode=(wr_flags & WR_NODE_MODE)!=NON_WR;
int samePid=0;
Boolean contSeqId=FALSE;
if ( !s->doRestart ) {
samePid= bmc_pidcmp(&frgn_master->receivePortIdentity, &wrp->parentAnnPortIdentity)==0;
if (samePid ) {
// We check for a continuous sequence ID (With a margin of 1)
contSeqId=frgn_master->sequenceId==(UInteger16) (wrp->parentAnnSequenceId+1) ||
frgn_master->sequenceId==(UInteger16) (wrp->parentAnnSequenceId+2);
}
newParentDectected = !samePid ||(samePid && !contSeqId);
} else {
parentIsWRnode=FALSE;
resetWrProtocol=ppi->extState==PP_EXSTATE_ACTIVE && slaveUncalState;
// Force a restart - simulate a new parent
s->doRestart=FALSE;
newParentDectected=TRUE;
}
memcpy(&wrp->parentAnnPortIdentity,pid,sizeof(struct PortIdentity));
wrp->parentAnnSequenceId=hdr->sequenceId;
if ( parentIsWRnode ) {
// Announce message from a WR node
if ( newParentDectected && wrp->parentDetection!=PD_WR_PARENT ) {
// New WR parent detected - keep only wrConfig part
wr_flags&=WR_NODE_MODE;
/* Update the WR parent state */
if ( !parentIsWRnode )
/* Not a WR node */
wr_flags=0; /* Forget all bits. They are not relevant */
wrp->parentIsWRnode = parentIsWRnode;
// Check if parent is WR Master-enabled
if ( wr_flags==WR_MASTER || wr_flags==WR_M_AND_S ) {
wrp->parentDetection=PD_WR_PARENT;
}
}
} else {
if ( newParentDectected && wrp->parentDetection!=PD_NOT_WR_PARENT ) {
wrp->parentDetection=PD_NOT_WR_PARENT;
}
wr_flags=0;
}
// Update WR parent flags
wrp->parentIsWRnode = (wr_flags & WR_NODE_MODE)==NON_WR;
wrp->parentWrModeOn = (wr_flags & WR_IS_WR_MODE) != 0;
wrp->parentCalibrated =(wr_flags & WR_IS_CALIBRATED) != 0;
wrp->parentWrConfig = wr_flags & WR_NODE_MODE;
} else {
resetWrProtocol=ppi->extState==PP_EXSTATE_ACTIVE && slaveUncalState;
}
if ( resetWrProtocol ) {
ppi->next_state=PPS_UNCALIBRATED;
wrp->next_state=WRS_PRESENT;
wrp->wrMode=WR_SLAVE;
// Save parent identity and the sequence Id to be used next time
memcpy(&wrp->parentAnnPortIdentity,&frgn_master->receivePortIdentity,sizeof(PortIdentity));
wrp->parentAnnSequenceId=frgn_master->sequenceId;
wrExtSpec->notTreated=0;
}
return 0;
}
static void wr_state_change(struct pp_instance *ppi)
{
struct wr_dsport *wrp = WR_DSPOR(ppi);
pp_diag(ppi, ext, 2, "hook: %s\n", __func__);
if ( ppi->extState==PP_EXSTATE_PTP && ppi->next_state==PPS_UNCALIBRATED ) {
// Extension need to be re-enabled
pdstate_enable_extension(ppi);
}
if ( ppi->extState==PP_EXSTATE_ACTIVE ) {
......@@ -220,8 +250,19 @@ static void wr_state_change(struct pp_instance *ppi)
wr_reset_process(ppi,WR_MASTER);
break;
case PPS_UNCALIBRATED : /* Enter in UNCALIBRATED state */
wrp->next_state=WRS_PRESENT;
wr_reset_process(ppi,WR_SLAVE);
if ( ppi->state == PPS_SLAVE ) {
// This part must be done if doRestart() is called in the servo
if ( wrp->parentWrConfig==WR_MASTER || wrp->parentWrConfig==WR_M_AND_S ) {
wrp->next_state=WRS_PRESENT;
wr_reset_process(ppi,WR_SLAVE);
}
} else {
// This force the transition from UNCALIBRATED to SLAVE at startup if
// no parent is detected.
if ( !(wrp->parentWrConfig==WR_MASTER || wrp->parentWrConfig==WR_M_AND_S) ) {
wr_handshake_fail(ppi);
}
}
break;
case PPS_LISTENING : /* Enter in LISTENING state */
wr_reset_process(ppi,WR_ROLE_NONE);
......@@ -307,5 +348,6 @@ struct pp_ext_hooks wr_ext_hooks = {
.get_ingress_latency=wr_get_latency,
.get_egress_latency=wr_get_latency,
.is_correction_field_compliant=wr_is_correction_field_compliant,
.extension_state_changed= wr_extension_state_changed
.extension_state_changed= wr_extension_state_changed,
.bmca_s1=wr_bmca_s1
};
......@@ -35,12 +35,35 @@ int wr_idle(struct pp_instance *ppi, void *buf, int len, int new_state)
}
}
} else {
if ( ppi->extState==PP_EXSTATE_ACTIVE && ppi->state==PPS_SLAVE ) {
if ( !(wrp->wrModeOn && wrp->parentWrModeOn) ) {
/* Failure detected in the protocol */
if ( wrp->parentDetection==PD_WR_PARENT ) {
// New WR parent detected
if ( ppi->extState==PP_EXSTATE_PTP) {
pp_diag(ppi, ext, 1, "%s: WR extension enabled.\n",__FUNCTION__);
pdstate_enable_extension(ppi);
}
if ( ppi->extState==PP_EXSTATE_ACTIVE ) {
if ( wrp->state == WRS_IDLE ) {
if ( ppi->state==PPS_SLAVE) {
ppi->next_state=PPS_UNCALIBRATED;
}
wr_reset_process(ppi,WR_SLAVE);
wrp->next_state=WRS_PRESENT;
wrp->parentDetection=PD_NO_DETECTION;
}
} else {
wrp->parentDetection=PD_NO_DETECTION;
}
return 0;
}
else if ( wrp->parentDetection==PD_NOT_WR_PARENT ) {
if ( ppi->extState==PP_EXSTATE_ACTIVE ) {
pp_diag(ppi, ext, 1, "%s: WR extension disabled.\n",__FUNCTION__);
pdstate_disable_extension(ppi);
}
if ( ppi->state==PPS_SLAVE) {
ppi->next_state=PPS_UNCALIBRATED;
wr_reset_process(ppi,WR_ROLE_NONE);
}
wrp->parentDetection=PD_NO_DETECTION;
}
}
......
......@@ -17,6 +17,12 @@
#include "../include/hw-specific/wrh.h"
#include "wr-constants.h"
typedef enum {
PD_NO_DETECTION=0, //No new parent detected
PD_WR_PARENT, // WR parent detected
PD_NOT_WR_PARENT // Not a WR parent detected
}ParentDetection;
/*
* This structure is used as extension-specific data in the DSPort
* (see wrspec.v2-06-07-2011, page 17)
......@@ -52,6 +58,7 @@ struct wr_dsport {
struct PortIdentity parentAnnPortIdentity; /* Last received announce message port identity */
UInteger16 parentAnnSequenceId; /* Last received sequence did in the parent announce message */
ParentDetection parentDetection; /* Indicates that a new parent has been detected */
};
/* This uppercase name matches "DSPOR(ppi)" used by standard protocol */
......
......@@ -24,16 +24,7 @@ int wr_servo_init(struct pp_instance *ppi)
int wr_servo_got_sync(struct pp_instance *ppi) {
/* Re-adjust T1 and T2 */
wr_servo_ext_t *se=WRE_SRV(ppi);
wrh_servo_t *s=WRH_SRV(ppi);
if (s->doRestart) {
// Error detected by the servo.
s->doRestart=FALSE;
if ( ppi->state==PPS_SLAVE ) {
// Restart calibration
ppi->next_state=PPS_UNCALIBRATED;
}
}
pp_time_add(&ppi->t1,&se->delta_txm);
pp_time_sub(&ppi->t2,&se->delta_rxs);
return wrh_servo_got_sync(ppi);
......
......@@ -280,6 +280,9 @@ void bmc_s1(struct pp_instance *ppi,
/* Disable timer (if needed) used to go to GM by BMCA */
pp_gtimeout_disable(GLBS(ppi),PP_TO_GM_BY_BMCA);
if (is_ext_hook_available(ppi,bmca_s1))
ppi->ext_hooks->bmca_s1(ppi,frgn_master);
}
void bmc_p1(struct pp_instance *ppi)
......@@ -323,7 +326,7 @@ static void bmc_setup_local_frgn_master(struct pp_instance *ppi,
frgn_master->stepsRemoved = 0;
frgn_master->timeSource = TIME_SRC_INTERNAL_OSCILLATOR; //TODO get this from somewhere
frgn_master->ext_specific = 0;
bzero(frgn_master->ext_specific,sizeof(frgn_master->ext_specific));
}
int bmc_idcmp(struct ClockIdentity *a, struct ClockIdentity *b)
......@@ -858,6 +861,7 @@ void bmc_store_frgn_master(struct pp_instance *ppi,
frgn_master->timeSource = ann.timeSource;
frgn_master->qualified=
frgn_master->lastAnnounceMsgMs=0;
memcpy(frgn_master->ext_specific,ann.ext_specific,sizeof(frgn_master->ext_specific));
}
......
......@@ -261,6 +261,7 @@ void msg_unpack_announce(struct pp_instance *ppi, void *buf, MsgAnnounce *ann)
ann->stepsRemoved = *(UInteger8 *)(buf + 61);
ann->stepsRemoved = (ann->stepsRemoved << 8) + *(UInteger8 *)(buf + 62);
ann->timeSource = *(Enumeration8 *) (buf + 63);
bzero(ann->ext_specific,sizeof(ann->ext_specific));
/* this can fill in extention specific flags otherwise just zero them*/
if (is_ext_hook_available(ppi,unpack_announce))
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment