Commit 0b031b22 authored by baujc's avatar baujc

Review of WR protocol implementation

- It has now its own state table
- The servo is shared with L1Sync extension. It means that servo
calculation is now following the new standard IEEE 1588
- It stay compatible with older versions of the switch. The correction
field value in the exchange messages are still not compliant with the
standard to keep the compatibility.
parent 621c3372
......@@ -84,6 +84,7 @@ endif
ifeq ($(CONFIG_HAS_EXT_L1SYNC),1)
include proto-ext-l1sync/Makefile
endif
include proto-ext-common/Makefile
include proto-standard/Makefile
# ...and the TIME choice sets the default operations
......
D := proto-ext-common
INC_WRH_SERVO=$(shell test ".$(CONFIG_HAS_EXT_WR)" = ".1" -o \
".$(CONFIG_HAS_EXT_L1SYNC)" = ".1" \
&& echo -n "true")
ifeq ($(INC_WRH_SERVO),true)
OBJ-y += $D/wrh-servo.o
endif
/*
* Copyright (C) 2018 CERN (www.cern.ch)
* Author: Jean-Claude BAU & Maciej Lipinski
*
* Released according to the GNU LGPL, version 2.1 or any later version.
*/
#include <stdint.h>
#include <inttypes.h>
#include <ppsi/ppsi.h>
// #include "wrs-constants.h"
#include <libwr/shmem.h>
#include "../proto-standard/common-fun.h"
static const char *wrh_servo_state_name[] = {
[WRH_UNINITIALIZED] = "Uninitialized",
[WRH_SYNC_NSEC] = "SYNC_NSEC",
[WRH_SYNC_TAI] = "SYNC_SEC",
[WRH_SYNC_PHASE] = "SYNC_PHASE",
[WRH_TRACK_PHASE] = "TRACK_PHASE",
[WRH_WAIT_OFFSET_STABLE] = "WAIT_OFFSET_STABLE",
};
/* Enable tracking by default. Disabling the tracking is used for demos. */
static int wrh_tracking_enabled = 1;
/* prototypes */
static int __wrh_servo_update(struct pp_instance *ppi);
/* External data */
extern struct wrs_shm_head *ppsi_head;
extern struct pp_time faulty_stamps[6]; /* if unused, dropped at link time */
void wrh_servo_enable_tracking(int enable)
{
wrh_tracking_enabled = enable;
}
/*
* Update calibration data
*/
int wrh_update_correction_values(struct pp_instance *ppi)
{
wrh_servo_t *s = WRH_SRV(ppi);
pp_diag(ppi, ext, 2, "hook: %s -- ext %i\n", __func__, ppi->protocol_extension);
/* read the interesting values from HW (i.e. HAL)*/
if ( WRH_OPER()->read_calib_data(ppi,&s->clock_period_ps,NULL) != WRH_HW_CALIB_OK){
pp_diag(ppi, ext, 2, "hook: %s -- cannot read calib values\n",
__func__);
return -1;
}
pp_diag(ppi, ext, 2, "ML- Updated correction values: Clock period=%d [ps]\n",
s->clock_period_ps);
return 0;
}
int wrh_servo_init(struct pp_instance *ppi)
{
wrh_servo_t *s=WRH_SRV(ppi);
struct pp_servo *gs=SRV(ppi);
int ret=0;
pp_servo_init(ppi); // Initialize the standard servo data
/* shmem lock */
wrs_shm_write(ppsi_head, WRS_SHM_WRITE_BEGIN);
WRH_SERVO_RESET_DATA(s);
/* Update correction data in data sets*/
if (wrh_update_correction_values(ppi) != -1) {
/*
* Do not reset cur_setpoint, but trim it to be less than one tick.
* The softpll code uses the module anyways, but if we unplug-replug
* the fiber it will always increase, so don't scare the user
*/
if (s->cur_setpoint_ps > s->clock_period_ps)
s->cur_setpoint_ps %= s->clock_period_ps;
pp_diag(ppi, servo, 3, "%s.%d: Adjust_phase: %d\n",__func__,__LINE__,s->cur_setpoint_ps);
WRH_OPER()->adjust_phase(s->cur_setpoint_ps);
strcpy(gs->servo_state_name, wrh_servo_state_name[gs->state]);
gs->flags |= PP_SERVO_FLAG_VALID;
ppi->t_ops->get(ppi, &gs->update_time);
s->tracking_enabled = wrh_tracking_enabled;
gs->state = WRH_SYNC_TAI;
}
/* shmem unlock */
wrs_shm_write(ppsi_head, WRS_SHM_WRITE_END);
return ret;
}
void wrh_servo_reset(struct pp_instance *ppi)
{
if ( ppi->ext_enabled ) {
/* shmem lock */
wrs_shm_write(ppsi_head, WRS_SHM_WRITE_BEGIN);
ppi->flags = 0;
WRH_SERVO_RESET_DATA(WRH_SRV(ppi));
SRV(ppi)->state = WRH_UNINITIALIZED;
/* shmem unlock */
wrs_shm_write(ppsi_head, WRS_SHM_WRITE_END);
}
}
/**
* SYNC/FOLLOW_UP messages have been received: t1/t2 are available
*/
int wrh_servo_got_sync(struct pp_instance *ppi)
{
struct pp_servo *gs=SRV(ppi);
/* shmem lock */
wrs_shm_write(ppsi_head, WRS_SHM_WRITE_BEGIN);
gs->t1=ppi->t1;apply_faulty_stamp(ppi,1);
gs->t2=ppi->t2;apply_faulty_stamp(ppi,2);
if ( is_delayMechanismP2P(ppi) && gs->got_sync) {
gs->got_sync=0;
__wrh_servo_update(ppi);
}else {
gs->got_sync=1;
}
/* shmem unlock */
wrs_shm_write(ppsi_head, WRS_SHM_WRITE_END);
return 0;
}
/**
* DELAY_RESPONSE message has been received: t3/t4 are available
*/
int wrh_servo_got_resp(struct pp_instance *ppi)
{
struct pp_servo *gs=SRV(ppi);
int ret;
static int errcount=0;
if ( !gs->got_sync )
return 0; /* t1 & t2 not available yet */
gs->got_sync=0;
if ( is_timestamps_incorrect(ppi,&errcount,0xC /* mask=t3&t4 */) )
return 0;
wrs_shm_write(ppsi_head, WRS_SHM_WRITE_BEGIN);
gs->t3 = ppi->t3; apply_faulty_stamp(ppi,3);
gs->t4 = ppi->t4; apply_faulty_stamp(ppi,4);
ret=__wrh_servo_update(ppi);
wrs_shm_write(ppsi_head, WRS_SHM_WRITE_END);
return ret;
}
/**
* PDELAY_RESPONSE_FUP message has been received: t3/t4/t5/t6 are available
*/
int wrh_servo_got_presp(struct pp_instance *ppi)
{
struct pp_servo *gs=SRV(ppi);
static int errcount=0;
if ( is_timestamps_incorrect(ppi,&errcount,0x3C /* mask=&t3&t4&t5&t6 */) )
return 0;
wrs_shm_write(ppsi_head, WRS_SHM_WRITE_BEGIN);
gs->t3 = ppi->t3; apply_faulty_stamp(ppi,3);
gs->t4 = ppi->t4; apply_faulty_stamp(ppi,4);
gs->t5 = ppi->t5; apply_faulty_stamp(ppi,5);
gs->t6 = ppi->t6; apply_faulty_stamp(ppi,6);
gs->got_sync=1;
wrs_shm_write(ppsi_head, WRS_SHM_WRITE_END);
return 1;
}
static int __wrh_servo_update(struct pp_instance *ppi)
{
struct pp_servo *gs=SRV(ppi);
wrh_servo_t *s=WRH_SRV(ppi);
int remaining_offset;
int32_t offset_ticks;
int64_t prev_delayMM_ps = 0;
int locking_poll_ret;
struct pp_time offsetMS ;
int32_t offset_ps;
if ( gs->state==WRH_UNINITIALIZED )
return 0;
prev_delayMM_ps = s->delayMM_ps;
if ( !pp_servo_calculate_delays(ppi) )
return 0;
s->delayMM_ps=pp_time_to_picos(&gs->delayMM);
offsetMS=gs->offsetFromMaster;
s->offsetMS_ps=pp_time_to_picos(&offsetMS);
s->tracking_enabled = wrh_tracking_enabled;
// Servo updated
gs->update_count++;
ppi->t_ops->get(ppi, &gs->update_time);
if (!s->readyForSync )
return 1; /* We have to wait before to start the synchronization */
locking_poll_ret = WRH_OPER()->locking_poll(ppi);
if (locking_poll_ret != WRH_SPLL_READY
&& locking_poll_ret != WRH_SPLL_CALIB_NOT_READY) {
pp_diag(ppi, servo, 1, "PLL out of lock\n");
/* TODO check
* DSPOR(ppi)->doRestart = TRUE; */
}
/* After each action on the hardware, we must verify if it is over. */
if (!WRH_OPER()->adjust_in_progress()) {
gs->flags &= ~PP_SERVO_FLAG_WAIT_HW;
} else {
pp_diag(ppi, servo, 1, "servo:busy\n");
return 1;
}
/* So, we didn't return. Choose the right state */
if (offsetMS.secs) {/* so bad... */
gs->state = WRH_SYNC_TAI;
pp_diag(ppi, servo, 2, "offsetMS: %li sec ...\n",
(long)offsetMS.secs);
} else {
pp_time_hardwarize(&offsetMS, s->clock_period_ps,
&offset_ticks, &offset_ps);
pp_diag(ppi, servo, 2, "offsetMS: %li sec %09li ticks (%li ps)\n",
(long)offsetMS.secs, (long)offset_ticks,
(long)offset_ps);
if (offset_ticks) /* not that bad */
gs->state = WRH_SYNC_NSEC;
/* else, let the states below choose the sequence */
}
/* update string state name */
strcpy(gs->servo_state_name, wrh_servo_state_name[gs->state]);
pp_diag(ppi, servo, 1, "wrh_servo state: %s%s\n",
gs->servo_state_name,
gs->flags & PP_SERVO_FLAG_WAIT_HW ? " (wait for hw)" : "");
switch (gs->state) {
case WRH_SYNC_TAI:
WRH_OPER()->adjust_counters(offsetMS.secs, 0);
gs->flags |= PP_SERVO_FLAG_WAIT_HW;
/*
* If nsec wrong, code above forces SYNC_NSEC,
* Else, we must ensure we leave this status towards
* fine tuning
*/
gs->state = WRH_SYNC_PHASE;
break;
case WRH_SYNC_NSEC:
WRH_OPER()->adjust_counters(0, offset_ticks);
gs->flags |= PP_SERVO_FLAG_WAIT_HW;
gs->state = WRH_SYNC_PHASE;
break;
case WRH_SYNC_PHASE:
pp_diag(ppi, servo, 2, "oldsetp %i, offset %i:%04i\n",
s->cur_setpoint_ps, offset_ticks,
offset_ps);
s->cur_setpoint_ps += offset_ps;
pp_diag(ppi, servo, 3, "%s.%d: Adjust_phase: %d\n",__func__,__LINE__,s->cur_setpoint_ps);
WRH_OPER()->adjust_phase(s->cur_setpoint_ps);
gs->flags |= PP_SERVO_FLAG_WAIT_HW;
gs->state = WRH_WAIT_OFFSET_STABLE;
if (CONFIG_ARCH_IS_WRS) {
/*
* Now, let's fix system time. We pass here
* once only, so that's the best place to do
* it. We use current WR time.
* */
struct pp_time t;
ppi->t_ops->get(ppi,&t);
unix_time_ops.set(ppi, &t);
pp_diag(ppi, time, 1, "system time set to %s TAI\n",
time_to_string(&t));
}
break;
case WRH_WAIT_OFFSET_STABLE:
/* 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);
s->prev_delayMS_ps = s->delayMS_ps;
gs->state = WRH_TRACK_PHASE;
} else {
s->missed_iters++;
}
if (s->missed_iters >= 10) {
s->missed_iters = 0;
gs->state = WRH_SYNC_PHASE;
}
break;
case WRH_TRACK_PHASE:
s->skew_ps = s->delayMS_ps - s->prev_delayMS_ps;
/* Can be disabled for manually tweaking and testing */
if(wrh_tracking_enabled) {
if (abs(offset_ps) >
2 * WRH_SERVO_OFFSET_STABILITY_THRESHOLD) {
gs->state = WRH_SYNC_PHASE;
break;
}
// adjust phase towards offset = 0 make ck0 0
s->cur_setpoint_ps += (offset_ps / 4);
pp_diag(ppi, servo, 3, "%s.%d: Adjust_phase: %d\n",__func__,__LINE__,s->cur_setpoint_ps);
WRH_OPER()->adjust_phase(s->cur_setpoint_ps);
pp_diag(ppi, time, 1, "adjust phase %i\n",
s->cur_setpoint_ps);
s->prev_delayMS_ps = s->delayMS_ps;
}
break;
}
gs->servo_locked=gs->state==WRH_TRACK_PHASE;
/* Increase number of servo updates with state different than
* WRH_TRACK_PHASE. (Used by SNMP) */
if (gs->state != WRH_TRACK_PHASE)
s->n_err_state++;
/* Increase number of servo updates with offset exceeded
* SNMP_MAX_OFFSET_PS (Used by SNMP) */
if (abs(s->offsetMS_ps) > SNMP_MAX_OFFSET_PS)
s->n_err_offset++;
/* Increase number of servo updates with delta rtt exceeded
* SNMP_MAX_DELTA_RTT_PS (Used by SNMP) */
if (abs(prev_delayMM_ps - s->delayMM_ps) > SNMP_MAX_DELTA_RTT_PS)
s->n_err_delta_rtt++;
return 1;
}
......@@ -4,6 +4,5 @@ D := proto-ext-l1sync
OBJ-y += $D/l1e-hooks.o \
$D/l1e-servo.o\
$D/l1e-msg.o\
$D/l1e-state-machine.o
\ No newline at end of file
$D/l1e-state-machine.o
......@@ -13,7 +13,9 @@ OBJ-y += $D/fsm-table.o \
$D/state-wr-calibrated.o \
$D/state-wr-resp-calib-req.o \
$D/state-wr-link-on.o \
$D/state-wr-idle.o \
$D/wr-msg.o \
$D/wr-servo.o
$D/wr-servo.o \
$D/wr-state-machine.o
OBJ-$(CONFIG_ABSCAL) += $D/state-wr-abscal.o
......@@ -6,30 +6,19 @@
*/
#include <ppsi/ppsi.h>
/* We are entering WR handshake, as either master or slave */
void wr_handshake_init(struct pp_instance *ppi, int mode_or_retry)
{
void wr_reset_process(struct pp_instance *ppi, wr_role_t role) {
struct wr_dsport *wrp = WR_DSPOR(ppi);
switch(mode_or_retry) {
case PPS_MASTER:
wrp->wrMode = WR_MASTER;
ppi->next_state = WRS_M_LOCK;
break;
case PPS_SLAVE:
wrp->wrMode = WR_SLAVE;
ppi->next_state = WRS_PRESENT;
break;
default: /* retry: only called from below in this file */
if (wrp->wrMode == WR_MASTER)
ppi->next_state = WRS_M_LOCK;
else
ppi->next_state = WRS_PRESENT;
break;
}
wrp->wrStateTimeout = WR_DEFAULT_STATE_TIMEOUT_MS;
wrp->calPeriod = WR_DEFAULT_CAL_PERIOD;
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;
}
/* The handshake failed: go master or slave in normal PTP mode */
......@@ -39,15 +28,10 @@ void wr_handshake_fail(struct pp_instance *ppi)
pp_diag(ppi, ext, 1, "Handshake failure: now non-wr %s\n",
wrp->wrMode == WR_MASTER ? "master" : "slave");
if (wrp->wrMode == WR_MASTER)
ppi->next_state = PPS_MASTER;
else
ppi->next_state = PPS_SLAVE;
wrp->wrMode =
wrp->parentWrConfig = NON_WR;
wrp->parentIsWRnode =
wrp->parentWrModeOn =
wrp->parentCalibrated = FALSE;
wrp->next_state=WRS_IDLE;
wr_reset_process(ppi,WR_ROLE_NONE);
wr_servo_reset(ppi);
lstate_set_link_perror(ppi);
}
......
......@@ -11,6 +11,7 @@
* This is the WR state machine table.
*/
#if 0
struct pp_state_table_item pp_state_table[] = {
{ PPS_INITIALIZING, "initializing", pp_initializing,},
{ PPS_FAULTY, "faulty", pp_faulty,},
......@@ -34,3 +35,4 @@ struct pp_state_table_item pp_state_table[] = {
#endif
{ PPS_END_OF_TABLE,}
};
#endif
This diff is collapsed.
......@@ -22,15 +22,17 @@ static int next_pps_ms(struct pp_instance *ppi, struct pp_time *t)
* This is using a software loop during the last 10ms in order to get
* right after the pps event
*/
int wr_abscal(struct pp_instance *ppi, void *buf, int plen)
#define WR_TMO_NAME "WR_ABSCAL"
int wr_abscal(struct pp_instance *ppi, void *buf, int plen, int new_state)
{
struct pp_time t;
struct wr_dsport *wrp = WR_DSPOR(ppi);
int len, i;
if (ppi->is_new_state) {
if (new_state) {
/* add 1s to be enough in the future, the first time */
pp_timeout_set_rename(ppi, wrTmoIdx, 990 + next_pps_ms(ppi, &t),"WR_ABSCAL");
pp_timeout_set_rename(ppi, wrTmoIdx, 990 + next_pps_ms(ppi, &t),WR_TMO_NAME);
return 0;
}
......@@ -51,10 +53,8 @@ int wr_abscal(struct pp_instance *ppi, void *buf, int plen)
/* And again next second */
pp_timeout_set(ppi, wrTmoIdx, next_pps_ms(ppi, &t) - 10);
ppi->next_delay = next_pps_ms(ppi, &t) - 10;
return 0;
return next_pps_ms(ppi, &t) - 10;
}
/* no timeout: wait according to next_pps_ms calculated earlier */
ppi->next_delay = i > 0 ? i : 0;
return 0;
return i > 0 ? i : 0;
}
......@@ -12,47 +12,53 @@
* We enter here from WRS_CALIBRATION. If master we wait for
* a CALIBRATE message, if slave we wait for LINK_ON.
*/
int wr_calibrated(struct pp_instance *ppi, void *buf, int len)
#define WR_TMO_NAME "WR_CALIBRATED"
#define WR_TMO_MS WR_CALIBRATED_TIMEOUT_MS
int wr_calibrated(struct pp_instance *ppi, void *buf, int len, int new_state)
{
struct wr_dsport *wrp = WR_DSPOR(ppi);
MsgSignaling wrsig_msg;
int enable = 0;
int sendmsg = 0;
if (ppi->is_new_state) {
if (new_state) {
wrp->wrStateRetry = WR_STATE_RETRY;
pp_timeout_set_rename(ppi, wrTmoIdx, WR_CALIBRATED_TIMEOUT_MS*(WR_STATE_RETRY+1),"WR_CLAIBRATED");
enable = 1;
pp_timeout_set_rename(ppi, wrTmoIdx, WR_TMO_MS*(WR_STATE_RETRY+1),WR_TMO_NAME);
sendmsg = 1;
} else {
int rms=pp_next_delay_1(ppi, wrTmoIdx);
if ( rms==0 || rms<(wrp->wrStateRetry*WR_CALIBRATED_TIMEOUT_MS)) {
/*
* FIXME: We should implement a retry by re-sending
* the "calibrated" message, moving it here from the
* previous state (sub-state 8 of "state-wr-calibration"
*/
if (wr_handshake_retry(ppi))
enable = 1;
else
return 0; /* non-wr already */
if (ppi->received_ptp_header.messageType == PPM_SIGNALING) {
msg_unpack_wrsig(ppi, buf, &wrsig_msg,
&(wrp->msgTmpWrMessageID));
if ((wrp->msgTmpWrMessageID == CALIBRATE) &&
(wrp->wrMode == WR_MASTER)) {
wrp->next_state = WRS_RESP_CALIB_REQ;
return 0;
}
else if ((wrp->msgTmpWrMessageID == WR_MODE_ON) &&
(wrp->wrMode == WR_SLAVE)) {
wrp->next_state = WRS_WR_LINK_ON;
return 0;
}
}
{
/* Check if tmo expired */
int rms=pp_next_delay_1(ppi, wrTmoIdx);
if ( rms==0 || rms<(wrp->wrStateRetry*WR_TMO_MS)) {
if (wr_handshake_retry(ppi))
sendmsg = 1;
else {
pp_diag(ppi, time, 1, "timeout expired: "WR_TMO_NAME"\n");
return 0; /* non-wr already */
}
}
}
}
if (enable){
if (sendmsg){
msg_issue_wrsig(ppi, CALIBRATED);
}
if (ppi->received_ptp_header.messageType == PPM_SIGNALING) {
msg_unpack_wrsig(ppi, buf, &wrsig_msg,
&(wrp->msgTmpWrMessageID));
if ((wrp->msgTmpWrMessageID == CALIBRATE) &&
(wrp->wrMode == WR_MASTER))
ppi->next_state = WRS_RESP_CALIB_REQ;
else if ((wrp->msgTmpWrMessageID == WR_MODE_ON) &&
(wrp->wrMode == WR_SLAVE))
ppi->next_state = WRS_WR_LINK_ON;
}
ppi->next_delay = pp_next_delay_1(ppi,wrTmoIdx)-wrp->wrStateRetry*WR_CALIBRATED_TIMEOUT_MS;
return 0;
return pp_next_delay_1(ppi,wrTmoIdx)-wrp->wrStateRetry*WR_TMO_MS;
}
......@@ -12,132 +12,39 @@
* We enter this state from WRS_M_LOCK or WRS_RESP_CALIB_REQ.
* We send CALIBRATE and do the hardware steps; finally we send CALIBRATED.
*/
int wr_calibration(struct pp_instance *ppi, void *buf, int len)
#define WR_TMO_NAME "WR_CALIBRATION"
#define WR_TMO_MS wrp->calPeriod
int wr_calibration(struct pp_instance *ppi, void *buf, int len, int new_state)
{
struct wr_dsport *wrp = WR_DSPOR(ppi);
int sendmsg = 0;
uint32_t delta;
if (ppi->is_new_state) {
wrp->wrStateRetry = WR_STATE_RETRY;
pp_timeout_set_rename(ppi, wrTmoIdx, wrp->calPeriod*(WR_STATE_RETRY+1),"WR_CALIBRATED");
sendmsg = 1;
} else {
int rms=pp_next_delay_1(ppi, wrTmoIdx);
if ( rms==0 || rms<(wrp->wrStateRetry*wrp->calPeriod)) {
if (wr_handshake_retry(ppi))
sendmsg = 1;
else
return 0; /* non-wr already */
}
}
if (sendmsg) {
msg_issue_wrsig(ppi, CALIBRATE);
wrp->wrPortState = WR_PORT_CALIBRATION_0;
if (wrp->calibrated)
wrp->wrPortState = WR_PORT_CALIBRATION_2;
}
pp_diag(ppi, ext, 1, "%s: substate %i\n", __func__,
wrp->wrPortState - WR_PORT_CALIBRATION_0);
switch (wrp->wrPortState) {
case WR_PORT_CALIBRATION_0:
/* enable pattern sending */
if (WRH_OPER()->calib_pattern_enable(ppi, 0, 0, 0) ==
WRH_HW_CALIB_OK)
wrp->wrPortState = WR_PORT_CALIBRATION_1;
else
break;
case WR_PORT_CALIBRATION_1:
/* enable Tx calibration */
if (WRH_OPER()->calib_enable(ppi, WRH_HW_CALIB_TX)
== WRH_HW_CALIB_OK)
wrp->wrPortState = WR_PORT_CALIBRATION_2;
else
break;
case WR_PORT_CALIBRATION_2:
/* wait until Tx calibration is finished */
if (WRH_OPER()->calib_poll(ppi, WRH_HW_CALIB_TX, &delta) ==
WRH_HW_CALIB_READY) {
wrp->deltaTx.scaledPicoseconds.msb =
0xFFFFFFFF & (((uint64_t)delta) >> 16);
wrp->deltaTx.scaledPicoseconds.lsb =
0xFFFFFFFF & (((uint64_t)delta) << 16);
pp_diag(ppi, ext, 1, "Tx=>>scaledPicoseconds.msb = 0x%x\n",
wrp->deltaTx.scaledPicoseconds.msb);
pp_diag(ppi, ext, 1, "Tx=>>scaledPicoseconds.lsb = 0x%x\n",
wrp->deltaTx.scaledPicoseconds.lsb);
wrp->wrPortState = WR_PORT_CALIBRATION_3;
} else {
break; /* again */
}
case WR_PORT_CALIBRATION_3:
/* disable Tx calibration */
if (WRH_OPER()->calib_disable(ppi, WRH_HW_CALIB_TX)
== WRH_HW_CALIB_OK)
wrp->wrPortState = WR_PORT_CALIBRATION_4;
else
break;
case WR_PORT_CALIBRATION_4:
/* disable pattern sending */
if (WRH_OPER()->calib_pattern_disable(ppi) == WRH_HW_CALIB_OK)
wrp->wrPortState = WR_PORT_CALIBRATION_5;
else
break;
case WR_PORT_CALIBRATION_5:
/* enable Rx calibration using the pattern sent by other port */
if (WRH_OPER()->calib_enable(ppi, WRH_HW_CALIB_RX) ==
WRH_HW_CALIB_OK)
wrp->wrPortState = WR_PORT_CALIBRATION_6;
else
break;
case WR_PORT_CALIBRATION_6:
/* wait until Rx calibration is finished */
if (WRH_OPER()->calib_poll(ppi, WRH_HW_CALIB_RX, &delta) ==
WRH_HW_CALIB_READY) {
pp_diag(ppi, ext, 1, "Rx fixed delay = %d\n", (int)delta);
wrp->deltaRx.scaledPicoseconds.msb =
0xFFFFFFFF & (delta >> 16);
wrp->deltaRx.scaledPicoseconds.lsb =
0xFFFFFFFF & (delta << 16);
pp_diag(ppi, ext, 1, "Rx=>>scaledPicoseconds.msb = 0x%x\n",
wrp->deltaRx.scaledPicoseconds.msb);
pp_diag(ppi, ext, 1, "Rx=>>scaledPicoseconds.lsb = 0x%x\n",
wrp->deltaRx.scaledPicoseconds.lsb);
wrp->wrPortState = WR_PORT_CALIBRATION_7;
} else {
break; /* again */
}
case WR_PORT_CALIBRATION_7:
/* disable Rx calibration */
if (WRH_OPER()->calib_disable(ppi, WRH_HW_CALIB_RX)
== WRH_HW_CALIB_OK)
wrp->wrPortState = WR_PORT_CALIBRATION_8;
else
break;
case WR_PORT_CALIBRATION_8:
/* send deltas to the other port and go to the next state */
// msg_issue_wrsig(ppi, CALIBRATED);
ppi->next_state = WRS_CALIBRATED;
wrp->calibrated = TRUE;
default:
break;
}
ppi->next_delay = pp_next_delay_1(ppi,wrTmoIdx)-wrp->wrStateRetry*wrp->calPeriod;
return 0; /* ignore error */
wr_servo_ext_t *se =WRE_SRV(ppi);
UInteger64 *delta;
/* Calculate deltaTx and update servo*/
delta=(UInteger64 *)&wrp->deltaTx;
*delta= (UInteger64)(ppi->timestampCorrectionPortDS.egressLatency*1000);
pp_diag(ppi, ext, 1, "deltaTx: msb=0x%x lsb=0x%x\n",
wrp->deltaTx.scaledPicoseconds.msb,
wrp->deltaTx.scaledPicoseconds.lsb);
fixedDelta_to_pp_time(*(struct FixedDelta *)delta,&se->delta_txs);/* Update servo specific data */
/* Calculate deltaRx and update servo*/
delta=(UInteger64 *)&wrp->deltaRx;
*delta=(UInteger64)((ppi->timestampCorrectionPortDS.ingressLatency +
ppi->timestampCorrectionPortDS.semistaticLatency) * 1000);
pp_diag(ppi, ext, 1, "deltaRx: msb=0x%x lsb=0x%x\n",
wrp->deltaRx.scaledPicoseconds.msb,
wrp->deltaRx.scaledPicoseconds.lsb);
fixedDelta_to_pp_time(*(struct FixedDelta *)delta, &se->delta_rxs);/* Update servo specific data */
/* Go to the next state */
wrp->next_state = WRS_CALIBRATED;
wrp->calibrated = TRUE;
/* Send CLALIBRATE message */
msg_issue_wrsig(ppi, CALIBRATE);
wrp->wrPortState = 0; /* No longer used */
return 0;
}
......@@ -12,26 +12,19 @@
* This is the last WR state: ack the other party and go master or slave.
* There is no timeout nor a check for is_new_state: we just do things once
*/
int wr_link_on(struct pp_instance *ppi, void *buf, int len)
int wr_link_on(struct pp_instance *ppi, void *buf, int len, int new_state)
{
struct wr_dsport *wrp = WR_DSPOR(ppi);
int e = 0;
wrp->wrModeOn = TRUE;
WRH_OPER()->enable_ptracker(ppi);
if (wrp->wrMode == WR_MASTER)
e = msg_issue_wrsig(ppi, WR_MODE_ON);
wrp->parentWrModeOn = TRUE;
if ( msg_issue_wrsig(ppi, WR_MODE_ON) )
return 0; /* Retry next time */
if (e != 0)
return -1;
if (wrp->wrMode == WR_SLAVE)
ppi->next_state = PPS_SLAVE;
else
ppi->next_state = PPS_MASTER;
// Success
WRH_OPER()->enable_ptracker(ppi);
wrp->wrModeOn =
wrp->parentWrModeOn = TRUE;
wrp->next_state=WRS_IDLE;
#ifdef CONFIG_ABSCAL
/*
......@@ -42,7 +35,7 @@ int wr_link_on(struct pp_instance *ppi, void *buf, int len)
extern int ep_get_bitslide(void);
if (ptp_mode == 4 /* WRC_MODE_ABSCAL */) {
ppi->next_state = WRS_ABSCAL;
wrp->next_state = WRS_ABSCAL;
/* print header for the serial port stream of stamps */
pp_printf("### t4.phase is already corrected for bitslide\n");
pp_printf("t1: t4: "
......
......@@ -12,40 +12,48 @@
* WR slave: got here from WRS_S_LOCK: send LOCKED, wait for CALIBRATE.
* On timeout resend.
*/
int wr_locked(struct pp_instance *ppi, void *buf, int len)
#define WR_TMO_NAME "WR_LOCKED"
#define WR_TMO_MS WR_LOCKED_TIMEOUT_MS
int wr_locked(struct pp_instance *ppi, void *buf, int len, int new_state)
{
int e=0, sendmsg = 0;
int sendmsg = 0;
MsgSignaling wrsig_msg;
struct wr_dsport *wrp = WR_DSPOR(ppi);
if (ppi->is_new_state) {
if (new_state) {
wrp->wrStateRetry = WR_STATE_RETRY;
pp_timeout_set_rename(ppi, wrTmoIdx, WR_LOCKED_TIMEOUT_MS*(WR_STATE_RETRY+1),"WR_LOCKED");
WRH_SRV(ppi)->readyForSync=TRUE; /* We can start synchronization in the servo */
pp_timeout_set_rename(ppi, wrTmoIdx, WR_TMO_MS*(WR_STATE_RETRY+1),WR_TMO_NAME);
sendmsg = 1;
} else {
int rms=pp_next_delay_1(ppi, wrTmoIdx);
if ( rms==0 || rms<(wrp->wrStateRetry*WR_LOCKED_TIMEOUT_MS)) {
if (wr_handshake_retry(ppi))
sendmsg = 1;
else
return 0; /* non-wr already */
}
}
if (sendmsg) {
e=msg_issue_wrsig(ppi, LOCKED);
}
if (ppi->received_ptp_header.messageType == PPM_SIGNALING) {
if (ppi->received_ptp_header.messageType == PPM_SIGNALING) {
msg_unpack_wrsig(ppi, buf, &wrsig_msg,
&(wrp->msgTmpWrMessageID));
msg_unpack_wrsig(ppi, buf, &wrsig_msg,
&(wrp->msgTmpWrMessageID));
if (wrp->msgTmpWrMessageID == CALIBRATE) {
wrp->next_state = WRS_RESP_CALIB_REQ;
return 0;
}
}
if (wrp->msgTmpWrMessageID == CALIBRATE)
ppi->next_state = WRS_RESP_CALIB_REQ;
{ /* Check remaining time */
int rms=pp_next_delay_1(ppi, wrTmoIdx);
if ( rms==0 || rms<(wrp->wrStateRetry*WR_TMO_MS)) {
if (wr_handshake_retry(ppi))
sendmsg = 1;
else {
pp_diag(ppi, time, 1, "timeout expired: "WR_TMO_NAME"\n");
return 0; /* non-wr already */
}
}
}
}
ppi->next_delay = pp_next_delay_1(ppi,wrTmoIdx)-wrp->wrStateRetry*WR_LOCKED_TIMEOUT_MS;
if (sendmsg) {
msg_issue_wrsig(ppi, LOCKED);
}
return e;
return pp_next_delay_1(ppi,wrTmoIdx)-wrp->wrStateRetry*WR_TMO_MS;
}
......@@ -12,40 +12,47 @@
* This the entry point for a WR master: send "LOCK" and wait
* for "LOCKED". On timeout retry sending, for WR_STATE_RETRY times.
*/
int wr_m_lock(struct pp_instance *ppi, void *buf, int len)
#define WR_TMO_NAME "WR_MLOCK"
#define WR_TMO_MS WR_M_LOCK_TIMEOUT_MS
int wr_m_lock(struct pp_instance *ppi, void *buf, int len, int new_state)
{
int e = 0, sendmsg = 0;
int sendmsg = 0;
MsgSignaling wrsig_msg;
struct wr_dsport *wrp = WR_DSPOR(ppi);
if (ppi->is_new_state) {
if (new_state) {
wr_reset_process(ppi,WR_MASTER);
wrp->wrStateRetry = WR_STATE_RETRY;
pp_timeout_set_rename(ppi, wrTmoIdx, WR_M_LOCK_TIMEOUT_MS*(WR_STATE_RETRY+1),"WR_MLOCK");
pp_timeout_set_rename(ppi, wrTmoIdx, WR_TMO_MS*(WR_STATE_RETRY+1),WR_TMO_NAME);
sendmsg = 1;
} else {
int rms=pp_next_delay_1(ppi, wrTmoIdx);
if ( rms==0 || rms<(wrp->wrStateRetry*WR_M_LOCK_TIMEOUT_MS)) {
if (wr_handshake_retry(ppi))
sendmsg = 1;
else
return 0; /* non-wr already */
if (ppi->received_ptp_header.messageType == PPM_SIGNALING) {
msg_unpack_wrsig(ppi, buf, &wrsig_msg,
&(wrp->msgTmpWrMessageID));
if (wrp->msgTmpWrMessageID == LOCKED) {
wrp->next_state = WRS_CALIBRATION;
return 0;
}
}
}
if (sendmsg) {
e = msg_issue_wrsig(ppi, LOCK);
{ /* Check remaining time */
int rms=pp_next_delay_1(ppi, wrTmoIdx);
if ( rms==0 || rms<(wrp->wrStateRetry*WR_TMO_MS)) {
if (wr_handshake_retry(ppi))
sendmsg = 1;
else {
pp_diag(ppi, time, 1, "timeout expired: "WR_TMO_NAME"\n");
return 0; /* non-wr already */
}
}
}
}
if (ppi->received_ptp_header.messageType == PPM_SIGNALING) {
msg_unpack_wrsig(ppi, buf, &wrsig_msg,
&(wrp->msgTmpWrMessageID));
if (wrp->msgTmpWrMessageID == LOCKED)
ppi->next_state = WRS_CALIBRATION;
if (sendmsg) {
msg_issue_wrsig(ppi, LOCK);
}
ppi->next_delay = pp_next_delay_1(ppi,wrTmoIdx)-wrp->wrStateRetry*WR_M_LOCK_TIMEOUT_MS;
return e;
return pp_next_delay_1(ppi,wrTmoIdx)-wrp->wrStateRetry*WR_TMO_MS;
}
......@@ -14,46 +14,50 @@
* Here we send SLAVE_PRESENT and wait for LOCK. If timeout,
* resent SLAVE_PRESENT from WR_STATE_RETRY times
*/
int wr_present(struct pp_instance *ppi, void *buf, int len)
#define WR_TMO_NAME "WR_PRESENT"
#define WR_TMO_MS WR_PRESENT_TIMEOUT_MS
int wr_present(struct pp_instance *ppi, void *buf, int len, int new_state)
{
int e = 0, sendmsg = 0;
int sendmsg = 0;
struct wr_dsport *wrp = WR_DSPOR(ppi);
MsgSignaling wrsig_msg;
if (ppi->is_new_state) {
if (new_state) {
wr_servo_init(ppi);
wrp->wrStateRetry = WR_STATE_RETRY;
pp_timeout_set_rename(ppi, wrTmoIdx, WR_PRESENT_TIMEOUT_MS*(WR_STATE_RETRY+1),"WR_PRESENT");
pp_timeout_set_rename(ppi, wrTmoIdx, WR_TMO_MS*(WR_STATE_RETRY+1),WR_TMO_NAME);
sendmsg = 1;
} else {
int rms=pp_next_delay_1(ppi, wrTmoIdx);
if ( rms==0 || rms<(wrp->wrStateRetry*WR_PRESENT_TIMEOUT_MS)) {
if (wr_handshake_retry(ppi))
sendmsg = 1;
else
return 0; /* non-wr already */
if (ppi->received_ptp_header.messageType == PPM_SIGNALING) {
msg_unpack_wrsig(ppi, buf, &wrsig_msg,
&(wrp->msgTmpWrMessageID));
if (wrp->msgTmpWrMessageID == LOCK) {
wrp->next_state = WRS_S_LOCK;
lstate_set_link_in_progress(ppi);
return 0;
}
}
}
if (sendmsg) {
e = msg_issue_wrsig(ppi, SLAVE_PRESENT);
}
if (ppi->received_ptp_header.messageType == PPM_SIGNALING) {
msg_unpack_wrsig(ppi, buf, &wrsig_msg,
&(wrp->msgTmpWrMessageID));
if (wrp->msgTmpWrMessageID == LOCK)
ppi->next_state = WRS_S_LOCK;
{ /* Check remaining time */
int rms=pp_next_delay_1(ppi, wrTmoIdx);
if ( rms==0 || rms<(wrp->wrStateRetry*WR_TMO_MS)) {
if (wr_handshake_retry(ppi))
sendmsg = 1;
else {
pp_diag(ppi, time, 1, "timeout expired: "WR_TMO_NAME"\n");
return 0; /* non-wr already */
}
}
}
}
if (e == 0)
wr_execute_slave(ppi);
else {
/* nothing, just stay here again */
if (sendmsg) {
msg_issue_wrsig(ppi, SLAVE_PRESENT);
}
ppi->next_delay = pp_next_delay_1(ppi,wrTmoIdx)-wrp->wrStateRetry*WR_PRESENT_TIMEOUT_MS;
return e;
return pp_next_delay_1(ppi,wrTmoIdx)-wrp->wrStateRetry*WR_TMO_MS;
}
......@@ -8,49 +8,52 @@
#include <ppsi/ppsi.h>
int wr_resp_calib_req(struct pp_instance *ppi, void *buf, int len)
#define WR_TMO_NAME "WR_CALIBREQ"
#define WR_TMO_MS WR_RESP_CALIB_REQ_TIMEOUT_MS
int wr_resp_calib_req(struct pp_instance *ppi, void *buf, int len, int new_state)
{
struct wr_dsport *wrp = WR_DSPOR(ppi);
MsgSignaling wrsig_msg;
int e = 0, enable = 0;
int send_pattern = (wrp->otherNodeCalSendPattern != 0);
if (ppi->is_new_state) {
static unsigned long startTime;
if (new_state) {
wrp->wrStateRetry = WR_STATE_RETRY;
pp_timeout_set_rename(ppi, wrTmoIdx,WR_RESP_CALIB_REQ_TIMEOUT_MS*(WR_STATE_RETRY+1),"WR_CALIBREQ");
enable = 1;
pp_timeout_set_rename(ppi, wrTmoIdx,WR_TMO_MS*(WR_STATE_RETRY+1),WR_TMO_NAME);
startTime = ppi->t_ops->calc_timeout(ppi, 0);
} else {
int rms=pp_next_delay_1(ppi, wrTmoIdx);
if ( rms==0 || rms<(wrp->wrStateRetry*WR_RESP_CALIB_REQ_TIMEOUT_MS)) {
if (send_pattern)
WRH_OPER()->calib_pattern_disable(ppi);
if (wr_handshake_retry(ppi))
enable = 1;
else
return 0; /* non-wr already */
}
}
if (enable) { /* first or retry */
if (send_pattern)
WRH_OPER()->calib_pattern_enable(ppi, 0, 0, 0);
}
if (ppi->received_ptp_header.messageType == PPM_SIGNALING) {
msg_unpack_wrsig(ppi, buf, &wrsig_msg,
&(wrp->msgTmpWrMessageID));
if (ppi->received_ptp_header.messageType == PPM_SIGNALING) {
if (wrp->msgTmpWrMessageID == CALIBRATED) {
/* Update servo */
wr_servo_ext_t *se =WRE_SRV(ppi);
msg_unpack_wrsig(ppi, buf, &wrsig_msg,
&(wrp->msgTmpWrMessageID));
fixedDelta_to_pp_time(wrp->otherNodeDeltaTx,&se->delta_txm);
fixedDelta_to_pp_time(wrp->otherNodeDeltaRx,&se->delta_rxm);
wrp->next_state = (wrp->wrMode == WR_MASTER) ?
WRS_WR_LINK_ON :
WRS_CALIBRATION;
pp_printf("JCB: CALIBRATED RECEIVED. Started= %ld ms, Now=%ld\n",startTime,ppi->t_ops->calc_timeout(ppi, 0));
return 0;
}
}
if (wrp->msgTmpWrMessageID == CALIBRATED) {
if (send_pattern)
WRH_OPER()->calib_pattern_disable(ppi);
if (wrp->wrMode == WR_MASTER)
ppi->next_state = WRS_WR_LINK_ON;
else
ppi->next_state = WRS_CALIBRATION;
{ /* Check remaining time */
int rms=pp_next_delay_1(ppi, wrTmoIdx);
if ( rms==0 || rms<(wrp->wrStateRetry*WR_TMO_MS)) {
if (!wr_handshake_retry(ppi)) {
pp_diag(ppi, time, 1, "timeout expired: "WR_TMO_NAME"\n");
return 0; /* non-wr already */
}
}
}
}
ppi->next_delay = pp_next_delay_1(ppi,wrTmoIdx)-wrp->wrStateRetry*WR_RESP_CALIB_REQ_TIMEOUT_MS;
return e;
return pp_next_delay_1(ppi,wrTmoIdx)-wrp->wrStateRetry*WR_TMO_MS;
}
......@@ -8,45 +8,43 @@
#include <ppsi/ppsi.h>
int wr_s_lock(struct pp_instance *ppi, void *buf, int len)
#define WR_TMO_NAME "WR_SLOCK"
#define WR_TMO_MS WR_S_LOCK_TIMEOUT_MS
int wr_s_lock(struct pp_instance *ppi, void *buf, int len, int new_state)
{
struct wr_dsport *wrp = WR_DSPOR(ppi);
int enable = 0;
int poll_ret;
if (ppi->is_new_state) {
if (new_state) {
wrp->wrStateRetry = WR_STATE_RETRY;
pp_timeout_set_rename(ppi, wrTmoIdx, WR_S_LOCK_TIMEOUT_MS*(WR_STATE_RETRY+1),"WR_SLOCK");
pp_timeout_set_rename(ppi, wrTmoIdx, WR_TMO_MS*(WR_STATE_RETRY+1),WR_TMO_NAME);
enable = 1;
} else {
int rms=pp_next_delay_1(ppi, wrTmoIdx);
if ( rms==0 || rms<(wrp->wrStateRetry*WR_S_LOCK_TIMEOUT_MS)) {
WRH_OPER()->locking_disable(ppi);
if (wr_handshake_retry(ppi))
enable = 1;
else
return 0; /* non-wr already */
int poll_ret = WRH_OPER()->locking_poll(ppi);
if (poll_ret == WRH_SPLL_READY) {
wrp->next_state = WRS_LOCKED;
return 0;
}
{ /* Check remaining time */
int rms=pp_next_delay_1(ppi, wrTmoIdx);
if ( rms==0 || rms<(wrp->wrStateRetry*WR_TMO_MS)) {
WRH_OPER()->locking_disable(ppi);
if (wr_handshake_retry(ppi))
enable = 1;
else {
pp_diag(ppi, time, 1, "timeout expired: "WR_TMO_NAME"\n");
return 0; /* non-wr already */
}
}
}
}
if (enable) {
WRH_OPER()->locking_enable(ppi);
}
ppi->next_delay = pp_next_delay_1(ppi,wrTmoIdx)-wrp->wrStateRetry*WR_S_LOCK_TIMEOUT_MS;
poll_ret = WRH_OPER()->locking_poll(ppi);
if (poll_ret == WRH_SPLL_READY) {
ppi->next_state = WRS_LOCKED;
WRH_OPER()->locking_disable(ppi);
} else if (poll_ret == WRH_SPLL_CALIB_NOT_READY) {
/* rxts_calibration not ready, enter the same state without
* a delay */
ppi->next_delay = 0;
}
/* Calibration can take time so we restart the BMC timer to avoid aged foreign master removed. */
pp_gtimeout_reset(GLBS(ppi), PP_TO_BMC);
return 0;
return 100 ;/* 100ms : We check every 100ms if the PLL is locked */
}
......@@ -22,6 +22,7 @@
* (see wrspec.v2-06-07-2011, page 17)
*/
struct wr_dsport {
wr_state_t state, next_state; /* WR state */
Boolean wrModeOn; /* True when extension is running */
Boolean parentWrModeOn;
FixedDelta deltaTx;
......@@ -49,6 +50,9 @@ struct wr_dsport {
UInteger16 otherNodeCalSendPattern;
UInteger32 otherNodeCalPeriod;/* microseconsds, never changed */
UInteger8 otherNodeCalRetry;
struct PortIdentity parentAnnPortIdentity; /* Last received announce message port identity */
UInteger16 parentAnnSequenceId; /* Last received sequence did in the parent announce message */
};
/* This uppercase name matches "DSPOR(ppi)" used by standard protocol */
......@@ -73,7 +77,7 @@ static inline Integer32 phase_to_cf_units(Integer32 phase)
/* Pack/Unkpack White rabbit message in the suffix of PTP announce message */
void msg_pack_announce_wr_tlv(struct pp_instance *ppi);
void msg_unpack_announce_wr_tlv(void *buf, MsgAnnounce *ann);
void msg_unpack_announce_wr_tlv(void *buf, MsgAnnounce *ann, UInteger16 *wrFlags);
/* Pack/Unkpack/Issue White rabbit message signaling msg */
int msg_pack_wrsig(struct pp_instance *ppi, Enumeration16 wr_msg_id);
......@@ -82,70 +86,96 @@ void msg_unpack_wrsig(struct pp_instance *ppi, void *buf,
int msg_issue_wrsig(struct pp_instance *ppi, Enumeration16 wr_msg_id);
/* White rabbit state functions */
int wr_present(struct pp_instance *ppi, void *buf, int len);
int wr_m_lock(struct pp_instance *ppi, void *buf, int len);
int wr_s_lock(struct pp_instance *ppi, void *buf, int len);
int wr_locked(struct pp_instance *ppi, void *buf, int len);
int wr_calibration(struct pp_instance *ppi, void *buf, int len);
int wr_calibrated(struct pp_instance *ppi, void *buf, int len);
int wr_resp_calib_req(struct pp_instance *ppi, void *buf, int len);
int wr_link_on(struct pp_instance *ppi, void *buf, int len);
int wr_abscal(struct pp_instance *ppi, void *buf, int plen);
int wr_present(struct pp_instance *ppi, void *buf, int len,int new_state);
int wr_m_lock(struct pp_instance *ppi, void *buf, int len,int new_state);
int wr_s_lock(struct pp_instance *ppi, void *buf, int len,int new_state);
int wr_locked(struct pp_instance *ppi, void *buf, int len,int new_state);
int wr_calibration(struct pp_instance *ppi, void *buf, int len,int new_state);
int wr_calibrated(struct pp_instance *ppi, void *buf, int len,int new_state);
int wr_resp_calib_req(struct pp_instance *ppi, void *buf, int len,int new_state);
int wr_link_on(struct pp_instance *ppi, void *buf, int len,int new_state);
int wr_abscal(struct pp_instance *ppi, void *buf, int len,int new_state);
int wr_idle(struct pp_instance *ppi, void *buf, int len, int new_state);
int wr_run_state_machine(struct pp_instance *ppi, void *buf, int len);
/* Common functions, used by various states and hooks */
void wr_handshake_init(struct pp_instance *ppi, int mode);
void wr_handshake_fail(struct pp_instance *ppi); /* goto non-wr */
int wr_handshake_retry(struct pp_instance *ppi); /* 1 == retry; 0 == failed */
int wr_execute_slave(struct pp_instance *ppi);
int wr_ready_for_slave(struct pp_instance *ppi);
void wr_reset_process(struct pp_instance *ppi, wr_role_t role);
/* wr_servo interface */
int wr_servo_init(struct pp_instance *ppi);
void wr_servo_reset(struct pp_instance *ppi);
void wr_servo_enable_tracking(int enable);
int wr_servo_got_sync(struct pp_instance *ppi);
int wr_servo_got_delay(struct pp_instance *ppi);
int wr_servo_update(struct pp_instance *ppi);
struct wr_servo_state {
/* These fields are used by servo code, after asetting at init time */
int32_t delta_txm_ps;
int32_t delta_rxm_ps;
int32_t delta_txs_ps;
int32_t delta_rxs_ps;
int32_t fiber_fix_alpha;
int32_t clock_period_ps;
int wr_servo_init(struct pp_instance *ppi);
void wr_servo_enable_tracking(int enable);
/* Following fields are for monitoring/diagnostics (use w/ shmem) */
struct pp_time delayMM;
int64_t delayMM_ps;
int32_t cur_setpoint;
int64_t delayMS_ps;
int tracking_enabled;
int64_t skew;
#define WR_SERVO_RESET_DATA_SIZE (sizeof(struct wr_servo_state)-offsetof(struct wr_servo_state,reset_address))
#define WR_SERVO_RESET_DATA(servo) memset(&servo->reset_address,0,WR_SERVO_RESET_DATA_SIZE);
struct wr_servo_state {
/* Values used by snmp. Values are increased at servo update when
* erroneous condition occurs. */
uint32_t n_err_state;
uint32_t n_err_offset;
uint32_t n_err_delta_rtt;
struct pp_time update_time;
/* ----- All data after this line will cleared during a servo reset */
int reset_address;
int64_t delayMM_ps;
int32_t cur_setpoint_ps;
int64_t delayMS_ps;
int tracking_enabled;
int64_t skew_ps;
int64_t offsetMS_ps;
/* These fields are used by servo code, across iterations */
struct pp_time t1, t2, t3, t4, t5, t6;
int64_t prev_delayMS_ps;
int64_t prev_delayMS_ps;
int missed_iters;
/* These fields are used by servo code, after asetting at init time */
int32_t delta_txm_ps;
int32_t delta_rxm_ps;
int32_t delta_txs_ps;
int32_t delta_rxs_ps;
int32_t clock_period_ps;
};
typedef struct wr_servo_ext {
struct pp_time delta_txm;
struct pp_time delta_rxm;
struct pp_time delta_txs;
struct pp_time delta_rxs;
}wr_servo_ext_t;
/* All data used as extension ppsi-wr must be put here */
struct wr_data {
struct wr_servo_state servo_state;
wrh_servo_t servo; /* As to be in the first place in this structure */
wr_servo_ext_t servo_ext;
};
static inline struct wr_servo_ext *WRE_SRV(struct pp_instance *ppi)
{
return &((struct wr_data *)ppi->ext_data)->servo_ext;
}
extern struct pp_ext_hooks wr_ext_hooks;
extern int wrTmoIdx;
/* Servo routines */
static inline void wr_servo_reset(struct pp_instance *ppi) {
wrh_servo_reset(ppi);
}
extern int wr_servo_got_sync(struct pp_instance *ppi);
extern int wr_servo_got_resp(struct pp_instance *ppi);
extern int wr_servo_got_presp(struct pp_instance *ppi);
#endif /* __ASSEMBLY__ */
#endif /* CONFIG_EXT_WR == 1*/
......
......@@ -30,7 +30,7 @@
#define WR_S_LOCK_TIMEOUT_MS 15000
#define WR_LOCKED_TIMEOUT_MS 300
#define WR_CALIBRATION_TIMEOUT_MS 3000
#define WR_RESP_CALIB_REQ_TIMEOUT_MS 100 // 3
#define WR_RESP_CALIB_REQ_TIMEOUT_MS 300 // 3
#define WR_CALIBRATED_TIMEOUT_MS 300
......@@ -61,29 +61,20 @@
/* Indicates if a port is configured as White Rabbit, and what kind
* (master/slave) */
enum {
NON_WR = 0x0,
WR_S_ONLY = 0x2,
typedef enum {
NON_WR = 0,
WR_M_ONLY = 0x1,
WR_S_ONLY = 0x2,
WR_M_AND_S = 0x3,
WR_MODE_AUTO = 0x4, /* only for ptpx - not in the spec */
};
WR_MODE_AUTO= 0x4, /* only for ptpx - not in the spec */
}wr_config_t;
/* White Rabbit node */
enum {
WR_SLAVE = 2,
typedef enum {
WR_ROLE_NONE=0,
WR_MASTER = 1,
};
/* White Rabbit Servo */
enum {
WR_UNINITIALIZED = 0,
WR_SYNC_NSEC,
WR_SYNC_TAI,
WR_SYNC_PHASE,
WR_TRACK_PHASE,
WR_WAIT_OFFSET_STABLE,
};
WR_SLAVE = 2
}wr_role_t;
/* Values of Management Actions (extended for WR), see table 38
*/
......@@ -96,13 +87,10 @@ enum {
WR_CMD, /* White Rabbit */
};
/* brief WR PTP states (new, single FSM) */
enum {
/*
* Extension-specific states start from 100 according to some docs
* so not to conflict with normal states
*/
WRS_PRESENT = 100,
/* brief WR PTP states */
typedef enum {
WRS_IDLE=0,
WRS_PRESENT,
WRS_S_LOCK,
WRS_M_LOCK,
WRS_LOCKED,
......@@ -110,19 +98,10 @@ enum {
WRS_CALIBRATED,
WRS_RESP_CALIB_REQ,
WRS_WR_LINK_ON,
/* substates: used within WRS_CALIBRATED as wrPortState field */
WR_PORT_CALIBRATION_0,
WR_PORT_CALIBRATION_1,
WR_PORT_CALIBRATION_2,
WR_PORT_CALIBRATION_3,
WR_PORT_CALIBRATION_4,
WR_PORT_CALIBRATION_5,
WR_PORT_CALIBRATION_6,
WR_PORT_CALIBRATION_7,
WR_PORT_CALIBRATION_8,
/* A special send-sync-only state for absolute calibration */
WRS_ABSCAL,
};
WRS_MAX_STATES,
wr_state_t_ForceToIntSize = INT_MAX
}wr_state_t;
/* White Rabbit commands (for new implementation, single FSM), see table 38 */
enum {
......
......@@ -55,7 +55,8 @@ static inline UInteger16 get_be16(void *ptr)
void msg_pack_announce_wr_tlv(struct pp_instance *ppi)
{
void *buf;
UInteger16 wr_flags = 0;
UInteger16 wr_flags;
struct wr_dsport *wrp = WR_DSPOR(ppi);
buf = ppi->tx_ptp;
......@@ -72,17 +73,17 @@ void msg_pack_announce_wr_tlv(struct pp_instance *ppi)
| WR_TLV_WR_VERSION_NUMBER)));
/* wrMessageId */
*(UInteger16 *)(buf + 74) = htons(ANN_SUFIX);
wr_flags = wr_flags | WR_DSPOR(ppi)->wrConfig;
if (WR_DSPOR(ppi)->calibrated)
wr_flags = WR_IS_CALIBRATED | wr_flags;
wr_flags = wrp->wrConfig;
if (wrp->calibrated)
wr_flags |= WR_IS_CALIBRATED;
if (WR_DSPOR(ppi)->wrModeOn)
wr_flags = WR_IS_WR_MODE | wr_flags;
if (wrp->wrModeOn)
wr_flags |= WR_IS_WR_MODE;
*(UInteger16 *)(buf + 76) = htons(wr_flags);
}
void msg_unpack_announce_wr_tlv(void *buf, MsgAnnounce *ann)
void msg_unpack_announce_wr_tlv(void *buf, MsgAnnounce *ann, UInteger16 *wrFlags)
{
UInteger16 tlv_type;
UInteger32 tlv_organizationID;
......@@ -105,16 +106,9 @@ void msg_unpack_announce_wr_tlv(void *buf, MsgAnnounce *ann)
tlv_magicNumber == WR_TLV_MAGIC_NUMBER &&
tlv_versionNumber == WR_TLV_WR_VERSION_NUMBER &&
tlv_wrMessageID == ANN_SUFIX) {
ann->ext_specific = (UInteger16)get_be16(buf+76);
*wrFlags= (UInteger16)get_be16(buf+76);
} else
ann->ext_specific = 0;
}
static inline int32_t delta_to_ps(struct FixedDelta d)
{
_UInteger64 *sps = &d.scaledPicoseconds; /* ieee type :( */
return (sps->lsb >> 16) | (sps->msb << 16);
*wrFlags = 0;
}
/* White Rabbit: packing WR Signaling messages*/
......@@ -123,14 +117,6 @@ int msg_pack_wrsig(struct pp_instance *ppi, Enumeration16 wr_msg_id)
void *buf;
UInteger16 len = 0;
struct wr_dsport *wrp = WR_DSPOR(ppi);
struct wr_servo_state *s =&((struct wr_data *)ppi->ext_data)->servo_state;
if ( (wrp->wrMode == NON_WR) || (wr_msg_id == ANN_SUFIX)) {
pp_diag(ppi, frames, 1,
"BUG: Trying to send invalid wr_msg mode=%x id=%x",
wrp->wrMode, wr_msg_id);
return 0;
}
buf = ppi->tx_ptp;
......@@ -171,7 +157,7 @@ int msg_pack_wrsig(struct pp_instance *ppi, Enumeration16 wr_msg_id)
len = 14;
break;
case CALIBRATED: /* new fsm */
case CALIBRATED:
/* delta TX */
put_be32(buf+56, wrp->deltaTx.scaledPicoseconds.msb);
put_be32(buf+60, wrp->deltaTx.scaledPicoseconds.lsb);
......@@ -180,13 +166,6 @@ int msg_pack_wrsig(struct pp_instance *ppi, Enumeration16 wr_msg_id)
put_be32(buf+64, wrp->deltaRx.scaledPicoseconds.msb);
put_be32(buf+68, wrp->deltaRx.scaledPicoseconds.lsb);
len = 24;
/*JCB: Hack. servo_init() called too early. PTP state machine must be modify. */
/* We should stay in UNCALIBRATED state during WR protocol */
s->delta_txm_ps = delta_to_ps(wrp->otherNodeDeltaTx);
s->delta_rxm_ps = delta_to_ps(wrp->otherNodeDeltaRx);
s->delta_txs_ps = delta_to_ps(wrp->deltaTx);
s->delta_rxs_ps = delta_to_ps(wrp->deltaRx);
break;
default:
......@@ -213,7 +192,6 @@ void msg_unpack_wrsig(struct pp_instance *ppi, void *buf,
UInteger16 tlv_versionNumber;
Enumeration16 wr_msg_id;
struct wr_dsport *wrp = WR_DSPOR(ppi);
struct wr_servo_state *s =&((struct wr_data *)ppi->ext_data)->servo_state;
memcpy(&wrsig_msg->targetPortIdentity.clockIdentity, (buf + 34),
PP_CLOCK_IDENTITY_LENGTH);
......@@ -284,10 +262,6 @@ void msg_unpack_wrsig(struct pp_instance *ppi, void *buf,
get_be32(buf+64);
wrp->otherNodeDeltaRx.scaledPicoseconds.lsb =
get_be32(buf+68);
/*JCB: Hack. serrvo_init() called too early. PTP state machine must be modify. */
/* We should stay in UNCALIBRATED state during WR protocol */
s->delta_txm_ps = delta_to_ps(wrp->otherNodeDeltaTx);
s->delta_rxm_ps = delta_to_ps(wrp->otherNodeDeltaRx);
break;
default:
......
This diff is collapsed.
/*
* Copyright (C) 2018 CERN (www.cern.ch)
* Author: Jean-Claude BAU & Maciej Lipinski
*
* Released according to the GNU LGPL, version 2.1 or any later version.
*/
#include <ppsi/ppsi.h>
#include <common-fun.h>
#include "wr-constants.h"
#include <math.h>
typedef struct {
char *name;
int (*action)(struct pp_instance *ppi, void *buf, int len, int new_state);
}wr_state_machine_t;
#define MAX_STATE_ACTIONS (sizeof(wr_state_actions)/sizeof(wr_state_machine_t))
static wr_state_machine_t wr_state_actions[] ={
[WRS_IDLE]{
.name="wr-idle",
.action=wr_idle,
},
[WRS_PRESENT]{
.name="wr-present",
.action=wr_present,
},
[WRS_M_LOCK]{
.name="wr_m_lock",
.action=wr_m_lock,
},
[WRS_S_LOCK]{
.name="wr-s-lock",
.action=wr_s_lock,
},
[WRS_LOCKED]{
.name="wr-locked",
.action=wr_locked,
},
[WRS_CALIBRATION]{
.name="wr-calibration",
.action=wr_calibration,
},
[WRS_CALIBRATED]{
.name="wr-calibrated",
.action=wr_calibrated,
},
[WRS_RESP_CALIB_REQ]{
.name="wr-resp-calib-req",
.action=wr_resp_calib_req,
},
[WRS_WR_LINK_ON]{
.name="wr-link-on",
.action=wr_link_on,
},
#ifdef CONFIG_ABSCAL
[WRS_ABSCAL]{
.name="absolute-calibration",
.action=wr_abscal,
},
#endif
};
/*
* This hook is called by fsm to run the extension state machine.
* It is used to send signaling messages.
* It returns the ext-specific timeout value
*/
int wr_run_state_machine(struct pp_instance *ppi, void *buf, int len) {
struct wr_dsport * wrp=WR_DSPOR(ppi);
wr_state_t nextState=wrp->next_state;
Boolean newState=nextState!=wrp->state;
int delay;
if ( !ppi->ext_enabled || ppi->state==PPS_INITIALIZING || nextState>=MAX_STATE_ACTIONS) {
if ( wrp->state!=WRS_IDLE ) {
nextState=wrp->next_state=WRS_IDLE;
/* Force to IDLE state when extension is disabled */
} else
return INT_MAX; /* Return a big delay. fsm will then not use it */
}
/*
* Evaluation of events common to all states
*/
if ( newState ) {
pp_diag(ppi, ext, 2, "WR state: LEAVE=%s, ENTER=%s\n",
wr_state_actions[wrp->state].name,
wr_state_actions[nextState].name);
wrp->state=nextState;
}
delay=(*wr_state_actions[wrp->state].action) (ppi, buf,len, newState);
return delay;
}
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