Commit 5702115b authored by Alessandro Rubini's avatar Alessandro Rubini

whiterabbit: implement retry on timeout

This commits adds retry in most wr states. This allows to deal with
lost frames. There a few missing items, and a few rough situation.
The code itself shows a number of repetitions, which I dislike, but
over time we'll fix it properly.

By now this should be enough to deal with transient data loss
during calibration, that happens at some users' site.
Signed-off-by: Alessandro Rubini's avatarAlessandro Rubini <rubini@gnudd.com>
parent 76d99d0d
......@@ -4,6 +4,7 @@ D := proto-ext-whiterabbit
OBJ-y += $D/fsm-table.o \
$D/hooks.o \
$D/common-fun.o \
$D/state-wr-present.o \
$D/state-wr-m-lock.o \
$D/state-wr-s-lock.o \
......
/*
* Copyright (C) 2014 CERN (www.cern.ch)
* Author: Alessandro Rubini
*
* Released according to the GNU LGPL, version 2.1 or any later version.
*/
#include <ppsi/ppsi.h>
#include "wr-api.h"
/* We are entering WR handshake, as either master or slave */
void wr_handshake_init(struct pp_instance *ppi, int mode_or_retry)
{
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;
}
}
/* The handshake failed: go master or slave in normal PTP mode */
void wr_handshake_fail(struct pp_instance *ppi)
{
struct wr_dsport *wrp = WR_DSPOR(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 = NON_WR;
}
/* One of the steps failed: either retry or fail */
int wr_handshake_retry(struct pp_instance *ppi)
{
struct wr_dsport *wrp = WR_DSPOR(ppi);
if (wrp->wrStateRetry > 0) {
wrp->wrStateRetry--;
pp_diag(ppi, ext, 1, "Retry on timeout\n");
return 1; /* yes, retry */
}
wr_handshake_fail(ppi);
return 0; /* don't retry, we are over already */
}
......@@ -93,8 +93,10 @@ static int wr_master_msg(struct pp_instance *ppi, unsigned char *pkt, int plen,
msg_unpack_wrsig(ppi, pkt, &wrsig_msg,
&(WR_DSPOR(ppi)->msgTmpWrMessageID));
if ((WR_DSPOR(ppi)->msgTmpWrMessageID == SLAVE_PRESENT) &&
(WR_DSPOR(ppi)->wrConfig & WR_M_ONLY))
ppi->next_state = WRS_M_LOCK;
(WR_DSPOR(ppi)->wrConfig & WR_M_ONLY)) {
/* We must start the handshake as a WR master */
wr_handshake_init(ppi, PPS_MASTER);
}
msgtype = PPM_NOTHING_TO_DO;
break;
}
......@@ -173,8 +175,10 @@ static void wr_handle_announce(struct pp_instance *ppi)
if ((WR_DSPOR(ppi)->wrConfig & WR_S_ONLY) &&
(1 /* FIXME: Recommended State, see page 33*/) &&
(WR_DSPOR(ppi)->parentWrConfig & WR_M_ONLY) &&
(!WR_DSPOR(ppi)->wrModeOn || !WR_DSPOR(ppi)->parentWrModeOn))
ppi->next_state = WRS_PRESENT;
(!WR_DSPOR(ppi)->wrModeOn || !WR_DSPOR(ppi)->parentWrModeOn)) {
/* We must start the handshake as a WR slave */
wr_handshake_init(ppi, PPS_SLAVE);
}
}
static int wr_handle_followup(struct pp_instance *ppi,
......
......@@ -9,21 +9,26 @@
#include <ppsi/ppsi.h>
#include "wr-api.h"
/*
* 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, unsigned char *pkt, int plen)
{
struct wr_dsport *wrp = WR_DSPOR(ppi);
MsgSignaling wrsig_msg;
if (ppi->is_new_state) {
pp_timeout_set(ppi, PP_TO_EXT_0,
WR_DSPOR(ppi)->wrStateTimeout);
}
if (ppi->is_new_state)
pp_timeout_set(ppi, PP_TO_EXT_0, wrp->wrStateTimeout);
if (pp_timeout_z(ppi, PP_TO_EXT_0)) {
if (WR_DSPOR(ppi)->wrMode == WR_MASTER)
ppi->next_state = PPS_MASTER;
else
ppi->next_state = PPS_LISTENING;
goto out;
/*
* 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"
*/
wr_handshake_fail(ppi);
return 0; /* non-wr */
}
if (plen == 0)
......@@ -31,17 +36,17 @@ int wr_calibrated(struct pp_instance *ppi, unsigned char *pkt, int plen)
if (ppi->received_ptp_header.messageType == PPM_SIGNALING) {
msg_unpack_wrsig(ppi, pkt, &wrsig_msg,
&(WR_DSPOR(ppi)->msgTmpWrMessageID));
&(wrp->msgTmpWrMessageID));
if ((WR_DSPOR(ppi)->msgTmpWrMessageID == CALIBRATE) &&
(WR_DSPOR(ppi)->wrMode == WR_MASTER))
if ((wrp->msgTmpWrMessageID == CALIBRATE) &&
(wrp->wrMode == WR_MASTER))
ppi->next_state = WRS_RESP_CALIB_REQ;
else if ((WR_DSPOR(ppi)->msgTmpWrMessageID == WR_MODE_ON) &&
(WR_DSPOR(ppi)->wrMode == WR_SLAVE))
else if ((wrp->msgTmpWrMessageID == WR_MODE_ON) &&
(wrp->wrMode == WR_SLAVE))
ppi->next_state = WRS_WR_LINK_ON;
}
out:
ppi->next_delay = WR_DSPOR(ppi)->wrStateTimeout;
ppi->next_delay = wrp->wrStateTimeout;
return 0;
}
......@@ -9,30 +9,35 @@
#include <ppsi/ppsi.h>
#include "wr-api.h"
/*
* 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, unsigned char *pkt, int plen)
{
struct wr_dsport *wrp = WR_DSPOR(ppi);
int e = 0;
int e = 0, sendmsg = 0;
uint32_t delta;
if (ppi->is_new_state) {
wrp->wrPortState = WR_PORT_CALIBRATION_0;
wrp->wrStateRetry = WR_STATE_RETRY;
sendmsg = 1;
} else if (pp_timeout_z(ppi, PP_TO_EXT_0)) {
if (wr_handshake_retry(ppi))
sendmsg = 1;
else
return 0; /* non-wr already */
}
e = msg_issue_wrsig(ppi, CALIBRATE);
if (sendmsg) {
pp_timeout_set(ppi, PP_TO_EXT_0,
wrp->calPeriod);
e = msg_issue_wrsig(ppi, CALIBRATE);
wrp->wrPortState = WR_PORT_CALIBRATION_0;
if (wrp->calibrated)
wrp->wrPortState = WR_PORT_CALIBRATION_8;
}
if (pp_timeout_z(ppi, PP_TO_EXT_0)) {
if (wrp->wrMode == WR_MASTER)
ppi->next_state = PPS_MASTER;
else
ppi->next_state = PPS_LISTENING;
goto out;
}
pp_diag(ppi, ext, 1, "%s: substate %i\n", __func__,
wrp->wrPortState - WR_PORT_CALIBRATION_0);
......@@ -130,7 +135,6 @@ int wr_calibration(struct pp_instance *ppi, unsigned char *pkt, int plen)
break;
}
out:
ppi->next_delay = wrp->wrStateTimeout;
return e;
......
......@@ -9,20 +9,22 @@
#include <ppsi/ppsi.h>
#include "wr-api.h"
/*
* 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, unsigned char *pkt, int plen)
{
struct wr_dsport *wrp = WR_DSPOR(ppi);
int e = 0;
if (ppi->is_new_state) {
wrp->wrModeOn = TRUE;
wrp->ops->enable_ptracker(ppi);
wrp->wrModeOn = TRUE;
wrp->ops->enable_ptracker(ppi);
if (wrp->wrMode == WR_MASTER)
e = msg_issue_wrsig(ppi, WR_MODE_ON);
if (wrp->wrMode == WR_MASTER)
e = msg_issue_wrsig(ppi, WR_MODE_ON);
wrp->parentWrModeOn = TRUE;
}
wrp->parentWrModeOn = TRUE;
if (e != 0)
return -1;
......
......@@ -9,23 +9,30 @@
#include <ppsi/ppsi.h>
#include "wr-api.h"
/*
* WR slave: got here from WRS_S_LOCK: send LOCKED, wait for CALIBRATE.
* On timeout resend.
*/
int wr_locked(struct pp_instance *ppi, unsigned char *pkt, int plen)
{
int e = 0;
int e = 0, sendmsg = 0;
MsgSignaling wrsig_msg;
struct wr_dsport *wrp = WR_DSPOR(ppi);
if (ppi->is_new_state) {
pp_timeout_set(ppi, PP_TO_EXT_0,
WR_DSPOR(ppi)->wrStateTimeout);
e = msg_issue_wrsig(ppi, LOCKED);
wrp->wrStateRetry = WR_STATE_RETRY;
sendmsg = 1;
} else if (pp_timeout_z(ppi, PP_TO_EXT_0)) {
if (wr_handshake_retry(ppi))
sendmsg = 1;
else
return 0; /* non-wr already */
}
if (pp_timeout_z(ppi, PP_TO_EXT_0)) {
ppi->next_state = PPS_LISTENING;
WR_DSPOR(ppi)->wrMode = NON_WR;
goto out;
if (sendmsg) {
pp_timeout_set(ppi, PP_TO_EXT_0,
wrp->wrStateTimeout);
e = msg_issue_wrsig(ppi, LOCKED);
}
if (plen == 0)
......@@ -34,16 +41,16 @@ int wr_locked(struct pp_instance *ppi, unsigned char *pkt, int plen)
if (ppi->received_ptp_header.messageType == PPM_SIGNALING) {
msg_unpack_wrsig(ppi, pkt, &wrsig_msg,
&(WR_DSPOR(ppi)->msgTmpWrMessageID));
&(wrp->msgTmpWrMessageID));
if (WR_DSPOR(ppi)->msgTmpWrMessageID == CALIBRATE)
if (wrp->msgTmpWrMessageID == CALIBRATE)
ppi->next_state = WRS_RESP_CALIB_REQ;
}
out:
if (e != 0)
ppi->next_state = PPS_FAULTY;
ppi->next_delay = WR_DSPOR(ppi)->wrStateTimeout;
ppi->next_delay = wrp->wrStateTimeout;
return e;
}
......@@ -9,20 +9,29 @@
#include <ppsi/ppsi.h>
#include "wr-api.h"
/*
* 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, unsigned char *pkt, int plen)
{
int e = 0;
int e = 0, sendmsg = 0;
MsgSignaling wrsig_msg;
struct wr_dsport *wrp = WR_DSPOR(ppi);
if (ppi->is_new_state) {
WR_DSPOR(ppi)->wrMode = WR_MASTER;
e = msg_issue_wrsig(ppi, LOCK);
pp_timeout_set(ppi, PP_TO_EXT_0, WR_M_LOCK_TIMEOUT_MS);
wrp->wrStateRetry = WR_STATE_RETRY;
sendmsg = 1;
} else if (pp_timeout_z(ppi, PP_TO_EXT_0)) {
if (wr_handshake_retry(ppi))
sendmsg = 1;
else
return 0; /* non-wr already */
}
if (pp_timeout_z(ppi, PP_TO_EXT_0)) {
ppi->next_state = PPS_MASTER;
goto out;
if (sendmsg) {
e = msg_issue_wrsig(ppi, LOCK);
pp_timeout_set(ppi, PP_TO_EXT_0, WR_M_LOCK_TIMEOUT_MS);
}
if (plen == 0)
......@@ -31,16 +40,16 @@ int wr_m_lock(struct pp_instance *ppi, unsigned char *pkt, int plen)
if (ppi->received_ptp_header.messageType == PPM_SIGNALING) {
msg_unpack_wrsig(ppi, pkt, &wrsig_msg,
&(WR_DSPOR(ppi)->msgTmpWrMessageID));
&(wrp->msgTmpWrMessageID));
if (WR_DSPOR(ppi)->msgTmpWrMessageID == LOCKED)
if (wrp->msgTmpWrMessageID == LOCKED)
ppi->next_state = WRS_CALIBRATION;
}
out:
if (e != 0)
ppi->next_state = PPS_FAULTY;
ppi->next_delay = WR_DSPOR(ppi)->wrStateTimeout;
ppi->next_delay = wrp->wrStateTimeout;
return e;
}
......@@ -10,35 +10,45 @@
#include "wr-api.h"
#include "../proto-standard/common-fun.h"
/*
* WRS_PRESENT is the entry point for a WR slave
*
* 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, unsigned char *pkt, int plen)
{
int e = 0;
int e = 0, sendmsg = 0;
struct wr_dsport *wrp = WR_DSPOR(ppi);
MsgSignaling wrsig_msg;
if (ppi->is_new_state) {
WR_DSPOR(ppi)->wrMode = WR_SLAVE;
wrp->wrStateRetry = WR_STATE_RETRY;
sendmsg = 1;
} else if (pp_timeout_z(ppi, PP_TO_EXT_0)) {
if (wr_handshake_retry(ppi))
sendmsg = 1;
else
return 0; /* non-wr already */
}
if (sendmsg) {
pp_timeout_set(ppi, PP_TO_EXT_0,
WR_WRS_PRESENT_TIMEOUT_MS);
pp_timeout_restart_annrec(ppi);
e = msg_issue_wrsig(ppi, SLAVE_PRESENT);
}
if (pp_timeout_z(ppi, PP_TO_EXT_0)) {
ppi->next_state = PPS_LISTENING;
WR_DSPOR(ppi)->wrMode = NON_WR;
goto out;
}
if (plen == 0)
goto out;
if (ppi->received_ptp_header.messageType == PPM_SIGNALING) {
msg_unpack_wrsig(ppi, pkt, &wrsig_msg,
&(WR_DSPOR(ppi)->msgTmpWrMessageID));
&(wrp->msgTmpWrMessageID));
if (WR_DSPOR(ppi)->msgTmpWrMessageID == LOCK)
if (wrp->msgTmpWrMessageID == LOCK)
ppi->next_state = WRS_S_LOCK;
}
......
......@@ -12,11 +12,23 @@
int wr_resp_calib_req(struct pp_instance *ppi, unsigned char *pkt, int plen)
{
struct wr_dsport *wrp = WR_DSPOR(ppi);
int e = 0;
MsgSignaling wrsig_msg;
int e = 0, enable = 0;
int send_pattern = (wrp->otherNodeCalSendPattern != 0);
if (ppi->is_new_state) {
if (wrp->otherNodeCalSendPattern) {
wrp->wrStateRetry = WR_STATE_RETRY;
enable = 1;
} else if (pp_timeout_z(ppi, PP_TO_EXT_0)) {
wrp->ops->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) {
wrp->ops->calib_pattern_enable(ppi, 0, 0, 0);
pp_timeout_set(ppi, PP_TO_EXT_0,
wrp->otherNodeCalPeriod / 1000);
......@@ -24,15 +36,6 @@ int wr_resp_calib_req(struct pp_instance *ppi, unsigned char *pkt, int plen)
}
if ((wrp->otherNodeCalSendPattern) &&
(pp_timeout_z(ppi, PP_TO_EXT_0))) {
if (wrp->wrMode == WR_MASTER)
ppi->next_state = PPS_MASTER;
else
ppi->next_state = PPS_LISTENING;
goto out;
}
if (plen == 0)
goto out;
......@@ -42,13 +45,12 @@ int wr_resp_calib_req(struct pp_instance *ppi, unsigned char *pkt, int plen)
&(wrp->msgTmpWrMessageID));
if (wrp->msgTmpWrMessageID == CALIBRATED) {
if (wrp->otherNodeCalSendPattern)
if (send_pattern)
wrp->ops->calib_pattern_disable(ppi);
if (wrp->wrMode == WR_MASTER)
ppi->next_state = WRS_WR_LINK_ON;
else
ppi->next_state = WRS_CALIBRATION;
}
}
......
......@@ -12,17 +12,22 @@
int wr_s_lock(struct pp_instance *ppi, unsigned char *pkt, int plen)
{
struct wr_dsport *wrp = WR_DSPOR(ppi);
int e = 0;
int enable = 0;
if (ppi->is_new_state) {
wrp->ops->locking_enable(ppi);
pp_timeout_set(ppi, PP_TO_EXT_0, WR_S_LOCK_TIMEOUT_MS);
wrp->wrStateRetry = WR_STATE_RETRY;
enable = 1;
} else if (pp_timeout_z(ppi, PP_TO_EXT_0)) {
wrp->ops->locking_disable(ppi);
if (wr_handshake_retry(ppi))
enable = 1;
else
return 0; /* non-wr already */
}
if (pp_timeout_z(ppi, PP_TO_EXT_0)) {
ppi->next_state = PPS_FAULTY;
wrp->wrMode = NON_WR;
goto out;
if (enable) {
wrp->ops->locking_enable(ppi);
pp_timeout_set(ppi, PP_TO_EXT_0, WR_S_LOCK_TIMEOUT_MS);
}
if (wrp->ops->locking_poll(ppi, 0) == WR_SPLL_READY) {
......@@ -30,7 +35,6 @@ int wr_s_lock(struct pp_instance *ppi, unsigned char *pkt, int plen)
wrp->ops->locking_disable(ppi);
}
out:
ppi->next_delay = wrp->wrStateTimeout;
return e;
return 0;
}
......@@ -88,6 +88,11 @@ int wr_calibrated(struct pp_instance *ppi, unsigned char *pkt, int plen);
int wr_resp_calib_req(struct pp_instance *ppi, unsigned char *pkt, int plen);
int wr_link_on(struct pp_instance *ppi, unsigned char *pkt, int plen);
/* 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 */
/* White Rabbit hw-dependent functions (code in arch-wrpc and arch-wrs) */
struct wr_operations {
int (*locking_enable)(struct pp_instance *ppi);
......
......@@ -29,7 +29,7 @@
#define WR_WRS_PRESENT_TIMEOUT_MS 1000
#define WR_M_LOCK_TIMEOUT_MS 15000
#define WR_S_LOCK_TIMEOUT_MS 15000
#define WR_DEFAULT_INIT_REPEAT 3
#define WR_STATE_RETRY 3 /* if WR handhsake fails */
/* White Rabbit package Size */
#define WR_ANNOUNCE_TLV_LENGTH 0x0A
......
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