Commit fea217df authored by Alessandro Rubini's avatar Alessandro Rubini

Merge branch 'timeout-cleanup'

parents fbce8f05 6d7bf7e3
...@@ -51,7 +51,7 @@ CFLAGS += -O2 -ggdb -Iinclude -fno-common ...@@ -51,7 +51,7 @@ CFLAGS += -O2 -ggdb -Iinclude -fno-common
CFLAGS += -DPPSI_VERSION=\"$(VERSION)\" CFLAGS += -DPPSI_VERSION=\"$(VERSION)\"
# to avoid ifdef as much as possible, I use the kernel trick for OBJ variables # to avoid ifdef as much as possible, I use the kernel trick for OBJ variables
OBJ-y := fsm.o diag.o OBJ-y := fsm.o diag.o timeout.o
# Include arch code. Each arch chooses its own time directory.. # Include arch code. Each arch chooses its own time directory..
include arch-$(ARCH)/Makefile include arch-$(ARCH)/Makefile
......
...@@ -119,6 +119,8 @@ int pp_state_machine(struct pp_instance *ppi, uint8_t *packet, int plen) ...@@ -119,6 +119,8 @@ int pp_state_machine(struct pp_instance *ppi, uint8_t *packet, int plen)
if (ppi->state != ppi->next_state) { if (ppi->state != ppi->next_state) {
ppi->state = ppi->next_state; ppi->state = ppi->next_state;
ppi->is_new_state = 1; ppi->is_new_state = 1;
pp_timeout_setall(ppi);
ppi->flags &= ~PPI_FLAGS_WAITING;
pp_diag_fsm(ppi, ip->name, STATE_LEAVE, 0); pp_diag_fsm(ppi, ip->name, STATE_LEAVE, 0);
return 0; /* next_delay unused: go to new state now */ return 0; /* next_delay unused: go to new state now */
} }
......
...@@ -53,9 +53,9 @@ ...@@ -53,9 +53,9 @@
/* We use an array of timeouts, with these indexes */ /* We use an array of timeouts, with these indexes */
enum pp_timeouts { enum pp_timeouts {
PP_TO_REQUEST = 0, PP_TO_REQUEST = 0,
PP_TO_SYNC, PP_TO_SYNC_SEND,
PP_TO_ANN_RECEIPT, PP_TO_ANN_RECEIPT,
PP_TO_ANN_INTERVAL, PP_TO_ANN_SEND,
PP_TO_FAULTY, PP_TO_FAULTY,
/* Two timeouts for the protocol extension */ /* Two timeouts for the protocol extension */
PP_TO_EXT_0, PP_TO_EXT_0,
......
...@@ -57,6 +57,10 @@ struct pp_vlanhdr { ...@@ -57,6 +57,10 @@ struct pp_vlanhdr {
uint16_t h_proto; uint16_t h_proto;
}; };
/* Helpers for the fsm (fsm-lib.c) */
extern int pp_lib_may_issue_sync(struct pp_instance *ppi);
extern int pp_lib_may_issue_announce(struct pp_instance *ppi);
extern int pp_lib_may_issue_request(struct pp_instance *ppi);
/* We use data sets a lot, so have these helpers */ /* We use data sets a lot, so have these helpers */
static inline struct pp_globals *GLBS(struct pp_instance *ppi) static inline struct pp_globals *GLBS(struct pp_instance *ppi)
...@@ -193,7 +197,6 @@ struct pp_time_operations { ...@@ -193,7 +197,6 @@ struct pp_time_operations {
int (*adjust_offset)(struct pp_instance *ppi, long offset_ns); int (*adjust_offset)(struct pp_instance *ppi, long offset_ns);
int (*adjust_freq)(struct pp_instance *ppi, long freq_ppb); int (*adjust_freq)(struct pp_instance *ppi, long freq_ppb);
int (*init_servo)(struct pp_instance *ppi); int (*init_servo)(struct pp_instance *ppi);
/* calc_timeout cannot return zero */
unsigned long (*calc_timeout)(struct pp_instance *ppi, int millisec); unsigned long (*calc_timeout)(struct pp_instance *ppi, int millisec);
}; };
...@@ -212,69 +215,21 @@ extern struct pp_time_operations unix_time_ops; ...@@ -212,69 +215,21 @@ extern struct pp_time_operations unix_time_ops;
#define PP_ADJ_FREQ_MAX 512000 #define PP_ADJ_FREQ_MAX 512000
/* /*
* Timeouts. I renamed from "timer" to "timeout" to avoid * Timeouts.
* misread/miswrite with the time operations above. A timeout, actually, *
* is just a number that must be compared with the current counter. * A timeout, is just a number that must be compared with the current counter.
* So we don't need struct operations, as it is one function only, * So we don't need struct operations, as it is one function only,
* which is folded into the "pp_time_operations" above. * which is folded into the "pp_time_operations" above.
*/ */
extern void pp_timeout_init(struct pp_instance *ppi);
static inline void pp_timeout_set(struct pp_instance *ppi, int index, extern void __pp_timeout_set(struct pp_instance *ppi, int index, int millisec);
int millisec) extern void pp_timeout_set(struct pp_instance *ppi, int index);
{ extern void pp_timeout_setall(struct pp_instance *ppi);
ppi->timeouts[index] = ppi->t_ops->calc_timeout(ppi, millisec); extern int pp_timeout(struct pp_instance *ppi, int index)
} __attribute__((warn_unused_result));
extern int pp_next_delay_1(struct pp_instance *ppi, int i1);
extern void pp_timeout_rand(struct pp_instance *ppi, int index, int logval); extern int pp_next_delay_2(struct pp_instance *ppi, int i1, int i2);
extern int pp_next_delay_3(struct pp_instance *ppi, int i1, int i2, int i3);
static inline void pp_timeout_clr(struct pp_instance *ppi, int index)
{
ppi->timeouts[index] = 0;
}
extern void pp_timeout_log(struct pp_instance *ppi, int index);
static inline int pp_timeout(struct pp_instance *ppi, int index)
{
int ret = ppi->timeouts[index] &&
time_after_eq(ppi->t_ops->calc_timeout(ppi, 0),
ppi->timeouts[index]);
if (ret)
pp_timeout_log(ppi, index);
return ret;
}
static inline int pp_timeout_z(struct pp_instance *ppi, int index)
{
int ret = pp_timeout(ppi, index);
if (ret)
pp_timeout_clr(ppi, index);
return ret;
}
/* how many ms to wait for the timeout to happen, for ppi->next_delay */
static inline int pp_ms_to_timeout(struct pp_instance *ppi, int index)
{
signed long ret;
if (!ppi->timeouts[index]) /* not pending, nothing to wait for */
return 0;
ret = ppi->timeouts[index] - ppi->t_ops->calc_timeout(ppi, 0);
return ret <= 0 ? 0 : ret;
}
/* called several times, only sets a timeout, so inline it here */
static inline void pp_timeout_restart_annrec(struct pp_instance *ppi)
{
/* This timeout is a number of the announce interval lapses */
pp_timeout_set(ppi, PP_TO_ANN_RECEIPT,
((DSPOR(ppi)->announceReceiptTimeout) <<
DSPOR(ppi)->logAnnounceInterval) * 1000);
}
/* The channel for an instance must be created and possibly destroyed. */ /* The channel for an instance must be created and possibly destroyed. */
extern int pp_init_globals(struct pp_globals *ppg, struct pp_runtime_opts *opts); extern int pp_init_globals(struct pp_globals *ppg, struct pp_runtime_opts *opts);
......
...@@ -186,7 +186,6 @@ static int wr_execute_slave(struct pp_instance *ppi) ...@@ -186,7 +186,6 @@ static int wr_execute_slave(struct pp_instance *ppi)
return 0; return 0;
ppi->next_state = PPS_INITIALIZING; ppi->next_state = PPS_INITIALIZING;
pp_timeout_restart_annrec(ppi);
WR_DSPOR(ppi)->doRestart = FALSE; WR_DSPOR(ppi)->doRestart = FALSE;
return 1; /* the caller returns too */ return 1; /* the caller returns too */
} }
......
...@@ -19,9 +19,9 @@ int wr_calibrated(struct pp_instance *ppi, unsigned char *pkt, int plen) ...@@ -19,9 +19,9 @@ int wr_calibrated(struct pp_instance *ppi, unsigned char *pkt, int plen)
MsgSignaling wrsig_msg; MsgSignaling wrsig_msg;
if (ppi->is_new_state) if (ppi->is_new_state)
pp_timeout_set(ppi, PP_TO_EXT_0, wrp->wrStateTimeout); __pp_timeout_set(ppi, PP_TO_EXT_0, wrp->wrStateTimeout);
if (pp_timeout_z(ppi, PP_TO_EXT_0)) { if (pp_timeout(ppi, PP_TO_EXT_0)) {
/* /*
* FIXME: We should implement a retry by re-sending * FIXME: We should implement a retry by re-sending
* the "calibrated" message, moving it here from the * the "calibrated" message, moving it here from the
......
...@@ -22,7 +22,7 @@ int wr_calibration(struct pp_instance *ppi, unsigned char *pkt, int plen) ...@@ -22,7 +22,7 @@ int wr_calibration(struct pp_instance *ppi, unsigned char *pkt, int plen)
if (ppi->is_new_state) { if (ppi->is_new_state) {
wrp->wrStateRetry = WR_STATE_RETRY; wrp->wrStateRetry = WR_STATE_RETRY;
sendmsg = 1; sendmsg = 1;
} else if (pp_timeout_z(ppi, PP_TO_EXT_0)) { } else if (pp_timeout(ppi, PP_TO_EXT_0)) {
if (wr_handshake_retry(ppi)) if (wr_handshake_retry(ppi))
sendmsg = 1; sendmsg = 1;
else else
...@@ -30,8 +30,7 @@ int wr_calibration(struct pp_instance *ppi, unsigned char *pkt, int plen) ...@@ -30,8 +30,7 @@ int wr_calibration(struct pp_instance *ppi, unsigned char *pkt, int plen)
} }
if (sendmsg) { if (sendmsg) {
pp_timeout_set(ppi, PP_TO_EXT_0, __pp_timeout_set(ppi, PP_TO_EXT_0, wrp->calPeriod);
wrp->calPeriod);
e = msg_issue_wrsig(ppi, CALIBRATE); e = msg_issue_wrsig(ppi, CALIBRATE);
wrp->wrPortState = WR_PORT_CALIBRATION_0; wrp->wrPortState = WR_PORT_CALIBRATION_0;
if (wrp->calibrated) if (wrp->calibrated)
......
...@@ -22,7 +22,7 @@ int wr_locked(struct pp_instance *ppi, unsigned char *pkt, int plen) ...@@ -22,7 +22,7 @@ int wr_locked(struct pp_instance *ppi, unsigned char *pkt, int plen)
if (ppi->is_new_state) { if (ppi->is_new_state) {
wrp->wrStateRetry = WR_STATE_RETRY; wrp->wrStateRetry = WR_STATE_RETRY;
sendmsg = 1; sendmsg = 1;
} else if (pp_timeout_z(ppi, PP_TO_EXT_0)) { } else if (pp_timeout(ppi, PP_TO_EXT_0)) {
if (wr_handshake_retry(ppi)) if (wr_handshake_retry(ppi))
sendmsg = 1; sendmsg = 1;
else else
...@@ -30,8 +30,7 @@ int wr_locked(struct pp_instance *ppi, unsigned char *pkt, int plen) ...@@ -30,8 +30,7 @@ int wr_locked(struct pp_instance *ppi, unsigned char *pkt, int plen)
} }
if (sendmsg) { if (sendmsg) {
pp_timeout_set(ppi, PP_TO_EXT_0, __pp_timeout_set(ppi, PP_TO_EXT_0, wrp->wrStateTimeout);
wrp->wrStateTimeout);
e = msg_issue_wrsig(ppi, LOCKED); e = msg_issue_wrsig(ppi, LOCKED);
} }
......
...@@ -22,7 +22,7 @@ int wr_m_lock(struct pp_instance *ppi, unsigned char *pkt, int plen) ...@@ -22,7 +22,7 @@ int wr_m_lock(struct pp_instance *ppi, unsigned char *pkt, int plen)
if (ppi->is_new_state) { if (ppi->is_new_state) {
wrp->wrStateRetry = WR_STATE_RETRY; wrp->wrStateRetry = WR_STATE_RETRY;
sendmsg = 1; sendmsg = 1;
} else if (pp_timeout_z(ppi, PP_TO_EXT_0)) { } else if (pp_timeout(ppi, PP_TO_EXT_0)) {
if (wr_handshake_retry(ppi)) if (wr_handshake_retry(ppi))
sendmsg = 1; sendmsg = 1;
else else
...@@ -31,7 +31,7 @@ int wr_m_lock(struct pp_instance *ppi, unsigned char *pkt, int plen) ...@@ -31,7 +31,7 @@ int wr_m_lock(struct pp_instance *ppi, unsigned char *pkt, int plen)
if (sendmsg) { if (sendmsg) {
e = msg_issue_wrsig(ppi, LOCK); e = msg_issue_wrsig(ppi, LOCK);
pp_timeout_set(ppi, PP_TO_EXT_0, WR_M_LOCK_TIMEOUT_MS); __pp_timeout_set(ppi, PP_TO_EXT_0, WR_M_LOCK_TIMEOUT_MS);
} }
if (plen == 0) if (plen == 0)
......
...@@ -26,7 +26,7 @@ int wr_present(struct pp_instance *ppi, unsigned char *pkt, int plen) ...@@ -26,7 +26,7 @@ int wr_present(struct pp_instance *ppi, unsigned char *pkt, int plen)
if (ppi->is_new_state) { if (ppi->is_new_state) {
wrp->wrStateRetry = WR_STATE_RETRY; wrp->wrStateRetry = WR_STATE_RETRY;
sendmsg = 1; sendmsg = 1;
} else if (pp_timeout_z(ppi, PP_TO_EXT_0)) { } else if (pp_timeout(ppi, PP_TO_EXT_0)) {
if (wr_handshake_retry(ppi)) if (wr_handshake_retry(ppi))
sendmsg = 1; sendmsg = 1;
else else
...@@ -34,9 +34,7 @@ int wr_present(struct pp_instance *ppi, unsigned char *pkt, int plen) ...@@ -34,9 +34,7 @@ int wr_present(struct pp_instance *ppi, unsigned char *pkt, int plen)
} }
if (sendmsg) { if (sendmsg) {
pp_timeout_set(ppi, PP_TO_EXT_0, __pp_timeout_set(ppi, PP_TO_EXT_0, WR_WRS_PRESENT_TIMEOUT_MS);
WR_WRS_PRESENT_TIMEOUT_MS);
pp_timeout_restart_annrec(ppi);
e = msg_issue_wrsig(ppi, SLAVE_PRESENT); e = msg_issue_wrsig(ppi, SLAVE_PRESENT);
} }
...@@ -58,9 +56,6 @@ out: ...@@ -58,9 +56,6 @@ out:
else else
ppi->next_state = PPS_FAULTY; ppi->next_state = PPS_FAULTY;
if (ppi->next_state != ppi->state)
pp_timeout_clr(ppi, PP_TO_ANN_RECEIPT);
ppi->next_delay = WR_DSPOR(ppi)->wrStateTimeout; ppi->next_delay = WR_DSPOR(ppi)->wrStateTimeout;
return e; return e;
......
...@@ -19,7 +19,7 @@ int wr_resp_calib_req(struct pp_instance *ppi, unsigned char *pkt, int plen) ...@@ -19,7 +19,7 @@ int wr_resp_calib_req(struct pp_instance *ppi, unsigned char *pkt, int plen)
if (ppi->is_new_state) { if (ppi->is_new_state) {
wrp->wrStateRetry = WR_STATE_RETRY; wrp->wrStateRetry = WR_STATE_RETRY;
enable = 1; enable = 1;
} else if (pp_timeout_z(ppi, PP_TO_EXT_0)) { } else if (pp_timeout(ppi, PP_TO_EXT_0)) {
if (send_pattern) if (send_pattern)
wrp->ops->calib_pattern_disable(ppi); wrp->ops->calib_pattern_disable(ppi);
if (wr_handshake_retry(ppi)) if (wr_handshake_retry(ppi))
...@@ -31,7 +31,7 @@ int wr_resp_calib_req(struct pp_instance *ppi, unsigned char *pkt, int plen) ...@@ -31,7 +31,7 @@ int wr_resp_calib_req(struct pp_instance *ppi, unsigned char *pkt, int plen)
if (enable) { /* first or retry */ if (enable) { /* first or retry */
if (send_pattern) if (send_pattern)
wrp->ops->calib_pattern_enable(ppi, 0, 0, 0); wrp->ops->calib_pattern_enable(ppi, 0, 0, 0);
pp_timeout_set(ppi, PP_TO_EXT_0, __pp_timeout_set(ppi, PP_TO_EXT_0,
wrp->otherNodeCalPeriod / 1000); wrp->otherNodeCalPeriod / 1000);
} }
......
...@@ -17,7 +17,7 @@ int wr_s_lock(struct pp_instance *ppi, unsigned char *pkt, int plen) ...@@ -17,7 +17,7 @@ int wr_s_lock(struct pp_instance *ppi, unsigned char *pkt, int plen)
if (ppi->is_new_state) { if (ppi->is_new_state) {
wrp->wrStateRetry = WR_STATE_RETRY; wrp->wrStateRetry = WR_STATE_RETRY;
enable = 1; enable = 1;
} else if (pp_timeout_z(ppi, PP_TO_EXT_0)) { } else if (pp_timeout(ppi, PP_TO_EXT_0)) {
wrp->ops->locking_disable(ppi); wrp->ops->locking_disable(ppi);
if (wr_handshake_retry(ppi)) if (wr_handshake_retry(ppi))
enable = 1; enable = 1;
...@@ -27,7 +27,7 @@ int wr_s_lock(struct pp_instance *ppi, unsigned char *pkt, int plen) ...@@ -27,7 +27,7 @@ int wr_s_lock(struct pp_instance *ppi, unsigned char *pkt, int plen)
if (enable) { if (enable) {
wrp->ops->locking_enable(ppi); wrp->ops->locking_enable(ppi);
pp_timeout_set(ppi, PP_TO_EXT_0, WR_S_LOCK_TIMEOUT_MS); __pp_timeout_set(ppi, PP_TO_EXT_0, WR_S_LOCK_TIMEOUT_MS);
} }
if (wrp->ops->locking_poll(ppi, 0) == WR_SPLL_READY) { if (wrp->ops->locking_poll(ppi, 0) == WR_SPLL_READY) {
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
D := proto-standard D := proto-standard
OBJ-y += $D/fsm-table.o \ OBJ-y += $D/fsm-table.o \
$D/fsm-lib.o \
$D/state-initializing.o \ $D/state-initializing.o \
$D/state-faulty.o \ $D/state-faulty.o \
$D/state-disabled.o \ $D/state-disabled.o \
...@@ -19,5 +20,4 @@ OBJ-y += $D/fsm-table.o \ ...@@ -19,5 +20,4 @@ OBJ-y += $D/fsm-table.o \
$D/arith.o \ $D/arith.o \
$D/servo.o \ $D/servo.o \
$D/hooks.o \ $D/hooks.o \
$D/timeout.o \
$D/open-close.o $D/open-close.o
...@@ -87,14 +87,14 @@ int st_com_execute_slave(struct pp_instance *ppi) ...@@ -87,14 +87,14 @@ int st_com_execute_slave(struct pp_instance *ppi)
if (ret < 0) if (ret < 0)
return ret; return ret;
if (pp_timeout_z(ppi, PP_TO_ANN_RECEIPT)) { if (pp_timeout(ppi, PP_TO_ANN_RECEIPT)) {
ppi->frgn_rec_num = 0; ppi->frgn_rec_num = 0;
if (DSDEF(ppi)->clockQuality.clockClass != PP_CLASS_SLAVE_ONLY if (DSDEF(ppi)->clockQuality.clockClass != PP_CLASS_SLAVE_ONLY
&& (ppi->role != PPSI_ROLE_SLAVE)) { && (ppi->role != PPSI_ROLE_SLAVE)) {
ppi->next_state = PPS_MASTER; ppi->next_state = PPS_MASTER;
} else { } else {
ppi->next_state = PPS_LISTENING; ppi->next_state = PPS_LISTENING;
pp_timeout_restart_annrec(ppi); pp_timeout_set(ppi, PP_TO_ANN_RECEIPT);
} }
} }
return 0; return 0;
...@@ -151,7 +151,7 @@ int st_com_slave_handle_announce(struct pp_instance *ppi, unsigned char *buf, ...@@ -151,7 +151,7 @@ int st_com_slave_handle_announce(struct pp_instance *ppi, unsigned char *buf,
st_com_add_foreign(ppi, buf); st_com_add_foreign(ppi, buf);
/*Reset Timer handling Announce receipt timeout*/ /*Reset Timer handling Announce receipt timeout*/
pp_timeout_restart_annrec(ppi); pp_timeout_set(ppi, PP_TO_ANN_RECEIPT);
ppi->next_state = bmc(ppi); /* got a new announce: run bmc */ ppi->next_state = bmc(ppi); /* got a new announce: run bmc */
......
/*
* Copyright (C) 2011 CERN (www.cern.ch)
* Author: Aurelio Colosimo
* Copyright (C) 2014 GSI (www.gsi.de)
* Author: Alessandro Rubin
*
* Released according to the GNU LGPL, version 2.1 or any later version.
*/
#include <ppsi/ppsi.h>
/* Local functions that build to nothing when Kconfig selects 0/1 vlans */
static int pp_vlan_issue_announce(struct pp_instance *ppi)
{
int i, vlan = 0;
if (CONFIG_VLAN_ARRAY_SIZE && ppi->nvlans == 1)
vlan = ppi->vlans[0];
if (CONFIG_VLAN_ARRAY_SIZE <= 1 || ppi->nvlans <= 1) {
ppi->peer_vid = vlan;
return msg_issue_announce(ppi);
}
/*
* If Kconfig selected 0/1 vlans, this code is not built.
* If we have several vlans, we replace peer_vid and proceed;
*/
for (i = 0; i < ppi->nvlans; i++) {
ppi->peer_vid = ppi->vlans[i];
msg_issue_announce(ppi);
/* ignore errors: each vlan is separate */
}
return 0;
}
static int pp_vlan_issue_sync_followup(struct pp_instance *ppi)
{
int i, vlan = 0;
if (CONFIG_VLAN_ARRAY_SIZE && ppi->nvlans == 1)
vlan = ppi->vlans[0];
if (CONFIG_VLAN_ARRAY_SIZE <= 1 || ppi->nvlans <= 1) {
ppi->peer_vid = vlan;
return msg_issue_sync_followup(ppi);
}
/*
* If Kconfig selected 0/1 vlans, this code is not built.
* If we have several vlans, we replace peer_vid and proceed;
*/
for (i = 0; i < ppi->nvlans; i++) {
ppi->peer_vid = ppi->vlans[i];
msg_issue_sync_followup(ppi);
/* ignore errors: each vlan is separate */
}
return 0;
}
/*
* The following set of functions help the states in the state machine.
* Ideally, we should manage to get to a completely table-driven fsm
* implementation based on these helpers
*/
int pp_lib_may_issue_sync(struct pp_instance *ppi)
{
int e;
if (!pp_timeout(ppi, PP_TO_SYNC_SEND))
return 0;
pp_timeout_set(ppi, PP_TO_SYNC_SEND);
e = pp_vlan_issue_sync_followup(ppi);
if (e)
pp_diag(ppi, frames, 1, "could not send sync\n");
return e;
}
int pp_lib_may_issue_announce(struct pp_instance *ppi)
{
int e;
if (!pp_timeout(ppi, PP_TO_ANN_SEND))
return 0;
pp_timeout_set(ppi, PP_TO_ANN_SEND);
e = pp_vlan_issue_announce(ppi);
if (e)
pp_diag(ppi, frames, 1, "could not send announce\n");
return e;
}
int pp_lib_may_issue_request(struct pp_instance *ppi)
{
int e = 0;
if (!pp_timeout(ppi, PP_TO_REQUEST))
return 0;
pp_timeout_set(ppi, PP_TO_REQUEST);
e = msg_issue_request(ppi); /* FIXME: what about multiple vlans? */
if (e) {
pp_diag(ppi, frames, 1, "could not send request\n");
return e;
}
ppi->t3 = ppi->last_snt_time;
return 0;
}
...@@ -15,14 +15,10 @@ ...@@ -15,14 +15,10 @@
int pp_faulty(struct pp_instance *ppi, unsigned char *pkt, int plen) int pp_faulty(struct pp_instance *ppi, unsigned char *pkt, int plen)
{ {
if (ppi->is_new_state) {
pp_timeout_set(ppi, PP_TO_FAULTY, 4000);
}
if (pp_timeout(ppi, PP_TO_FAULTY)) { if (pp_timeout(ppi, PP_TO_FAULTY)) {
ppi->next_state = PPS_INITIALIZING; ppi->next_state = PPS_INITIALIZING;
return 0; return 0;
} }
ppi->next_delay = pp_ms_to_timeout(ppi, PP_TO_FAULTY); ppi->next_delay = pp_next_delay_1(ppi, PP_TO_FAULTY);
return 0; return 0;
} }
...@@ -46,6 +46,7 @@ int pp_initializing(struct pp_instance *ppi, unsigned char *pkt, int plen) ...@@ -46,6 +46,7 @@ int pp_initializing(struct pp_instance *ppi, unsigned char *pkt, int plen)
port->announceReceiptTimeout = PP_DEFAULT_ANNOUNCE_RECEIPT_TIMEOUT; port->announceReceiptTimeout = PP_DEFAULT_ANNOUNCE_RECEIPT_TIMEOUT;
port->logSyncInterval = opt->sync_intvl; port->logSyncInterval = opt->sync_intvl;
port->versionNumber = PP_VERSION_PTP; port->versionNumber = PP_VERSION_PTP;
pp_timeout_init(ppi);
if (pp_hooks.init) if (pp_hooks.init)
ret = pp_hooks.init(ppi, pkt, plen); ret = pp_hooks.init(ppi, pkt, plen);
......
...@@ -20,23 +20,9 @@ int pp_listening(struct pp_instance *ppi, unsigned char *pkt, int plen) ...@@ -20,23 +20,9 @@ int pp_listening(struct pp_instance *ppi, unsigned char *pkt, int plen)
if (e) if (e)
goto out; goto out;
if (ppi->is_new_state) {
pp_timeout_restart_annrec(ppi);
pp_timeout_rand(ppi, PP_TO_REQUEST,
DSPOR(ppi)->logMinDelayReqInterval);
}
/* when the clock is using peer-delay, listening must send it too */ /* when the clock is using peer-delay, listening must send it too */
if (ppi->glbs->delay_mech == PP_P2P_MECH if (ppi->glbs->delay_mech == PP_P2P_MECH)
&& pp_timeout_z(ppi, PP_TO_REQUEST)) { e = pp_lib_may_issue_request(ppi);
e = msg_issue_request(ppi);
ppi->t3 = ppi->last_snt_time;
/* Restart the timeout for next time */
pp_timeout_rand(ppi, PP_TO_REQUEST,
DSPOR(ppi)->logMinDelayReqInterval);
}
if (plen == 0) if (plen == 0)
goto out; goto out;
...@@ -104,11 +90,7 @@ out: ...@@ -104,11 +90,7 @@ out:
if (e != 0) if (e != 0)
ppi->next_state = PPS_FAULTY; ppi->next_state = PPS_FAULTY;
/* Leaving this state */ ppi->next_delay = pp_next_delay_1(ppi, PP_TO_ANN_RECEIPT);
if (ppi->next_state != ppi->state)
pp_timeout_clr(ppi, PP_TO_ANN_RECEIPT);
ppi->next_delay = pp_ms_to_timeout(ppi, PP_TO_ANN_RECEIPT);
return 0; return 0;
} }
...@@ -9,105 +9,22 @@ ...@@ -9,105 +9,22 @@
#include <ppsi/ppsi.h> #include <ppsi/ppsi.h>
#include "common-fun.h" #include "common-fun.h"
/* Local functions that build to nothing when Kconfig selects 0/1 vlans */
static int pp_master_issue_announce(struct pp_instance *ppi)
{
int i, vlan = 0;
if (CONFIG_VLAN_ARRAY_SIZE && ppi->nvlans == 1)
vlan = ppi->vlans[0];
if (CONFIG_VLAN_ARRAY_SIZE <= 1 || ppi->nvlans <= 1) {
ppi->peer_vid = vlan;
return msg_issue_announce(ppi);
}
/*
* If Kconfig selected 0/1 vlans, this code is not built.
* If we have several vlans, we replace peer_vid and proceed;
*/
for (i = 0; i < ppi->nvlans; i++) {
ppi->peer_vid = ppi->vlans[i];
msg_issue_announce(ppi);
/* ignore errors: each vlan is separate */
}
return 0;
}
static int pp_master_issue_sync_followup(struct pp_instance *ppi)
{
int i, vlan = 0;
if (CONFIG_VLAN_ARRAY_SIZE && ppi->nvlans == 1)
vlan = ppi->vlans[0];
if (CONFIG_VLAN_ARRAY_SIZE <= 1 || ppi->nvlans <= 1) {
ppi->peer_vid = vlan;
return msg_issue_sync_followup(ppi);
}
/*
* If Kconfig selected 0/1 vlans, this code is not built.
* If we have several vlans, we replace peer_vid and proceed;
*/
for (i = 0; i < ppi->nvlans; i++) {
ppi->peer_vid = ppi->vlans[i];
msg_issue_sync_followup(ppi);
/* ignore errors: each vlan is separate */
}
return 0;
}
/* The real state function, relying on the two above for sending */
int pp_master(struct pp_instance *ppi, unsigned char *pkt, int plen) int pp_master(struct pp_instance *ppi, unsigned char *pkt, int plen)
{ {
int msgtype, d1, d2; int msgtype;
int e = 0; /* error var, to check errors in msg handling */ int e = 0; /* error var, to check errors in msg handling */
MsgHeader *hdr = &ppi->received_ptp_header; MsgHeader *hdr = &ppi->received_ptp_header;
MsgPDelayRespFollowUp respFllw; MsgPDelayRespFollowUp respFllw;
if (ppi->is_new_state) { /* ignore errors; we are not getting FAULTY if not transmitting */
pp_timeout_rand(ppi, PP_TO_SYNC, DSPOR(ppi)->logSyncInterval); pp_lib_may_issue_sync(ppi);
pp_timeout_rand(ppi, PP_TO_REQUEST, pp_lib_may_issue_announce(ppi);
DSPOR(ppi)->logMinDelayReqInterval);
pp_timeout_rand(ppi, PP_TO_ANN_INTERVAL,
DSPOR(ppi)->logAnnounceInterval);
/* Send an announce immediately, when becomes master */
if ((e = pp_master_issue_announce(ppi)) < 0)
goto out;
}
if (pp_timeout_z(ppi, PP_TO_SYNC)) {
/* Restart the timeout for next time */
pp_timeout_rand(ppi, PP_TO_SYNC, DSPOR(ppi)->logSyncInterval);
if ((e = pp_master_issue_sync_followup(ppi) < 0))
goto out;
}
if (pp_timeout_z(ppi, PP_TO_ANN_INTERVAL)) {
if ((e = pp_master_issue_announce(ppi) < 0))
goto out;
/* Restart the timeout for next time */
pp_timeout_rand(ppi, PP_TO_ANN_INTERVAL,
DSPOR(ppi)->logAnnounceInterval);
}
/* when the clock is using peer-delay, the muster mast send it too */ /* when the clock is using peer-delay, the muster mast send it too */
if (ppi->glbs->delay_mech == PP_P2P_MECH if (ppi->glbs->delay_mech == PP_P2P_MECH)
&& pp_timeout_z(ppi, PP_TO_REQUEST)) { pp_lib_may_issue_request(ppi);
e = msg_issue_request(ppi); else
pp_timeout_set(ppi, PP_TO_REQUEST);
ppi->t3 = ppi->last_snt_time;
/* Restart the timeout for next time */
pp_timeout_rand(ppi, PP_TO_REQUEST,
DSPOR(ppi)->logMinDelayReqInterval);
}
if (plen == 0) if (plen == 0)
goto out; goto out;
...@@ -204,9 +121,8 @@ out: ...@@ -204,9 +121,8 @@ out:
break; break;
} }
d1 = pp_ms_to_timeout(ppi, PP_TO_ANN_INTERVAL); ppi->next_delay = pp_next_delay_3(ppi,
d2 = pp_ms_to_timeout(ppi, PP_TO_SYNC); PP_TO_ANN_SEND, PP_TO_SYNC_SEND, PP_TO_REQUEST);
ppi->next_delay = d1 < d2 ? d1 : d2;
return e; return e;
out_fault: out_fault:
......
...@@ -15,23 +15,9 @@ int pp_passive(struct pp_instance *ppi, unsigned char *pkt, int plen) ...@@ -15,23 +15,9 @@ int pp_passive(struct pp_instance *ppi, unsigned char *pkt, int plen)
MsgHeader *hdr = &ppi->received_ptp_header; MsgHeader *hdr = &ppi->received_ptp_header;
MsgPDelayRespFollowUp respFllw; MsgPDelayRespFollowUp respFllw;
if (ppi->is_new_state) {
pp_timeout_restart_annrec(ppi);
pp_timeout_rand(ppi, PP_TO_REQUEST,
DSPOR(ppi)->logMinDelayReqInterval);
}
/* when the clock is using peer-delay, listening must send it too */ /* when the clock is using peer-delay, listening must send it too */
if (ppi->glbs->delay_mech == PP_P2P_MECH if (ppi->glbs->delay_mech == PP_P2P_MECH)
&& pp_timeout_z(ppi, PP_TO_REQUEST)) { e = pp_lib_may_issue_request(ppi);
e = msg_issue_request(ppi);
ppi->t3 = ppi->last_snt_time;
/* Restart the timeout for next time */
pp_timeout_rand(ppi, PP_TO_REQUEST,
DSPOR(ppi)->logMinDelayReqInterval);
}
if (plen == 0) if (plen == 0)
goto no_incoming_msg; goto no_incoming_msg;
...@@ -98,10 +84,6 @@ no_incoming_msg: ...@@ -98,10 +84,6 @@ no_incoming_msg:
if (e != 0) if (e != 0)
ppi->next_state = PPS_FAULTY; ppi->next_state = PPS_FAULTY;
if (ppi->next_state != ppi->state) {
pp_timeout_clr(ppi, PP_TO_ANN_RECEIPT);
}
ppi->next_delay = PP_DEFAULT_NEXT_DELAY_MS; ppi->next_delay = PP_DEFAULT_NEXT_DELAY_MS;
return 0; return 0;
......
...@@ -17,7 +17,6 @@ int pp_slave(struct pp_instance *ppi, unsigned char *pkt, int plen) ...@@ -17,7 +17,6 @@ int pp_slave(struct pp_instance *ppi, unsigned char *pkt, int plen)
MsgHeader *hdr = &ppi->received_ptp_header; MsgHeader *hdr = &ppi->received_ptp_header;
MsgDelayResp resp; MsgDelayResp resp;
MsgPDelayRespFollowUp respFllw; MsgPDelayRespFollowUp respFllw;
int d1, d2;
if (ppi->is_new_state) { if (ppi->is_new_state) {
memset(&ppi->t1, 0, sizeof(ppi->t1)); memset(&ppi->t1, 0, sizeof(ppi->t1));
...@@ -27,15 +26,10 @@ int pp_slave(struct pp_instance *ppi, unsigned char *pkt, int plen) ...@@ -27,15 +26,10 @@ int pp_slave(struct pp_instance *ppi, unsigned char *pkt, int plen)
e = pp_hooks.new_slave(ppi, pkt, plen); e = pp_hooks.new_slave(ppi, pkt, plen);
if (e) if (e)
goto out; goto out;
ppi->flags &= ~PPI_FLAGS_WAITING;
pp_timeout_restart_annrec(ppi);
pp_timeout_rand(ppi, PP_TO_REQUEST,
DSPOR(ppi)->logMinDelayReqInterval);
} }
e = pp_lib_may_issue_request(ppi);
if (plen == 0) if (plen == 0)
goto out; goto out;
...@@ -146,16 +140,6 @@ out: ...@@ -146,16 +140,6 @@ out:
if (e == 0) if (e == 0)
e = st_com_execute_slave(ppi); e = st_com_execute_slave(ppi);
if (pp_timeout_z(ppi, PP_TO_REQUEST)) {
e = msg_issue_request(ppi);
ppi->t3 = ppi->last_snt_time;
/* Restart the timeout for next time */
pp_timeout_rand(ppi, PP_TO_REQUEST,
DSPOR(ppi)->logMinDelayReqInterval);
}
switch(e) { switch(e) {
case PP_SEND_OK: /* 0 */ case PP_SEND_OK: /* 0 */
break; break;
...@@ -169,14 +153,10 @@ out: ...@@ -169,14 +153,10 @@ out:
} }
if (ppi->next_state != ppi->state) { if (ppi->next_state != ppi->state) {
pp_timeout_clr(ppi, PP_TO_ANN_RECEIPT);
pp_timeout_clr(ppi, PP_TO_REQUEST);
pp_servo_init(ppi); pp_servo_init(ppi);
return e;
} }
d1 = d2 = pp_ms_to_timeout(ppi, PP_TO_ANN_RECEIPT); ppi->next_delay = pp_next_delay_2(ppi,
if (ppi->timeouts[PP_TO_REQUEST]) PP_TO_ANN_RECEIPT, PP_TO_REQUEST);
d2 = pp_ms_to_timeout(ppi, PP_TO_REQUEST);
ppi->next_delay = d1 < d2 ? d1 : d2;
return e; return e;
} }
/*
* Copyright (C) 2013 CERN (www.cern.ch)
* Author: Alessandro Rubini
*
* Released according to the GNU LGPL, version 2.1 or any later version.
*/
#include <ppsi/ppsi.h>
#define N(n) [n] = #n
static char *timeout_names[__PP_TO_ARRAY_SIZE] __attribute__((used)) = {
N(PP_TO_REQUEST),
N(PP_TO_SYNC),
N(PP_TO_ANN_RECEIPT),
N(PP_TO_ANN_INTERVAL),
N(PP_TO_FAULTY),
N(PP_TO_EXT_0),
N(PP_TO_EXT_1),
};
/*
* Log means messages
*/
void pp_timeout_log(struct pp_instance *ppi, int index)
{
pp_diag(ppi, time, 1, "timeout expired: %s\n", timeout_names[index]);
}
/*
* And "rand" means logarithm...
*
* Randomize a timeout. We are required to fit between 70% and 130%
* of the value for 90% of the time, at least. But making it "almost
* exact" is bad in a big network. So randomize between 80% and 120%:
* constant part is 80% and variable is 40%.
*/
void pp_timeout_rand(struct pp_instance *ppi, int index, int logval)
{
static uint32_t seed;
uint32_t rval;
int millisec;
if (!seed) {
uint32_t *p;
/* use the least 32 bits of the mac address as seed */
p = (void *)(&DSDEF(ppi)->clockIdentity)
+ sizeof(ClockIdentity) - 4;
seed = *p;
}
/* From uclibc: they make 11 + 10 + 10 bits, we stop at 21 */
seed *= 1103515245;
seed += 12345;
rval = (unsigned int) (seed / 65536) % 2048;
seed *= 1103515245;
seed += 12345;
rval <<= 10;
rval ^= (unsigned int) (seed / 65536) % 1024;
millisec = (1 << logval) * 400; /* This is 40% of the nominal value */
millisec = (millisec * 2) + rval % millisec;
pp_timeout_set(ppi, index, millisec);
}
...@@ -92,15 +92,11 @@ static unsigned long bare_calc_timeout(struct pp_instance *ppi, int millisec) ...@@ -92,15 +92,11 @@ static unsigned long bare_calc_timeout(struct pp_instance *ppi, int millisec)
{ {
struct bare_timespec now; struct bare_timespec now;
uint64_t now_ms; uint64_t now_ms;
unsigned long result;
if (!millisec)
millisec = 1;
sys_clock_gettime(CLOCK_MONOTONIC, &now); sys_clock_gettime(CLOCK_MONOTONIC, &now);
now_ms = 1000LL * now.tv_sec + now.tv_nsec / 1000 / 1000; now_ms = 1000LL * now.tv_sec + now.tv_nsec / 1000 / 1000;
result = now_ms + millisec; return now_ms + millisec;
return result ? result : 1; /* cannot return 0 */
} }
struct pp_time_operations bare_time_ops = { struct pp_time_operations bare_time_ops = {
......
...@@ -110,10 +110,7 @@ static inline int sim_init_servo(struct pp_instance *ppi) ...@@ -110,10 +110,7 @@ static inline int sim_init_servo(struct pp_instance *ppi)
static unsigned long sim_calc_timeout(struct pp_instance *ppi, int millisec) static unsigned long sim_calc_timeout(struct pp_instance *ppi, int millisec)
{ {
unsigned long res; return millisec + SIM_PPI_ARCH(ppi)->time.current_ns / 1000LL / 1000LL;
res = millisec + SIM_PPI_ARCH(ppi)->time.current_ns / 1000LL / 1000LL;
return res ? res : 1;
} }
struct pp_time_operations sim_time_ops = { struct pp_time_operations sim_time_ops = {
......
...@@ -117,15 +117,11 @@ static unsigned long unix_calc_timeout(struct pp_instance *ppi, int millisec) ...@@ -117,15 +117,11 @@ static unsigned long unix_calc_timeout(struct pp_instance *ppi, int millisec)
{ {
struct timespec now; struct timespec now;
uint64_t now_ms; uint64_t now_ms;
unsigned long result;
if (!millisec)
millisec = 1;
clock_gettime(CLOCK_MONOTONIC, &now); clock_gettime(CLOCK_MONOTONIC, &now);
now_ms = 1000LL * now.tv_sec + now.tv_nsec / 1000 / 1000; now_ms = 1000LL * now.tv_sec + now.tv_nsec / 1000 / 1000;
result = now_ms + millisec; return now_ms + millisec;
return result ? result : 1; /* cannot return 0 */
} }
struct pp_time_operations unix_time_ops = { struct pp_time_operations unix_time_ops = {
......
...@@ -61,10 +61,7 @@ static int wrpc_time_adjust(struct pp_instance *ppi, long offset_ns, ...@@ -61,10 +61,7 @@ static int wrpc_time_adjust(struct pp_instance *ppi, long offset_ns,
static unsigned long wrpc_calc_timeout(struct pp_instance *ppi, int millisec) static unsigned long wrpc_calc_timeout(struct pp_instance *ppi, int millisec)
{ {
unsigned long now_ms = timer_get_tics(); return timer_get_tics() + millisec;
now_ms += millisec;
return now_ms ? now_ms : 1; /* cannot return 0 */
} }
struct pp_time_operations wrpc_time_ops = { struct pp_time_operations wrpc_time_ops = {
......
/*
* Copyright (C) 2013 CERN (www.cern.ch)
* Author: Alessandro Rubini
*
* Released according to the GNU LGPL, version 2.1 or any later version.
*/
#include <ppsi/ppsi.h>
struct timeout_config {
char *name;
int isrand;
int value;
};
/* most timeouts have a static configuration. Save it here */
static struct timeout_config to_configs[__PP_TO_ARRAY_SIZE] = {
[PP_TO_REQUEST] = {"REQUEST", 1,},
[PP_TO_SYNC_SEND] = {"SYNC_SEND", 1,},
[PP_TO_ANN_RECEIPT] = {"ANN_RECEIPT", 0,},
[PP_TO_ANN_SEND] = {"ANN_SEND", 1,},
[PP_TO_FAULTY] = {"FAULTY", 0, 4000},
/* extension timeouts are explicitly set to a value */
};
/* Init fills the timeout values; they are not changed after program startup */
void pp_timeout_init(struct pp_instance *ppi)
{
struct DSPort *port = ppi->portDS;
to_configs[PP_TO_REQUEST].value =
port->logMinDelayReqInterval;
to_configs[PP_TO_SYNC_SEND].value =
port->logSyncInterval;
to_configs[PP_TO_ANN_RECEIPT].value = 1000 * (
port->announceReceiptTimeout << port->logAnnounceInterval);
to_configs[PP_TO_ANN_SEND].value = port->logAnnounceInterval;
}
static void pp_timeout_log(struct pp_instance *ppi, int index)
{
pp_diag(ppi, time, 1, "timeout expired: %s\n",
to_configs[index].name);
}
void __pp_timeout_set(struct pp_instance *ppi, int index, int millisec)
{
ppi->timeouts[index] = ppi->t_ops->calc_timeout(ppi, millisec);
}
/*
* Randomize a timeout. We are required to fit between 70% and 130%
* of the value for 90% of the time, at least. But making it "almost
* exact" is bad in a big network. So randomize between 80% and 120%:
* constant part is 80% and variable is 40%.
*/
void pp_timeout_set(struct pp_instance *ppi, int index)
{
static uint32_t seed;
uint32_t rval;
int millisec;
int logval = to_configs[index].value;
if (!to_configs[index].isrand){
__pp_timeout_set(ppi, index, logval); /* not a logval */
return;
}
if (!seed) {
uint32_t *p;
/* use the least 32 bits of the mac address as seed */
p = (void *)(&DSDEF(ppi)->clockIdentity)
+ sizeof(ClockIdentity) - 4;
seed = *p;
}
/* From uclibc: they make 11 + 10 + 10 bits, we stop at 21 */
seed *= 1103515245;
seed += 12345;
rval = (unsigned int) (seed / 65536) % 2048;
seed *= 1103515245;
seed += 12345;
rval <<= 10;
rval ^= (unsigned int) (seed / 65536) % 1024;
millisec = (1 << logval) * 400; /* This is 40% of the nominal value */
millisec = (millisec * 2) + rval % millisec;
__pp_timeout_set(ppi, index, millisec);
}
/*
* When we enter a new fsm state, we init all timeouts. Who cares if
* some of them are not used (and even if some have no default timeout)
*/
void pp_timeout_setall(struct pp_instance *ppi)
{
int i;
for (i = 0; i < __PP_TO_ARRAY_SIZE; i++)
pp_timeout_set(ppi, i);
/* but announce_send must be send soon */
__pp_timeout_set(ppi, PP_TO_ANN_SEND, 20);
}
int pp_timeout(struct pp_instance *ppi, int index)
{
int ret = time_after_eq(ppi->t_ops->calc_timeout(ppi, 0),
ppi->timeouts[index]);
if (ret)
pp_timeout_log(ppi, index);
return ret;
}
/*
* How many ms to wait for the timeout to happen, for ppi->next_delay.
* It is not allowed for a timeout to not be pending
*/
int pp_next_delay_1(struct pp_instance *ppi, int i1)
{
unsigned long now = ppi->t_ops->calc_timeout(ppi, 0);
signed long r1;
r1 = ppi->timeouts[i1] - now;
return r1 < 0 ? 0 : r1;
}
int pp_next_delay_2(struct pp_instance *ppi, int i1, int i2)
{
unsigned long now = ppi->t_ops->calc_timeout(ppi, 0);
signed long r1, r2;
r1 = ppi->timeouts[i1] - now;
r2 = ppi->timeouts[i2] - now;
if (r2 < r1)
r1 = r2;
return r1 < 0 ? 0 : r1;
}
int pp_next_delay_3(struct pp_instance *ppi, int i1, int i2, int i3)
{
unsigned long now = ppi->t_ops->calc_timeout(ppi, 0);
signed long r1, r2, r3;
r1 = ppi->timeouts[i1] - now;
r2 = ppi->timeouts[i2] - now;
r3 = ppi->timeouts[i3] - now;
if (r2 < r1)
r1 = r2;
if (r3 < r1)
r1 = r3;
return r1 < 0 ? 0 : r1;
}
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