Add support for multiple fault types
Signed-off-by: Delio Brignoli <dbrignoli@audioscience.com>master
parent
455ebe7d22
commit
b936d35b6d
29
clock.c
29
clock.c
|
@ -72,7 +72,6 @@ struct clock {
|
|||
struct port *port[CLK_N_PORTS];
|
||||
struct pollfd pollfd[CLK_N_PORTS*N_CLOCK_PFD];
|
||||
int fault_fd[CLK_N_PORTS];
|
||||
int8_t fault_timeout[CLK_N_PORTS];
|
||||
int nports; /* does not include the UDS port */
|
||||
int free_running;
|
||||
int freq_est_interval;
|
||||
|
@ -123,18 +122,27 @@ void clock_destroy(struct clock *c)
|
|||
|
||||
static int clock_fault_timeout(struct clock *c, int index, int set)
|
||||
{
|
||||
int log_seconds = 0;
|
||||
unsigned int scale = 0;
|
||||
struct fault_interval i;
|
||||
|
||||
if (set) {
|
||||
pr_debug("waiting 2^{%d} seconds to clear fault on port %d",
|
||||
c->fault_timeout[index], index);
|
||||
log_seconds = c->fault_timeout[index];
|
||||
scale = 1;
|
||||
} else {
|
||||
if (!set) {
|
||||
pr_debug("clearing fault on port %d", index);
|
||||
return set_tmo_lin(c->fault_fd[index], 0);
|
||||
}
|
||||
return set_tmo_log(c->fault_fd[index], scale, log_seconds);
|
||||
|
||||
fault_interval(c->port[index], last_fault_type(c->port[index]), &i);
|
||||
|
||||
if (i.type == FTMO_LINEAR_SECONDS) {
|
||||
pr_debug("waiting %d seconds to clear fault on port %d",
|
||||
i.val, index);
|
||||
return set_tmo_lin(c->fault_fd[index], i.val);
|
||||
} else if (i.type == FTMO_LOG2_SECONDS) {
|
||||
pr_debug("waiting 2^{%d} seconds to clear fault on port %d",
|
||||
i.val, index);
|
||||
return set_tmo_log(c->fault_fd[index], 1, i.val);
|
||||
}
|
||||
|
||||
pr_err("Unsupported fault interval type %d", i.type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void clock_freq_est_reset(struct clock *c)
|
||||
|
@ -618,7 +626,6 @@ struct clock *clock_create(int phc_index, struct interface *iface, int count,
|
|||
clock_sync_interval(c, 0);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
c->fault_timeout[i] = iface[i].pod.fault_reset_interval;
|
||||
c->port[i] = port_open(phc_index, timestamping, 1+i, &iface[i], c);
|
||||
if (!c->port[i]) {
|
||||
pr_err("failed to open port %s", iface[i].name);
|
||||
|
|
5
config.c
5
config.c
|
@ -113,10 +113,11 @@ static enum parser_result parse_pod_setting(const char *option,
|
|||
pod->neighborPropDelayThresh = val;
|
||||
|
||||
} else if (!strcmp(option, "fault_reset_interval")) {
|
||||
pod->flt_interval_pertype[FT_UNSPECIFIED].type = FTMO_LOG2_SECONDS;
|
||||
if (!strcasecmp("ASAP", value)) {
|
||||
pod->fault_reset_interval = FRI_ASAP;
|
||||
pod->flt_interval_pertype[FT_UNSPECIFIED].val = FRI_ASAP;
|
||||
} else if (1 == sscanf(value, "%hhd", &i8)) {
|
||||
pod->fault_reset_interval = i8;
|
||||
pod->flt_interval_pertype[FT_UNSPECIFIED].val = i8;
|
||||
} else {
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
|
3
ds.h
3
ds.h
|
@ -21,6 +21,7 @@
|
|||
#define HAVE_DS_H
|
||||
|
||||
#include "ddt.h"
|
||||
#include "fault.h"
|
||||
|
||||
/* clock data sets */
|
||||
|
||||
|
@ -124,7 +125,7 @@ struct port_defaults {
|
|||
int path_trace_enabled;
|
||||
int follow_up_info;
|
||||
int freq_est_interval; /*log seconds*/
|
||||
int fault_reset_interval; /*log seconds*/
|
||||
struct fault_interval flt_interval_pertype[FT_CNT];
|
||||
UInteger32 neighborPropDelayThresh; /*nanoseconds*/
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
* @file fault.c
|
||||
* @note Copyright (C) 2013 Delio Brignoli <dbrignoli@audioscience.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
#include "fault.h"
|
||||
|
||||
static const char *fault_type_str[FT_CNT] = {
|
||||
"FT_UNSPECIFIED",
|
||||
};
|
||||
|
||||
const char *ft_str(enum fault_type ft)
|
||||
{
|
||||
if (ft < 0 || ft >= FT_CNT)
|
||||
return "INVALID_FAULT_TYPE_ENUM";
|
||||
return fault_type_str[ft];
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/**
|
||||
* @file fault.h
|
||||
* @note Copyright (C) 2013 Delio Brignoli <dbrignoli@audioscience.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
|
||||
enum fault_type {
|
||||
FT_UNSPECIFIED = 0,
|
||||
FT_CNT,
|
||||
};
|
||||
|
||||
enum fault_tmo_type {
|
||||
FTMO_LINEAR_SECONDS = 0,
|
||||
FTMO_LOG2_SECONDS,
|
||||
FTMO_CNT,
|
||||
};
|
||||
|
||||
struct fault_interval {
|
||||
enum fault_tmo_type type;
|
||||
int32_t val;
|
||||
};
|
||||
|
||||
const char *ft_str(enum fault_type ft);
|
6
makefile
6
makefile
|
@ -29,9 +29,9 @@ VER = -DVER=$(version)
|
|||
CFLAGS = -Wall $(VER) $(INC) $(DEBUG) $(FEAT_CFLAGS) $(EXTRA_CFLAGS)
|
||||
LDLIBS = -lm -lrt $(EXTRA_LDFLAGS)
|
||||
PRG = ptp4l pmc phc2sys hwstamp_ctl
|
||||
OBJ = bmc.o clock.o config.o fsm.o ptp4l.o mave.o msg.o phc.o pi.o port.o \
|
||||
print.o raw.o servo.o sk.o stats.o tlv.o tmtab.o transport.o udp.o udp6.o \
|
||||
uds.o util.o version.o
|
||||
OBJ = bmc.o clock.o config.o fault.o fsm.o ptp4l.o mave.o msg.o phc.o pi.o \
|
||||
port.o print.o raw.o servo.o sk.o stats.o tlv.o tmtab.o transport.o udp.o \
|
||||
udp6.o uds.o util.o version.o
|
||||
|
||||
OBJECTS = $(OBJ) hwstamp_ctl.o phc2sys.o pmc.o pmc_common.o sysoff.o
|
||||
SRC = $(OBJECTS:.o=.c)
|
||||
|
|
36
port.c
36
port.c
|
@ -87,6 +87,7 @@ struct port {
|
|||
Enumeration8 delayMechanism;
|
||||
Integer8 logMinPdelayReqInterval;
|
||||
UInteger32 neighborPropDelayThresh;
|
||||
enum fault_type last_fault_type;
|
||||
unsigned int versionNumber; /*UInteger4*/
|
||||
/* foreignMasterDS */
|
||||
LIST_HEAD(fm, foreign_clock) foreign_masters;
|
||||
|
@ -160,6 +161,23 @@ static int source_pid_eq(struct ptp_message *m1, struct ptp_message *m2)
|
|||
&m2->header.sourcePortIdentity);
|
||||
}
|
||||
|
||||
enum fault_type last_fault_type(struct port *port)
|
||||
{
|
||||
return port->last_fault_type;
|
||||
}
|
||||
|
||||
int fault_interval(struct port *port, enum fault_type ft,
|
||||
struct fault_interval *i)
|
||||
{
|
||||
if (!port || !i)
|
||||
return -EINVAL;
|
||||
if (ft < 0 || ft >= FT_CNT)
|
||||
return -EINVAL;
|
||||
i->type = port->pod.flt_interval_pertype[ft].type;
|
||||
i->val = port->pod.flt_interval_pertype[ft].val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int set_tmo_log(int fd, unsigned int scale, int log_seconds)
|
||||
{
|
||||
struct itimerspec tmo = {
|
||||
|
@ -768,8 +786,14 @@ static int port_set_sync_tmo(struct port *p)
|
|||
static void port_show_transition(struct port *p,
|
||||
enum port_state next, enum fsm_event event)
|
||||
{
|
||||
pr_notice("port %hu: %s to %s on %s", portnum(p),
|
||||
ps_str[p->state], ps_str[next], ev_str[event]);
|
||||
if (event == EV_FAULT_DETECTED) {
|
||||
pr_notice("port %hu: %s to %s on %s (%s)", portnum(p),
|
||||
ps_str[p->state], ps_str[next], ev_str[event],
|
||||
ft_str(last_fault_type(p)));
|
||||
} else {
|
||||
pr_notice("port %hu: %s to %s on %s", portnum(p),
|
||||
ps_str[p->state], ps_str[next], ev_str[event]);
|
||||
}
|
||||
}
|
||||
|
||||
static void port_slave_priority_warning(struct port *p)
|
||||
|
@ -1120,6 +1144,7 @@ static int port_initialize(struct port *p)
|
|||
{
|
||||
int fd[N_TIMER_FDS], i;
|
||||
|
||||
p->last_fault_type = FT_UNSPECIFIED;
|
||||
p->logMinDelayReqInterval = p->pod.logMinDelayReqInterval;
|
||||
p->peerMeanPathDelay = 0;
|
||||
p->logAnnounceInterval = p->pod.logAnnounceInterval;
|
||||
|
@ -1774,6 +1799,7 @@ static void port_p2p_transition(struct port *p, enum port_state next)
|
|||
int port_dispatch(struct port *p, enum fsm_event event, int mdiff)
|
||||
{
|
||||
enum port_state next;
|
||||
struct fault_interval i;
|
||||
|
||||
if (clock_slave_only(p->clock)) {
|
||||
if (event == EV_RS_MASTER || event == EV_RS_GRAND_MASTER) {
|
||||
|
@ -1784,8 +1810,10 @@ int port_dispatch(struct port *p, enum fsm_event event, int mdiff)
|
|||
next = ptp_fsm(p->state, event, mdiff);
|
||||
}
|
||||
|
||||
if (PS_INITIALIZING == next ||
|
||||
(PS_FAULTY == next && FRI_ASAP == p->pod.fault_reset_interval)) {
|
||||
fault_interval(p, last_fault_type(p), &i);
|
||||
int fri_asap = (i.val == FRI_ASAP && i.type == FTMO_LOG2_SECONDS) ||
|
||||
(i.val == 0 && i.type == FTMO_LINEAR_SECONDS);
|
||||
if (PS_INITIALIZING == next || (PS_FAULTY == next && fri_asap)) {
|
||||
/*
|
||||
* This is a special case. Since we initialize the
|
||||
* port immediately, we can skip right to listening
|
||||
|
|
20
port.h
20
port.h
|
@ -186,4 +186,24 @@ int set_tmo_log(int fd, unsigned int scale, int log_seconds);
|
|||
*/
|
||||
int set_tmo_lin(int fd, int seconds);
|
||||
|
||||
/**
|
||||
* Returns a port's last fault type.
|
||||
*
|
||||
* @param port A port instance.
|
||||
* @return One of the @ref fault_type values.
|
||||
*/
|
||||
enum fault_type last_fault_type(struct port *port);
|
||||
|
||||
/**
|
||||
* Fills passed in struct fault_interval with the value associated to a
|
||||
* port and fault type.
|
||||
*
|
||||
* @param port A port instance.
|
||||
* @param ft Fault type.
|
||||
* @param i Pointer to the struct which will be filled in.
|
||||
* @return Zero on success, non-zero otherwise.
|
||||
*/
|
||||
int fault_interval(struct port *port, enum fault_type ft,
|
||||
struct fault_interval *i);
|
||||
|
||||
#endif
|
||||
|
|
7
ptp4l.c
7
ptp4l.c
|
@ -79,7 +79,6 @@ static struct config cfg_settings = {
|
|||
.path_trace_enabled = 0,
|
||||
.follow_up_info = 0,
|
||||
.freq_est_interval = 1,
|
||||
.fault_reset_interval = 4,
|
||||
/* Default to very a large neighborPropDelay threshold */
|
||||
.neighborPropDelayThresh = 20000000,
|
||||
},
|
||||
|
@ -174,6 +173,12 @@ int main(int argc, char *argv[])
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* Set fault timeouts to a default value */
|
||||
for (i = 0; i < FT_CNT; i++) {
|
||||
cfg_settings.pod.flt_interval_pertype[i].type = FTMO_LOG2_SECONDS;
|
||||
cfg_settings.pod.flt_interval_pertype[i].val = 4;
|
||||
}
|
||||
|
||||
/* Process the command line arguments. */
|
||||
progname = strrchr(argv[0], '/');
|
||||
progname = progname ? 1+progname : argv[0];
|
||||
|
|
Loading…
Reference in New Issue