Commit 36accb7e authored by Jean-Claude BAU's avatar Jean-Claude BAU

[Issue:#196] WR time not set properly in GM mode

The WR time is set in GM mode as follow :
1/ At startup the NTP time is set using wr_date script
2/ PPSi calls the tool wr_date with parameters "set host". It will be
called every time it detects a PLL transition from UNLOCKED to LOCKED
state. Also PPSi provide a error counter 'gmUnlockErr' which gives the
number of time the PLL unlocked.
3/ Parameters "-v set host" in wr_date tool, set only the second part of
the WR time. The time is set in a middle of two WR seconds ticks.
parent 4da70724
......@@ -40,6 +40,25 @@ struct unix_arch_data {
struct timeval tv;
};
#define WRH_GLOBAL_ARCH(ppg) ((wrs_arch_data *)(ppg->arch_data))
typedef struct wrs_arch_data_t {
struct unix_arch_data unix_data; // Must be kept at first position
wrh_timing_mode_locking_state_t timingModeLockingState; /* Locking state for PLL */
wrh_timing_mode_t timingMode; /* Timing mode: Grand master, Free running,...*/
int gmUnlockErr; /* Error counter: Give the number of time the PLL was unlocked in GM mode */
}wrs_arch_data_t;
static inline wrs_arch_data_t *WRS_ARCH_I(struct pp_instance *ppi)
{
return (wrs_arch_data_t *) GLBS(ppi)->arch_data;
}
static inline wrs_arch_data_t *WRS_ARCH_G(struct pp_globals *ppg)
{
return (wrs_arch_data_t *) ppg->arch_data;
}
extern void wrs_main_loop(struct pp_globals *ppg);
extern void wrs_init_ipcserver(struct minipc_ch *ppsi_ch);
......@@ -62,9 +81,8 @@ int wrs_adjust_in_progress(void);
int wrs_adjust_counters(int64_t adjust_sec, int32_t adjust_nsec);
int wrs_adjust_phase(int32_t phase_ps);
int wrs_enable_timing_output(struct pp_globals *,int enable);
timing_mode_t wrs_get_timing_mode(struct pp_globals *);
timing_mode_state_t wrs_get_timing_mode_state(struct pp_globals *);
int wrs_set_timing_mode(struct pp_globals *,timing_mode_t tm);
timing_mode_t wrs_get_timing_mode(struct pp_globals *ppg);
int wrs_get_timing_mode(struct pp_globals *, wrh_timing_mode_t *tm);
int wrs_get_timing_mode_state(struct pp_globals *,wrh_timing_mode_pll_state_t *state);
int wrs_set_timing_mode(struct pp_globals *,wrh_timing_mode_t tm);
int wrs_update_port_info(struct pp_globals *ppg);
......@@ -36,6 +36,8 @@ static unsigned int run_all_state_machines(struct pp_globals *ppg)
if ( portInfoTmoIdx==-1) {
portInfoTmoIdx=pp_gtimeout_get_timer(ppg, "SEND_PORT_INFO", TO_RAND_NONE, 0);
pp_gtimeout_set(ppg,portInfoTmoIdx,2000); // Update interface info every 2 seconds
pp_gtimeout_set(ppg, PP_TO_BMC,TMO_DEFAULT_BMCA_MS);
bmc_update_clock_quality(ppg);// Update clock quality before any call to the state machine
}
for (j = 0; j < ppg->nlinks; j++) {
......@@ -113,9 +115,34 @@ static unsigned int run_all_state_machines(struct pp_globals *ppg)
/* BMCA must run at least once per announce interval 9.2.6.8 */
if (pp_gtimeout(ppg, PP_TO_BMC)) {
wrh_timing_mode_pll_state_t pllState;
bmc_calculate_ebest(ppg); /* Calculation of erbest, ebest ,... */
pp_gtimeout_set(ppg, PP_TO_BMC,TMO_DEFAULT_BMCA_MS);
pp_gtimeout_reset(ppg, PP_TO_BMC);
delay_ms=0;
if ( WRH_OPER()->get_timing_mode_state(ppg,&pllState)>=0 ) {
// Check the PLL for grand master
if ( WRS_ARCH_G(ppg)->timingMode==WRH_TM_GRAND_MASTER && pllState==WRH_TM_PLL_STATE_LOCKED ) {
// GM Locked
if ( WRS_ARCH_G(ppg)->timingModeLockingState==WRH_TM_LOCKING_STATE_LOCKING ||
WRS_ARCH_G(ppg)->timingModeLockingState==WRH_TM_LOCKING_STATE_ERROR) {
// Was not locked before
TOPS(INST(ppg,0))->set(INST(ppg,0),NULL); // GM locked: set the time
}
}
// Update timingModeLockingState field
if (pllState==WRH_TM_PLL_STATE_LOCKED) {
WRS_ARCH_G(ppg)->timingModeLockingState=WRH_TM_LOCKING_STATE_LOCKED;
} else if ( pllState==WRH_TM_PLL_STATE_UNLOCKED ) {
if ( WRS_ARCH_G(ppg)->timingModeLockingState==WRH_TM_LOCKING_STATE_LOCKED ) {
// Was locked before
WRS_ARCH_G(ppg)->timingModeLockingState=WRH_TM_LOCKING_STATE_ERROR;
if (WRS_ARCH_G(ppg)->timingMode==WRH_TM_GRAND_MASTER)
WRS_ARCH_G(ppg)->gmUnlockErr++;
}
}
}
} else {
/* check if the BMC timeout is the next to run */
int delay_bmca;
......
......@@ -118,7 +118,6 @@ static char *strCodeOpt="CODEOPT=("
int main(int argc, char **argv)
{
struct pp_globals *ppg;
struct pp_instance *ppi;
unsigned long seed;
struct timex t;
int i, hal_retries;
......@@ -227,10 +226,9 @@ int main(int argc, char **argv)
ppg->max_links = PP_MAX_LINKS;
/* NOTE: arch_data is not in shmem */
ppg->arch_data = malloc( sizeof(struct unix_arch_data));
ppg->arch_data = wrs_shm_alloc(ppsi_head, sizeof(wrs_arch_data_t));
ppg->pp_instances = wrs_shm_alloc(ppsi_head,
ppg->max_links * sizeof(*ppi));
ppg->max_links * sizeof(struct pp_instance));
if ((!ppg->arch_data) || (!ppg->pp_instances)) {
fprintf(stderr, "ppsi: out of memory\n");
......@@ -276,7 +274,8 @@ int main(int argc, char **argv)
}
}
for (i = 0; i < ppg->nlinks; i++) {
ppi = INST(ppg, i);
struct pp_instance *ppi= INST(ppg, i);
ppi->ch[PP_NP_EVT].fd = -1;
ppi->ch[PP_NP_GEN].fd = -1;
......@@ -383,28 +382,32 @@ int main(int argc, char **argv)
pp_init_globals(ppg, &__pp_default_rt_opts);
{
timing_mode_t prev_timing_mode=WRH_OPER()->get_timing_mode(ppg);
int nbRetry;
int enablePPS;
wrh_timing_mode_pll_state_t timing_mode_pll_state;
struct pp_instance *ppi=INST(ppg,0);
wrh_timing_mode_t prev_timing_mode;
int ret=WRH_OPER()->get_timing_mode(ppg,&prev_timing_mode);
if (ret<0) {
fprintf(stderr, "ppsi: Cannot get current timing mode\n");
exit(1);
}
ppg->timingModeLockingState=TM_LOCKING_STATE_LOCKING;
WRS_ARCH_G(ppg)->timingModeLockingState=WRH_TM_LOCKING_STATE_LOCKING;
if ( ppg->defaultDS->clockQuality.clockClass == PP_PTP_CLASS_GM_LOCKED ) {
if (prev_timing_mode==-1) {
fprintf(stderr, "ppsi: Cannot get current timing mode\n");
exit(1);
}
/* If read timing mode was GM, then we do not reprogram the hardware because it
* may unlock the PLL.
*/
if ( prev_timing_mode != TM_GRAND_MASTER ){
if ( prev_timing_mode != WRH_TM_GRAND_MASTER ){
/* Timing mode was not GM before */
WRH_OPER()->set_timing_mode(ppg,TM_GRAND_MASTER);
WRH_OPER()->set_timing_mode(ppg,WRH_TM_GRAND_MASTER);
} else
ppg->timingMode=TM_GRAND_MASTER; // set here because set_timing_mode() is not called
WRS_ARCH_G(ppg)->timingMode=WRH_TM_GRAND_MASTER; // set here because set_timing_mode() is not called
} else {
/* Timing mode will be set to BC when a port will become slave */
WRH_OPER()->set_timing_mode(ppg,TM_FREE_MASTER);
WRH_OPER()->set_timing_mode(ppg,WRH_TM_FREE_MASTER);
}
/* Waiting for PLL locking. We do not need a precise time-out here */
/* We are waiting up to 3s for PLL locking.
......@@ -412,11 +415,18 @@ int main(int argc, char **argv)
*/
nbRetry=2;
while(nbRetry>0) {
if ( WRH_OPER()->get_timing_mode_state(ppg)==PP_TIMING_MODE_STATE_LOCKED )
ret=WRH_OPER()->get_timing_mode_state(ppg,&timing_mode_pll_state);
if ( ret==0 && timing_mode_pll_state==WRH_TM_PLL_STATE_LOCKED )
break;
sleep(1); // wait 1s
nbRetry--;
}
if ( timing_mode_pll_state==WRH_TM_PLL_STATE_UNLOCKED) {
WRS_ARCH_G(ppg)->timingModeLockingState = WRH_TM_LOCKING_STATE_LOCKING;
} else if (timing_mode_pll_state==WRH_TM_PLL_STATE_LOCKED) {
TOPS(ppi)->set(ppi,NULL); // GM locked: set the time
WRS_ARCH_G(ppg)->timingModeLockingState = WRH_TM_LOCKING_STATE_LOCKED;
}
/* Enable the PPS generation only if
* - Grand master and PLL is locked
......@@ -425,7 +435,8 @@ int main(int argc, char **argv)
* OR
* - Timing output is forced (for testing only)
*/
enablePPS=(ppg->timingModeLockingState== TM_LOCKING_STATE_LOCKED && ppg->defaultDS->clockQuality.clockClass == PP_PTP_CLASS_GM_LOCKED) ||
enablePPS=(WRS_ARCH_G(ppg)->timingModeLockingState== WRH_TM_LOCKING_STATE_LOCKED &&
ppg->defaultDS->clockQuality.clockClass == PP_PTP_CLASS_GM_LOCKED) ||
( ppg->defaultDS->clockQuality.clockClass == PP_PTP_CLASS_GM_UNLOCKED ||
GOPTS(ppg)->forcePpsGen);
TOPS(ppi)->enable_timing_output(ppg,enablePPS);
......
......@@ -33,6 +33,29 @@
#define FIX_ALPHA_FRACBITS 40
#define FIX_ALPHA_FRACBITS_AS_FLOAT 40.0
typedef enum {
WRH_TM_LOCKING_STATE_NONE=0,
WRH_TM_LOCKING_STATE_LOCKING,
WRH_TM_LOCKING_STATE_LOCKED,
WRH_TM_LOCKING_STATE_HOLDOVER,
WRH_TM_LOCKING_STATE_ERROR
}wrh_timing_mode_locking_state_t;
typedef enum {
WRH_TM_PLL_STATE_LOCKED,
WRH_TM_PLL_STATE_UNLOCKED,
WRH_TM_PLL_STATE_HOLDOVER
}wrh_timing_mode_pll_state_t;
typedef enum {
WRH_TM_GRAND_MASTER=0,
WRH_TM_FREE_MASTER,
WRH_TM_BOUNDARY_CLOCK,
WRH_TM_DISABLED
}wrh_timing_mode_t;
#define WRH_SERVO_OFFSET_STABILITY_THRESHOLD 60 /* psec */
/* White Rabbit hw-dependent functions (code in arch-wrpc and arch-wrs) */
......@@ -50,10 +73,9 @@ struct wrh_operations {
int (*read_calib_data)(struct pp_instance *ppi,int32_t *clock_period, TimeInterval *scaledBitSlide,
RelativeDifference *scaledDelayCoefficient,
TimeInterval *scaledSfpDeltaTx, TimeInterval *scaledSfpDeltaRx);
int (*enable_timing_output)(struct pp_globals *,int enable);
timing_mode_t (*get_timing_mode)(struct pp_globals *);
timing_mode_state_t (*get_timing_mode_state)(struct pp_globals *);
int (*set_timing_mode)(struct pp_globals *, timing_mode_t tm);
int (*get_timing_mode)(struct pp_globals *,wrh_timing_mode_t *state);
int (*get_timing_mode_state)(struct pp_globals *, wrh_timing_mode_pll_state_t *state);
int (*set_timing_mode)(struct pp_globals *, wrh_timing_mode_t tm);
};
extern struct wrh_operations wrh_oper;
......@@ -112,7 +134,6 @@ typedef struct wrh_servo_t {
Boolean doRestart; /* PLL is unlocked: A restart of the calibration is needed */
} wrh_servo_t;
static inline wrh_servo_t *WRH_SRV(struct pp_instance *ppi)
{
return (wrh_servo_t *)ppi->ext_data;
......
......@@ -109,22 +109,6 @@
#define PP_FOREIGN_MASTER_THRESHOLD 2
#define PP_DEFAULT_TTL 1
typedef enum {
PP_TIMING_MODE_STATE_ERROR=-1,
PP_TIMING_MODE_STATE_UNLOCKED=0,
PP_TIMING_MODE_STATE_LOCKED,
PP_TIMING_MODE_STATE_HOLDOVER,
PP_TIMING_MODE_STATE_UNKNOWN
}timing_mode_state_t;
typedef enum {
TM_GRAND_MASTER=0,
TM_FREE_MASTER,
TM_BOUNDARY_CLOCK,
TM_DISABLED
}timing_mode_t;
#define PP_ALTERNATE_MASTER_FLAG 1
#define PP_TWO_STEP_FLAG 2
#define PP_VERSION_PTP 2
......
......@@ -294,14 +294,6 @@ struct pp_globals_cfg {
int cur_ppi_n; /* Remember which instance we are configuring */
};
typedef enum {
TM_LOCKING_STATE_NONE=0,
TM_LOCKING_STATE_LOCKING,
TM_LOCKING_STATE_LOCKED,
TM_LOCKING_STATE_HOLDOVER,
TM_LOCKING_STATE_ERROR
}timing_mode_locking_state_t;
/*
* Structure for the multi-port ppsi instance.
*/
......@@ -330,8 +322,6 @@ struct pp_globals {
void *arch_data; /* if arch needs it */
void *global_ext_data; /* if protocol ext needs it */
timing_mode_locking_state_t timingModeLockingState; /* Locking state for PLL */
timing_mode_t timingMode; /* Timing mode: Grand master, Free running,...*/
/* FIXME Here include all is common to many interfaces */
};
......
......@@ -242,6 +242,12 @@ extern struct pp_network_operations DEFAULT_NET_OPS;
/* These can be liked and used as fallback by a different timing engine */
extern struct pp_network_operations unix_net_ops;
typedef enum {
PP_TIMING_MODE_STATE_UNLOCKED=0,
PP_TIMING_MODE_STATE_HOLDOVER,
PP_TIMING_MODE_STATE_LOCKED,
}pp_timing_mode_state_t;
/*
* Time operations, like network operations above, are encapsulated.
* They may live in their own time-<name> subdirectory.
......@@ -260,7 +266,7 @@ struct pp_time_operations {
int (*adjust_freq)(struct pp_instance *ppi, long freq_ppb);
int (*init_servo)(struct pp_instance *ppi);
unsigned long (*calc_timeout)(struct pp_instance *ppi, int millisec);
int (*get_GM_locked_state)(struct pp_globals *ppg, pp_timing_mode_state_t *locked);
int (*get_GM_lock_state)(struct pp_globals *ppg, pp_timing_mode_state_t *state);
int (*enable_timing_output)(struct pp_globals *ppg,int enable);
};
......@@ -332,6 +338,7 @@ extern void bmc_add_frgn_master(struct pp_instance *ppi, struct pp_frgn_master *
extern void bmc_flush_erbest(struct pp_instance *ppi);
extern void bmc_calculate_ebest(struct pp_globals *ppg);
extern int bmc_apply_state_descision(struct pp_instance *ppi);
extern void bmc_update_clock_quality(struct pp_globals *ppg);
/* msg.c */
extern void msg_init_header(struct pp_instance *ppi, void *buf);
......
......@@ -319,7 +319,7 @@ static int __wrh_servo_update(struct pp_instance *ppi)
/* ts_to_picos() below returns phase alone */
remaining_offset = abs(pp_time_to_picos(&offsetMS));
if(remaining_offset < WRH_SERVO_OFFSET_STABILITY_THRESHOLD) {
WRH_OPER()->enable_timing_output(GLBS(ppi),1);
TOPS(ppi)->enable_timing_output(GLBS(ppi),1);
s->prev_delayMS_ps = s->delayMS_ps;
gs->state = WRH_TRACK_PHASE;
} else {
......
......@@ -1316,16 +1316,16 @@ static void bmc_update_ebest(struct pp_globals *ppg)
}
static void bmc_update_clock_quality(struct pp_globals *ppg)
void bmc_update_clock_quality(struct pp_globals *ppg)
{
char *pp_diag_msg;
struct pp_runtime_opts *rt_opts = ppg->rt_opts;
int rt_opts_clock_quality_clockClass=rt_opts->clock_quality_clockClass;
int defaultDS_clock_quality_clockClass=ppg->defaultDS->clockQuality.clockClass;
timing_mode_state_t timing_mode_state;
pp_timing_mode_state_t timing_mode_state;
static struct oper_t {
timing_mode_state_t timing_mode_state;
pp_timing_mode_state_t timing_mode_state;
int reqClockQuality;
ClockQuality clockQuality;
char *msg;
......@@ -1394,10 +1394,7 @@ static void bmc_update_clock_quality(struct pp_globals *ppg)
}
};
// Called here because get_timing_mode_state() updates timingModeLockingState field in pp_globals
timing_mode_state=WRH_OPER()->get_timing_mode_state(ppg);
if (rt_opts_clock_quality_clockClass >= 128)
if (rt_opts_clock_quality_clockClass >= 128)
return;
if ((rt_opts_clock_quality_clockClass == PP_PTP_CLASS_GM_LOCKED) ||
......@@ -1416,9 +1413,9 @@ static void bmc_update_clock_quality(struct pp_globals *ppg)
return;
}
if (timing_mode_state==PP_TIMING_MODE_STATE_ERROR) {
if (TOPS(INST(ppg,0))->get_GM_lock_state(ppg,&timing_mode_state) ) {
pp_diag(NULL, bmc, 1,
"Could not get timing mode locking state, taking old clock class: %i\n",
"Could not get GM locking state, taking old clock class: %i\n",
ppg->defaultDS->clockQuality.clockClass);
return;
}
......
......@@ -45,33 +45,12 @@ int pp_initializing(struct pp_instance *ppi, void *buf, int len)
int i;
int initds = 1;
Boolean waitGmLocking;
waitGmLocking= ppg->rt_opts->clock_quality_clockClass == PP_PTP_CLASS_GM_LOCKED &&
(ppg->timingModeLockingState == TM_LOCKING_STATE_LOCKING ||
ppg->timingModeLockingState == TM_LOCKING_STATE_ERROR);
if (waitGmLocking) {
/* Waiting for GM locking */
if ( ppi->is_new_state ) {
/* Init time-out for next calls : Wait 2 x the BMCA tmo */
pp_timeout_set(ppi,PP_TO_IN_STATE,TMO_DEFAULT_BMCA_MS<<1);
}else {
if ( pp_timeout(ppi,PP_TO_IN_STATE)) {
/* At this point, the BMCA already run. We can check the clockClass */
if ( DSDEF(ppi)->clockQuality.clockClass == PP_PTP_CLASS_GM_LOCKED) {
waitGmLocking=FALSE;
pp_timeout_disable(ppi,PP_TO_IN_STATE);
}
else {
pp_timeout_reset(ppi,PP_TO_IN_STATE);
goto failure;
}
} else
goto failure;
}
}
if ( ppg->rt_opts->clock_quality_clockClass == PP_PTP_CLASS_GM_LOCKED &&
DSDEF(ppi)->clockQuality.clockClass != PP_PTP_CLASS_GM_LOCKED) {
// GM not locked
goto failure;
}
if (ppi->n_ops->init(ppi) < 0) /* it must handle being called twice */
goto failure;
......@@ -157,12 +136,6 @@ int pp_initializing(struct pp_instance *ppi, void *buf, int len)
msg_init_header(ppi, ppi->tx_ptp); /* This is used for all tx */
if ( waitGmLocking ) {
/* must leave the BMC running before to check next time the clockClass */
ppi->next_delay = pp_gtimeout_get(ppg,PP_TO_BMC) << 1; /* wait 2 x BMCA tmo */
return 0;
}
if (is_externalPortConfigurationEnabled(DSDEF(ppi))) {
/* Clause 17.6.5.2 : the member portDS.portState shall be set to
* the value of the member externalPortConfigurationPortDS.desiredState
......
......@@ -501,7 +501,7 @@ static int wrs_net_send(struct pp_instance *ppi, void *pkt, int len,enum pp_msg_
memcpy(hdr->h_source, ch->addr, ETH_ALEN);
if (t)
ppi->t_ops->get(ppi, t);
TOPS(ppi)->get(ppi, t);
ret = send(ch->fd, hdr, len, 0);
if (ret < 0) {
......@@ -532,7 +532,7 @@ static int wrs_net_send(struct pp_instance *ppi, void *pkt, int len,enum pp_msg_
memcpy(vhdr->h_source, ch->addr, ETH_ALEN);
if (t)
ppi->t_ops->get(ppi, t);
TOPS(ppi)->get(ppi, t);
if (len < 64)
len = 64;
......
This diff is collapsed.
......@@ -307,6 +307,16 @@ struct dump_info wr_ext_portDS_info [] = {
};
#endif
#if CONFIG_ARCH_IS_WRS
#undef DUMP_STRUCT
#define DUMP_STRUCT struct wrs_arch_data_t
struct dump_info wrs_arch_data_info [] = {
DUMP_FIELD(int,timingMode),
DUMP_FIELD(int,timingModeLockingState),
DUMP_FIELD(int,gmUnlockErr)
};
#endif
int dump_ppsi_mem(struct wrs_shm_head *head)
{
struct pp_globals *ppg;
......@@ -338,6 +348,14 @@ int dump_ppsi_mem(struct wrs_shm_head *head)
dstp = wrs_shm_follow(head, ppg->timePropertiesDS);
dump_many_fields(dstp, dstp_info, ARRAY_SIZE(dstp_info),"ppsi.timePropertiesDS");
#if CONFIG_ARCH_IS_WRS
{
wrs_arch_data_t *arch_data=wrs_shm_follow(head, WRS_ARCH_G(ppg));
dump_many_fields(arch_data, wrs_arch_data_info, ARRAY_SIZE(wrs_arch_data_info),"ppsi.arch_data");
}
#endif
pp_instances = wrs_shm_follow(head, ppg->pp_instances);
/* print extension servo data set */
for (i = 0; i < ppg->nlinks; i++) {
......
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