Thread: [Linuxptp-devel] [PATCH v4 0/9] Dynamic sync direction for ts2phc
PTP IEEE 1588 stack for Linux
Brought to you by:
rcochran
|
From: Vladimir O. <ol...@gm...> - 2021-10-09 14:12:18
|
As discussed in this email thread: https://sourceforge.net/p/linuxptp/mailman/message/37047555/ there is a desire to synchronize multiple DSA switches in a boundary_clock_jbod setup, using a PPS signal, and the ts2phc program already offers a solid base. This patch series extends the ts2phc program to cater for that use case by introducing a new '-a' option and friends ('--transportSpecific'). This makes it quite similar to phc2sys which has the same ability, just that ts2phc can give much better performance if the hardware can assist with that. The overall board design for my use case is that there's an SoC with an embedded DSA switch, and hanging off of 3 ports of that embedded switch are 3 external switches. Every networking device (the DSA master for the embedded switch, the embedded switch, as well as each individual external switch) has a PTP clock. The topology for PPS signal distribution is fixed - that is given by hardware ability - the /dev/ptp1 clock can emit a valid PPS, and all external switches can timestamp that PPS (it is connected in a sort-of simplex "bus" design), and it cannot be any other way around. It looks like this: +---------------------------------------------------------------+ | LS1028A /dev/ptp0 (unused) | | +------------------------------+ | | | DSA master for Felix | | | |(internal ENETC port 2: eno2))| | | +------------+------------------------------+-------------+ | | | Felix embedded L2 switch /dev/ptp1 | | | | PPS master, sync slave | | | | +--------------+ +--------------+ +--------------+ | | | | |DSA master for| |DSA master for| |DSA master for| | | | | | SJA1105 1 | | SJA1105 2 | | SJA1105 3 | | | | | |(Felix port 1)| |(Felix port 2)| |(Felix port 3)| | | +--+-+--------------+---+--------------+---+--------------+--+--+ /dev/ptp2 /dev/ptp3 /dev/ptp4 PPS slave, sync master PPS slave, sync slave PPS slave, sync slave +-----------------------+ +-----------------------+ +-----------------------+ | SJA1105 switch 1 | | SJA1105 switch 2 | | SJA1105 switch 3 | +-----+-----+-----+-----+ +-----+-----+-----+-----+ +-----+-----+-----+-----+ |sw1p0|sw1p1|sw1p2|sw1p3| |sw2p0|sw2p1|sw2p2|sw2p3| |sw3p0|sw3p1|sw3p2|sw3p3| +-----+-----+-----+-----+ +-----+-----+-----+-----+ +-----+-----+-----+-----+ ^ | GM connected here In text, it would be described as this: cat ts2phc.cfg [global] first_step_threshold 0.00002 step_threshold 0.00002 ts2phc.pulsewidth 500000000 ts2phc.perout_phase 0 # Felix [/dev/ptp1] ts2phc.master 1 # SJA1105 switch 1 [/dev/ptp2] ts2phc.channel 0 ts2phc.extts_polarity both # SJA1105 switch 2 [/dev/ptp3] ts2phc.channel 0 ts2phc.extts_polarity both # SJA1105 switch 3 [/dev/ptp4] ts2phc.channel 0 ts2phc.extts_polarity both cat gPTP.cfg [global] gmCapable 1 priority1 248 priority2 248 logAnnounceInterval 0 logSyncInterval -3 syncReceiptTimeout 3 neighborPropDelayThresh 50000 min_neighbor_prop_delay -20000000 assume_two_step 1 path_trace_enabled 1 follow_up_info 1 transportSpecific 0x1 ptp_dst_mac 01:80:C2:00:00:0E network_transport L2 delay_mechanism P2P step_threshold 0.00002 tx_timestamp_timeout 20 boundary_clock_jbod 1 [sw1p0] [sw1p1] [sw1p2] [sw1p3] [sw2p0] [sw2p1] [sw2p2] [sw2p3] [sw3p0] [sw3p1] [sw3p2] [sw3p3] At a high level, what I have done is: - I moved the PMC related code from phc2sys into pmc_common.c, for ts2phc reuse - I created an extra abstraction in ts2phc as "struct clock" that would represent what's synchronizable. The "master" and "slave" concepts retain their meaning, which is: "master" == the device that emits PPS, and "slave" == the device that timestamps PPS. - I added support for telling the PHC master to start emitting periodic output using just phase information, and not an absolute time. This is required for the kernel drivers I am working with. - I added support for configuring the pulse width, not just hoping that the value specified in ts2phc.cfg is representative of what the hardware actually uses. The changes should be backwards-compatible with the non-automatic mode. I have only tested non-automatic mode with a PHC master (that's all I have) and it still appears to work as before. Changes in v4: - Rebased and resolved minor conflicts - Small coding style cleanups - Added patch for perout and phase configuration - Retested Changes in v3: - Split patch "phc2sys: break out pmc code into pmc_common.c" into more trivial chunks. There is zero delta compared to previous monolithic patch, otherwise. - Replaced full license header in ts2phc.h with simple SPDX. - Added usage message and manpage for '-a' option. - Removed some useless curly braces. - Moved ts2phc_master_get_clock() from ts2phc_phc_master.c to ts2phc_master.c where it should be. - Added justification in commit message for creating struct ts2phc_private. - Reordered headers alphabetically. Changes in v2: - Added Jacob's review tags, addressed some feedback. - Dropped patch "pmc_common: fix potential memory leak in run_pmc_events()" - Reordered patches (put the tmv helpers first) - Fixed memory leaks Vladimir Oltean (9): ts2phc: create a private data structure ts2phc: instantiate a full clock structure for every slave PHC ts2phc: instantiate a full clock structure for every PHC master ts2phc: instantiate a pmc agent ts2phc_slave: print master offset ts2phc: split slave poll from servo loop ts2phc: reconfigure sync direction by subscribing to ptp4l port events ts2phc: allow the PHC PPS master to be synchronized ts2phc_phc_master: make use of new kernel API for perout waveform config.c | 1 + makefile | 5 +- missing.h | 52 ++++ ts2phc.8 | 32 +- ts2phc.c | 645 +++++++++++++++++++++++++++++++++++++--- ts2phc.h | 64 ++++ ts2phc_generic_master.c | 2 +- ts2phc_generic_master.h | 3 +- ts2phc_master.c | 18 +- ts2phc_master.h | 8 +- ts2phc_master_private.h | 1 + ts2phc_nmea_master.c | 7 +- ts2phc_nmea_master.h | 3 +- ts2phc_phc_master.c | 82 +++-- ts2phc_phc_master.h | 3 +- ts2phc_slave.c | 386 ++++++++++++------------ ts2phc_slave.h | 10 +- 17 files changed, 1054 insertions(+), 268 deletions(-) create mode 100644 ts2phc.h -- 2.25.1 |
|
From: Vladimir O. <ol...@gm...> - 2020-08-01 17:46:43
|
As discussed in this email thread: https://sourceforge.net/p/linuxptp/mailman/message/37047555/ there is a desire to synchronize multiple DSA switches in a boundary_clock_jbod setup, using a PPS signal, and the ts2phc program already offers a solid base. This patch series extends the ts2phc program to cater for that use case by introducing a new '-a' option and friends ('--transportSpecific'). This makes it quite similar to phc2sys which has the same ability, just that ts2phc can give much better performance if the hardware can assist with that. The overall board design for my use case is that there's an SoC with an embedded DSA switch, and hanging off of 3 ports of that embedded switch are 3 external switches. Every networking device (the DSA master for the embedded switch, the embedded switch, as well as each individual external switch) has a PTP clock. The topology for PPS signal distribution is fixed - that is given by hardware ability - the /dev/ptp1 clock can emit a valid PPS, and all external switches can timestamp that PPS (it is connected in a sort-of simplex "bus" design), and it cannot be any other way around. It looks like this: +---------------------------------------------------------------+ | LS1028A /dev/ptp0 (unused) | | +------------------------------+ | | | DSA master for Felix | | | |(internal ENETC port 2: eno2))| | | +------------+------------------------------+-------------+ | | | Felix embedded L2 switch /dev/ptp1 | | | | PPS master, sync slave | | | | +--------------+ +--------------+ +--------------+ | | | | |DSA master for| |DSA master for| |DSA master for| | | | | | SJA1105 1 | | SJA1105 2 | | SJA1105 3 | | | | | |(Felix port 1)| |(Felix port 2)| |(Felix port 3)| | | +--+-+--------------+---+--------------+---+--------------+--+--+ /dev/ptp2 /dev/ptp3 /dev/ptp4 PPS slave, sync master PPS slave, sync slave PPS slave, sync slave +-----------------------+ +-----------------------+ +-----------------------+ | SJA1105 switch 1 | | SJA1105 switch 2 | | SJA1105 switch 3 | +-----+-----+-----+-----+ +-----+-----+-----+-----+ +-----+-----+-----+-----+ |sw1p0|sw1p1|sw1p2|sw1p3| |sw2p0|sw2p1|sw2p2|sw2p3| |sw3p0|sw3p1|sw3p2|sw3p3| +-----+-----+-----+-----+ +-----+-----+-----+-----+ +-----+-----+-----+-----+ ^ | GM connected here In text, it would be described as this: cat ts2phc.cfg [global] first_step_threshold 0.00002 step_threshold 0.00002 ts2phc.pulsewidth 500000000 ts2phc.perout_phase 0 # Felix [/dev/ptp1] ts2phc.master 1 # SJA1105 switch 1 [/dev/ptp2] ts2phc.channel 0 ts2phc.extts_polarity both # SJA1105 switch 2 [/dev/ptp3] ts2phc.channel 0 ts2phc.extts_polarity both # SJA1105 switch 3 [/dev/ptp4] ts2phc.channel 0 ts2phc.extts_polarity both cat gPTP.cfg [global] gmCapable 1 priority1 248 priority2 248 logAnnounceInterval 0 logSyncInterval -3 syncReceiptTimeout 3 neighborPropDelayThresh 50000 min_neighbor_prop_delay -20000000 assume_two_step 1 path_trace_enabled 1 follow_up_info 1 transportSpecific 0x1 ptp_dst_mac 01:80:C2:00:00:0E network_transport L2 delay_mechanism P2P step_threshold 0.00002 tx_timestamp_timeout 20 boundary_clock_jbod 1 [sw1p0] [sw1p1] [sw1p2] [sw1p3] [sw2p0] [sw2p1] [sw2p2] [sw2p3] [sw3p0] [sw3p1] [sw3p2] [sw3p3] At a high level, what I have done is: - I moved the PMC related code from phc2sys into pmc_common.c, for ts2phc reuse - I created an extra abstraction in ts2phc as "struct clock" that would represent what's synchronizable. The "master" and "slave" concepts retain their meaning, which is: "master" == the device that emits PPS, and "slave" == the device that timestamps PPS. The changes should be backwards-compatible with the non-automatic mode. I have only tested non-automatic mode with a PHC master (that's all I have) and it still appears to work as before. Vladimir Oltean (15): posix_clock_open: derive PHC index from device name if possible phc2sys: rename struct node to struct phc2sys_private phc2sys: break out pmc code into pmc_common.c pmc_common: fix potential memory leak in run_pmc_events() ts2phc: create a private data structure ts2phc: instantiate a full clock structure for every slave PHC ts2phc: instantiate a full clock structure for every PHC master ts2phc: instantiate a pmc node ts2phc_slave: print master offset ts2phc: split slave poll from servo loop tmv: introduce a conversion helper from ptp_clock_time tmv: introduce an initializer from nanoseconds ts2phc: reconfigure sync direction by subscribing to ptp4l port events ts2phc: allow the PHC PPS master to be synchronized ts2phc_phc_master: make use of new kernel API for perout waveform config.c | 1 + makefile | 3 +- missing.h | 53 ++++ phc2sys.c | 667 +++++++++++----------------------------- pmc_common.c | 342 ++++++++++++++++++++ pmc_common.h | 35 +++ tmv.h | 15 + ts2phc.8 | 5 + ts2phc.c | 621 ++++++++++++++++++++++++++++++++++--- ts2phc.h | 77 +++++ ts2phc_generic_master.c | 2 +- ts2phc_generic_master.h | 3 +- ts2phc_master.c | 10 +- ts2phc_master.h | 8 +- ts2phc_master_private.h | 1 + ts2phc_nmea_master.c | 5 +- ts2phc_nmea_master.h | 3 +- ts2phc_phc_master.c | 70 +++-- ts2phc_phc_master.h | 3 +- ts2phc_slave.c | 383 ++++++++++++----------- ts2phc_slave.h | 10 +- util.c | 10 + 22 files changed, 1577 insertions(+), 750 deletions(-) create mode 100644 ts2phc.h -- 2.25.1 |
|
From: Vladimir O. <ol...@gm...> - 2020-08-01 17:46:45
|
Eliminate the ad-hoc use of global variables in the ts2phc program by
introducing one data structure that incorporates them. This might make
the code more understandable to people coming from a kernel background,
since it resembles the type of data organization used there. It is also
now closer to the data organization of phc2sys, a similar program in
both purpose and implementation.
Signed-off-by: Vladimir Oltean <ol...@gm...>
---
ts2phc.c | 64 ++++++++++++-----------
ts2phc.h | 37 ++++++++++++++
ts2phc_slave.c | 136 ++++++++++++++++++++++++++++---------------------
ts2phc_slave.h | 10 ++--
4 files changed, 153 insertions(+), 94 deletions(-)
create mode 100644 ts2phc.h
diff --git a/ts2phc.c b/ts2phc.c
index 23428586ef66..0be7b18bda71 100644
--- a/ts2phc.c
+++ b/ts2phc.c
@@ -11,22 +11,21 @@
#include "config.h"
#include "interface.h"
#include "print.h"
-#include "ts2phc_master.h"
-#include "ts2phc_slave.h"
+#include "ts2phc.h"
#include "version.h"
struct interface {
STAILQ_ENTRY(interface) list;
};
-static void ts2phc_cleanup(struct config *cfg, struct ts2phc_master *master)
+static void ts2phc_cleanup(struct ts2phc_private *priv)
{
- ts2phc_slave_cleanup();
- if (master) {
- ts2phc_master_destroy(master);
+ ts2phc_slave_cleanup(priv);
+ if (priv->master) {
+ ts2phc_master_destroy(priv->master);
}
- if (cfg) {
- config_destroy(cfg);
+ if (priv->cfg) {
+ config_destroy(priv->cfg);
}
}
@@ -56,8 +55,8 @@ static void usage(char *progname)
int main(int argc, char *argv[])
{
int c, err = 0, have_slave = 0, index, print_level;
- struct ts2phc_master *master = NULL;
enum ts2phc_master_type pps_type;
+ struct ts2phc_private priv = {0};
char *config = NULL, *progname;
const char *pps_source = NULL;
struct config *cfg = NULL;
@@ -68,7 +67,7 @@ int main(int argc, char *argv[])
cfg = config_create();
if (!cfg) {
- ts2phc_cleanup(cfg, master);
+ ts2phc_cleanup(&priv);
return -1;
}
@@ -81,14 +80,14 @@ int main(int argc, char *argv[])
switch (c) {
case 0:
if (config_parse_option(cfg, opts[index].name, optarg)) {
- ts2phc_cleanup(cfg, master);
+ ts2phc_cleanup(&priv);
return -1;
}
break;
case 'c':
if (!config_create_interface(optarg, cfg)) {
fprintf(stderr, "failed to add slave\n");
- ts2phc_cleanup(cfg, master);
+ ts2phc_cleanup(&priv);
return -1;
}
have_slave = 1;
@@ -99,7 +98,7 @@ int main(int argc, char *argv[])
case 'l':
if (get_arg_val_i(c, optarg, &print_level,
PRINT_LEVEL_MIN, PRINT_LEVEL_MAX)) {
- ts2phc_cleanup(cfg, master);
+ ts2phc_cleanup(&priv);
return -1;
}
config_set_int(cfg, "logging_level", print_level);
@@ -116,29 +115,29 @@ int main(int argc, char *argv[])
case 's':
if (pps_source) {
fprintf(stderr, "too many PPS sources\n");
- ts2phc_cleanup(cfg, master);
+ ts2phc_cleanup(&priv);
return -1;
}
pps_source = optarg;
break;
case 'v':
- ts2phc_cleanup(cfg, master);
+ ts2phc_cleanup(&priv);
version_show(stdout);
return 0;
case 'h':
- ts2phc_cleanup(cfg, master);
+ ts2phc_cleanup(&priv);
usage(progname);
return -1;
case '?':
default:
- ts2phc_cleanup(cfg, master);
+ ts2phc_cleanup(&priv);
usage(progname);
return -1;
}
}
if (config && (c = config_read(config, cfg))) {
fprintf(stderr, "failed to read config\n");
- ts2phc_cleanup(cfg, master);
+ ts2phc_cleanup(&priv);
return -1;
}
print_set_progname(progname);
@@ -147,18 +146,21 @@ int main(int argc, char *argv[])
print_set_syslog(config_get_int(cfg, NULL, "use_syslog"));
print_set_level(config_get_int(cfg, NULL, "logging_level"));
+ STAILQ_INIT(&priv.slaves);
+ priv.cfg = cfg;
+
STAILQ_FOREACH(iface, &cfg->interfaces, list) {
if (1 == config_get_int(cfg, interface_name(iface), "ts2phc.master")) {
if (pps_source) {
fprintf(stderr, "too many PPS sources\n");
- ts2phc_cleanup(cfg, master);
+ ts2phc_cleanup(&priv);
return -1;
}
pps_source = interface_name(iface);
} else {
- if (ts2phc_slave_add(cfg, interface_name(iface))) {
+ if (ts2phc_slave_add(&priv, interface_name(iface))) {
fprintf(stderr, "failed to add slave\n");
- ts2phc_cleanup(cfg, master);
+ ts2phc_cleanup(&priv);
return -1;
}
have_slave = 1;
@@ -166,19 +168,19 @@ int main(int argc, char *argv[])
}
if (!have_slave) {
fprintf(stderr, "no slave clocks specified\n");
- ts2phc_cleanup(cfg, master);
+ ts2phc_cleanup(&priv);
usage(progname);
return -1;
}
if (!pps_source) {
fprintf(stderr, "no PPS source specified\n");
- ts2phc_cleanup(cfg, master);
+ ts2phc_cleanup(&priv);
usage(progname);
return -1;
}
- if (ts2phc_slave_arm()) {
- fprintf(stderr, "failed to arm slaves\n");
- ts2phc_cleanup(cfg, master);
+ if (ts2phc_slaves_init(&priv)) {
+ fprintf(stderr, "failed to initialize slaves\n");
+ ts2phc_cleanup(&priv);
return -1;
}
@@ -189,21 +191,21 @@ int main(int argc, char *argv[])
} else {
pps_type = TS2PHC_MASTER_PHC;
}
- master = ts2phc_master_create(cfg, pps_source, pps_type);
- if (!master) {
+ priv.master = ts2phc_master_create(cfg, pps_source, pps_type);
+ if (!priv.master) {
fprintf(stderr, "failed to create master\n");
- ts2phc_cleanup(cfg, master);
+ ts2phc_cleanup(&priv);
return -1;
}
while (is_running()) {
- err = ts2phc_slave_poll(master);
+ err = ts2phc_slave_poll(&priv);
if (err) {
pr_err("poll failed");
break;
}
}
- ts2phc_cleanup(cfg, master);
+ ts2phc_cleanup(&priv);
return err;
}
diff --git a/ts2phc.h b/ts2phc.h
new file mode 100644
index 000000000000..a5d50fc7e3be
--- /dev/null
+++ b/ts2phc.h
@@ -0,0 +1,37 @@
+/**
+ * @file ts2phc.h
+ * @brief Structure definitions for ts2phc
+ * @note Copyright 2020 Vladimir Oltean <ol...@gm...>
+ *
+ * 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.
+ */
+
+#ifndef HAVE_TS2PHC_H
+#define HAVE_TS2PHC_H
+
+struct ts2phc_slave_array;
+
+struct ts2phc_private {
+ struct ts2phc_master *master;
+ STAILQ_HEAD(slave_ifaces_head, ts2phc_slave) slaves;
+ unsigned int n_slaves;
+ struct ts2phc_slave_array *polling_array;
+ struct config *cfg;
+};
+
+#include "ts2phc_master.h"
+#include "ts2phc_slave.h"
+
+#endif
diff --git a/ts2phc_slave.c b/ts2phc_slave.c
index 749efe5f81ba..7b4fbfa70440 100644
--- a/ts2phc_slave.c
+++ b/ts2phc_slave.c
@@ -21,8 +21,7 @@
#include "phc.h"
#include "print.h"
#include "servo.h"
-#include "ts2phc_master.h"
-#include "ts2phc_slave.h"
+#include "ts2phc.h"
#include "util.h"
#define NS_PER_SEC 1000000000LL
@@ -47,7 +46,7 @@ struct ts2phc_slave {
struct ts2phc_slave_array {
struct ts2phc_slave **slave;
struct pollfd *pfd;
-} polling_array;
+};
struct ts2phc_source_timestamp {
struct timespec ts;
@@ -65,49 +64,55 @@ static enum extts_result ts2phc_slave_offset(struct ts2phc_slave *slave,
int64_t *offset,
uint64_t *local_ts);
-static STAILQ_HEAD(slave_ifaces_head, ts2phc_slave) ts2phc_slaves =
- STAILQ_HEAD_INITIALIZER(ts2phc_slaves);
-
-static unsigned int ts2phc_n_slaves;
-
-static int ts2phc_slave_array_create(void)
+static int ts2phc_slave_array_create(struct ts2phc_private *priv)
{
+ struct ts2phc_slave_array *polling_array;
struct ts2phc_slave *slave;
unsigned int i;
- if (polling_array.slave) {
- return 0;
+ polling_array = malloc(sizeof(*polling_array));
+ if (!polling_array) {
+ pr_err("low memory");
+ return -1;
}
- polling_array.slave = malloc(ts2phc_n_slaves * sizeof(*polling_array.slave));
- if (!polling_array.slave) {
+
+ polling_array->slave = malloc(priv->n_slaves *
+ sizeof(*polling_array->slave));
+ if (!polling_array->slave) {
pr_err("low memory");
return -1;
}
- polling_array.pfd = malloc(ts2phc_n_slaves * sizeof(*polling_array.pfd));
- if (!polling_array.pfd) {
+ polling_array->pfd = malloc(priv->n_slaves *
+ sizeof(*polling_array->pfd));
+ if (!polling_array->pfd) {
pr_err("low memory");
- free(polling_array.slave);
- polling_array.slave = NULL;
+ free(polling_array->slave);
+ polling_array->slave = NULL;
return -1;
}
i = 0;
- STAILQ_FOREACH(slave, &ts2phc_slaves, list) {
- polling_array.slave[i] = slave;
+ STAILQ_FOREACH(slave, &priv->slaves, list) {
+ polling_array->slave[i] = slave;
i++;
}
- for (i = 0; i < ts2phc_n_slaves; i++) {
- polling_array.pfd[i].events = POLLIN | POLLPRI;
- polling_array.pfd[i].fd = polling_array.slave[i]->fd;
+ for (i = 0; i < priv->n_slaves; i++) {
+ polling_array->pfd[i].events = POLLIN | POLLPRI;
+ polling_array->pfd[i].fd = polling_array->slave[i]->fd;
}
+
+ priv->polling_array = polling_array;
+
return 0;
}
-static void ts2phc_slave_array_destroy(void)
+static void ts2phc_slave_array_destroy(struct ts2phc_private *priv)
{
- free(polling_array.slave);
- free(polling_array.pfd);
- polling_array.slave = NULL;
- polling_array.pfd = NULL;
+ struct ts2phc_slave_array *polling_array = priv->polling_array;
+
+ free(polling_array->slave);
+ free(polling_array->pfd);
+ polling_array->slave = NULL;
+ polling_array->pfd = NULL;
}
static int ts2phc_slave_clear_fifo(struct ts2phc_slave *slave)
@@ -143,9 +148,10 @@ static int ts2phc_slave_clear_fifo(struct ts2phc_slave *slave)
return 0;
}
-static struct ts2phc_slave *ts2phc_slave_create(struct config *cfg, const char *device)
+static struct ts2phc_slave *ts2phc_slave_create(struct ts2phc_private *priv,
+ const char *device)
{
- enum servo_type servo = config_get_int(cfg, NULL, "clock_servo");
+ enum servo_type servo = config_get_int(priv->cfg, NULL, "clock_servo");
int err, fadj, junk, max_adj, pulsewidth;
struct ptp_extts_request extts;
struct ts2phc_slave *slave;
@@ -161,13 +167,18 @@ static struct ts2phc_slave *ts2phc_slave_create(struct config *cfg, const char *
free(slave);
return NULL;
}
- slave->pin_desc.index = config_get_int(cfg, device, "ts2phc.pin_index");
+ slave->pin_desc.index = config_get_int(priv->cfg, device,
+ "ts2phc.pin_index");
slave->pin_desc.func = PTP_PF_EXTTS;
- slave->pin_desc.chan = config_get_int(cfg, device, "ts2phc.channel");
- slave->polarity = config_get_int(cfg, device, "ts2phc.extts_polarity");
- slave->correction = config_get_int(cfg, device, "ts2phc.extts_correction");
-
- pulsewidth = config_get_int(cfg, device, "ts2phc.pulsewidth");
+ slave->pin_desc.chan = config_get_int(priv->cfg, device,
+ "ts2phc.channel");
+ slave->polarity = config_get_int(priv->cfg, device,
+ "ts2phc.extts_polarity");
+ slave->correction = config_get_int(priv->cfg, device,
+ "ts2phc.extts_correction");
+
+ pulsewidth = config_get_int(priv->cfg, device,
+ "ts2phc.pulsewidth");
pulsewidth /= 2;
slave->ignore_upper = 1000000000 - pulsewidth;
slave->ignore_lower = pulsewidth;
@@ -177,7 +188,7 @@ static struct ts2phc_slave *ts2phc_slave_create(struct config *cfg, const char *
pr_err("failed to open clock");
goto no_posix_clock;
}
- slave->no_adj = config_get_int(cfg, NULL, "free_running");
+ slave->no_adj = config_get_int(priv->cfg, NULL, "free_running");
slave->fd = CLOCKID_TO_FD(slave->clk);
pr_debug("PHC slave %s has ptp index %d", device, junk);
@@ -190,7 +201,7 @@ static struct ts2phc_slave *ts2phc_slave_create(struct config *cfg, const char *
max_adj = phc_max_adj(slave->clk);
- slave->servo = servo_create(cfg, servo, -fadj, max_adj, 0);
+ slave->servo = servo_create(priv->cfg, servo, -fadj, max_adj, 0);
if (!slave->servo) {
pr_err("failed to create servo");
goto no_servo;
@@ -346,28 +357,28 @@ static enum extts_result ts2phc_slave_offset(struct ts2phc_slave *slave,
/* public methods */
-int ts2phc_slave_add(struct config *cfg, const char *name)
+int ts2phc_slave_add(struct ts2phc_private *priv, const char *name)
{
struct ts2phc_slave *slave;
/* Create each interface only once. */
- STAILQ_FOREACH(slave, &ts2phc_slaves, list) {
+ STAILQ_FOREACH(slave, &priv->slaves, list) {
if (0 == strcmp(name, slave->name)) {
return 0;
}
}
- slave = ts2phc_slave_create(cfg, name);
+ slave = ts2phc_slave_create(priv, name);
if (!slave) {
pr_err("failed to create slave");
return -1;
}
- STAILQ_INSERT_TAIL(&ts2phc_slaves, slave, list);
- ts2phc_n_slaves++;
+ STAILQ_INSERT_TAIL(&priv->slaves, slave, list);
+ priv->n_slaves++;
return 0;
}
-int ts2phc_slave_arm(void)
+int ts2phc_slave_arm(struct ts2phc_private *priv)
{
struct ptp_extts_request extts;
struct ts2phc_slave *slave;
@@ -375,7 +386,7 @@ int ts2phc_slave_arm(void)
memset(&extts, 0, sizeof(extts));
- STAILQ_FOREACH(slave, &ts2phc_slaves, list) {
+ STAILQ_FOREACH(slave, &priv->slaves, list) {
extts.index = slave->pin_desc.chan;
extts.flags = slave->polarity | PTP_ENABLE_FEATURE;
err = ioctl(slave->fd, PTP_EXTTS_REQUEST2, &extts);
@@ -387,29 +398,38 @@ int ts2phc_slave_arm(void)
return 0;
}
-void ts2phc_slave_cleanup(void)
+int ts2phc_slaves_init(struct ts2phc_private *priv)
+{
+ int err;
+
+ err = ts2phc_slave_array_create(priv);
+ if (err)
+ return err;
+
+ return ts2phc_slave_arm(priv);
+}
+
+void ts2phc_slave_cleanup(struct ts2phc_private *priv)
{
struct ts2phc_slave *slave;
- ts2phc_slave_array_destroy();
+ ts2phc_slave_array_destroy(priv);
- while ((slave = STAILQ_FIRST(&ts2phc_slaves))) {
- STAILQ_REMOVE_HEAD(&ts2phc_slaves, list);
+ while ((slave = STAILQ_FIRST(&priv->slaves))) {
+ STAILQ_REMOVE_HEAD(&priv->slaves, list);
ts2phc_slave_destroy(slave);
- ts2phc_n_slaves--;
+ priv->n_slaves--;
}
}
-int ts2phc_slave_poll(struct ts2phc_master *master)
+int ts2phc_slave_poll(struct ts2phc_private *priv)
{
+ struct ts2phc_slave_array *polling_array = priv->polling_array;
struct ts2phc_source_timestamp source_ts;
unsigned int i;
int cnt, err;
- if (ts2phc_slave_array_create()) {
- return -1;
- }
- cnt = poll(polling_array.pfd, ts2phc_n_slaves, 2000);
+ cnt = poll(polling_array->pfd, priv->n_slaves, 2000);
if (cnt < 0) {
if (EINTR == errno) {
return 0;
@@ -422,12 +442,12 @@ int ts2phc_slave_poll(struct ts2phc_master *master)
return 0;
}
- err = ts2phc_master_getppstime(master, &source_ts.ts);
+ err = ts2phc_master_getppstime(priv->master, &source_ts.ts);
source_ts.valid = err ? false : true;
- for (i = 0; i < ts2phc_n_slaves; i++) {
- if (polling_array.pfd[i].revents & (POLLIN|POLLPRI)) {
- ts2phc_slave_event(polling_array.slave[i], source_ts);
+ for (i = 0; i < priv->n_slaves; i++) {
+ if (polling_array->pfd[i].revents & (POLLIN|POLLPRI)) {
+ ts2phc_slave_event(polling_array->slave[i], source_ts);
}
}
return 0;
diff --git a/ts2phc_slave.h b/ts2phc_slave.h
index 2de5ab7dd0ff..1bad9d297799 100644
--- a/ts2phc_slave.h
+++ b/ts2phc_slave.h
@@ -7,14 +7,14 @@
#ifndef HAVE_TS2PHC_SLAVE_H
#define HAVE_TS2PHC_SLAVE_H
-#include "ts2phc_master.h"
+#include "ts2phc.h"
-int ts2phc_slave_add(struct config *cfg, const char *name);
+int ts2phc_slave_add(struct ts2phc_private *priv, const char *name);
-int ts2phc_slave_arm(void);
+int ts2phc_slaves_init(struct ts2phc_private *priv);
-void ts2phc_slave_cleanup(void);
+void ts2phc_slave_cleanup(struct ts2phc_private *priv);
-int ts2phc_slave_poll(struct ts2phc_master *master);
+int ts2phc_slave_poll(struct ts2phc_private *priv);
#endif
--
2.25.1
|
|
From: Jacob K. <jac...@in...> - 2020-08-05 23:31:14
|
On 8/1/2020 10:46 AM, Vladimir Oltean wrote:
> Eliminate the ad-hoc use of global variables in the ts2phc program by
> introducing one data structure that incorporates them. This might make
> the code more understandable to people coming from a kernel background,
> since it resembles the type of data organization used there. It is also
> now closer to the data organization of phc2sys, a similar program in
> both purpose and implementation.
>
> Signed-off-by: Vladimir Oltean <ol...@gm...>
This patch is a bit difficult to read because a number of things get
moved at once. Hoever, I think it's a significant improvement on the
current state of things, and trying to do this transition piece-meal
would be difficult.
Avoiding global variables here is definitely an improvement, as it makes
it easier to think about who has access to what data.
Reviewed-by: Jacob Keller <jac...@in...>
> ---
> ts2phc.c | 64 ++++++++++++-----------
> ts2phc.h | 37 ++++++++++++++
> ts2phc_slave.c | 136 ++++++++++++++++++++++++++++---------------------
> ts2phc_slave.h | 10 ++--
> 4 files changed, 153 insertions(+), 94 deletions(-)
> create mode 100644 ts2phc.h
>
> diff --git a/ts2phc.c b/ts2phc.c
> index 23428586ef66..0be7b18bda71 100644
> --- a/ts2phc.c
> +++ b/ts2phc.c
> @@ -11,22 +11,21 @@
> #include "config.h"
> #include "interface.h"
> #include "print.h"
> -#include "ts2phc_master.h"
> -#include "ts2phc_slave.h"
> +#include "ts2phc.h"
> #include "version.h"
>
> struct interface {
> STAILQ_ENTRY(interface) list;
> };
>
> -static void ts2phc_cleanup(struct config *cfg, struct ts2phc_master *master)
> +static void ts2phc_cleanup(struct ts2phc_private *priv)
> {
> - ts2phc_slave_cleanup();
> - if (master) {
> - ts2phc_master_destroy(master);
> + ts2phc_slave_cleanup(priv);
> + if (priv->master) {
> + ts2phc_master_destroy(priv->master);
> }
> - if (cfg) {
> - config_destroy(cfg);
> + if (priv->cfg) {
> + config_destroy(priv->cfg);
> }
> }
>
> @@ -56,8 +55,8 @@ static void usage(char *progname)
> int main(int argc, char *argv[])
> {
> int c, err = 0, have_slave = 0, index, print_level;
> - struct ts2phc_master *master = NULL;
> enum ts2phc_master_type pps_type;
> + struct ts2phc_private priv = {0};
> char *config = NULL, *progname;
> const char *pps_source = NULL;
> struct config *cfg = NULL;
> @@ -68,7 +67,7 @@ int main(int argc, char *argv[])
>
> cfg = config_create();
> if (!cfg) {
> - ts2phc_cleanup(cfg, master);
> + ts2phc_cleanup(&priv);
> return -1;
> }
>
> @@ -81,14 +80,14 @@ int main(int argc, char *argv[])
> switch (c) {
> case 0:
> if (config_parse_option(cfg, opts[index].name, optarg)) {
> - ts2phc_cleanup(cfg, master);
> + ts2phc_cleanup(&priv);
> return -1;
> }
> break;
> case 'c':
> if (!config_create_interface(optarg, cfg)) {
> fprintf(stderr, "failed to add slave\n");
> - ts2phc_cleanup(cfg, master);
> + ts2phc_cleanup(&priv);
> return -1;
> }
> have_slave = 1;
> @@ -99,7 +98,7 @@ int main(int argc, char *argv[])
> case 'l':
> if (get_arg_val_i(c, optarg, &print_level,
> PRINT_LEVEL_MIN, PRINT_LEVEL_MAX)) {
> - ts2phc_cleanup(cfg, master);
> + ts2phc_cleanup(&priv);
> return -1;
> }
> config_set_int(cfg, "logging_level", print_level);
> @@ -116,29 +115,29 @@ int main(int argc, char *argv[])
> case 's':
> if (pps_source) {
> fprintf(stderr, "too many PPS sources\n");
> - ts2phc_cleanup(cfg, master);
> + ts2phc_cleanup(&priv);
> return -1;
> }
> pps_source = optarg;
> break;
> case 'v':
> - ts2phc_cleanup(cfg, master);
> + ts2phc_cleanup(&priv);
> version_show(stdout);
> return 0;
> case 'h':
> - ts2phc_cleanup(cfg, master);
> + ts2phc_cleanup(&priv);
> usage(progname);
> return -1;
> case '?':
> default:
> - ts2phc_cleanup(cfg, master);
> + ts2phc_cleanup(&priv);
> usage(progname);
> return -1;
> }
> }
> if (config && (c = config_read(config, cfg))) {
> fprintf(stderr, "failed to read config\n");
> - ts2phc_cleanup(cfg, master);
> + ts2phc_cleanup(&priv);
> return -1;
> }
> print_set_progname(progname);
> @@ -147,18 +146,21 @@ int main(int argc, char *argv[])
> print_set_syslog(config_get_int(cfg, NULL, "use_syslog"));
> print_set_level(config_get_int(cfg, NULL, "logging_level"));
>
> + STAILQ_INIT(&priv.slaves);
> + priv.cfg = cfg;
> +
> STAILQ_FOREACH(iface, &cfg->interfaces, list) {
> if (1 == config_get_int(cfg, interface_name(iface), "ts2phc.master")) {
> if (pps_source) {
> fprintf(stderr, "too many PPS sources\n");
> - ts2phc_cleanup(cfg, master);
> + ts2phc_cleanup(&priv);
> return -1;
> }
> pps_source = interface_name(iface);
> } else {
> - if (ts2phc_slave_add(cfg, interface_name(iface))) {
> + if (ts2phc_slave_add(&priv, interface_name(iface))) {
> fprintf(stderr, "failed to add slave\n");
> - ts2phc_cleanup(cfg, master);
> + ts2phc_cleanup(&priv);
> return -1;
> }
> have_slave = 1;
> @@ -166,19 +168,19 @@ int main(int argc, char *argv[])
> }
> if (!have_slave) {
> fprintf(stderr, "no slave clocks specified\n");
> - ts2phc_cleanup(cfg, master);
> + ts2phc_cleanup(&priv);
> usage(progname);
> return -1;
> }
> if (!pps_source) {
> fprintf(stderr, "no PPS source specified\n");
> - ts2phc_cleanup(cfg, master);
> + ts2phc_cleanup(&priv);
> usage(progname);
> return -1;
> }
> - if (ts2phc_slave_arm()) {
> - fprintf(stderr, "failed to arm slaves\n");
> - ts2phc_cleanup(cfg, master);
> + if (ts2phc_slaves_init(&priv)) {
> + fprintf(stderr, "failed to initialize slaves\n");
> + ts2phc_cleanup(&priv);
> return -1;
> }
>
> @@ -189,21 +191,21 @@ int main(int argc, char *argv[])
> } else {
> pps_type = TS2PHC_MASTER_PHC;
> }
> - master = ts2phc_master_create(cfg, pps_source, pps_type);
> - if (!master) {
> + priv.master = ts2phc_master_create(cfg, pps_source, pps_type);
> + if (!priv.master) {
> fprintf(stderr, "failed to create master\n");
> - ts2phc_cleanup(cfg, master);
> + ts2phc_cleanup(&priv);
> return -1;
> }
>
> while (is_running()) {
> - err = ts2phc_slave_poll(master);
> + err = ts2phc_slave_poll(&priv);
> if (err) {
> pr_err("poll failed");
> break;
> }
> }
>
> - ts2phc_cleanup(cfg, master);
> + ts2phc_cleanup(&priv);
> return err;
> }
> diff --git a/ts2phc.h b/ts2phc.h
> new file mode 100644
> index 000000000000..a5d50fc7e3be
> --- /dev/null
> +++ b/ts2phc.h
> @@ -0,0 +1,37 @@
> +/**
> + * @file ts2phc.h
> + * @brief Structure definitions for ts2phc
> + * @note Copyright 2020 Vladimir Oltean <ol...@gm...>
> + *
> + * 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.
> + */
> +
> +#ifndef HAVE_TS2PHC_H
> +#define HAVE_TS2PHC_H
> +
> +struct ts2phc_slave_array;
> +
> +struct ts2phc_private {
> + struct ts2phc_master *master;
> + STAILQ_HEAD(slave_ifaces_head, ts2phc_slave) slaves;
> + unsigned int n_slaves;
> + struct ts2phc_slave_array *polling_array;
> + struct config *cfg;
> +};
> +
> +#include "ts2phc_master.h"
> +#include "ts2phc_slave.h"
> +
> +#endif
> diff --git a/ts2phc_slave.c b/ts2phc_slave.c
> index 749efe5f81ba..7b4fbfa70440 100644
> --- a/ts2phc_slave.c
> +++ b/ts2phc_slave.c
> @@ -21,8 +21,7 @@
> #include "phc.h"
> #include "print.h"
> #include "servo.h"
> -#include "ts2phc_master.h"
> -#include "ts2phc_slave.h"
> +#include "ts2phc.h"
> #include "util.h"
>
> #define NS_PER_SEC 1000000000LL
> @@ -47,7 +46,7 @@ struct ts2phc_slave {
> struct ts2phc_slave_array {
> struct ts2phc_slave **slave;
> struct pollfd *pfd;
> -} polling_array;
> +};
>
> struct ts2phc_source_timestamp {
> struct timespec ts;
> @@ -65,49 +64,55 @@ static enum extts_result ts2phc_slave_offset(struct ts2phc_slave *slave,
> int64_t *offset,
> uint64_t *local_ts);
>
> -static STAILQ_HEAD(slave_ifaces_head, ts2phc_slave) ts2phc_slaves =
> - STAILQ_HEAD_INITIALIZER(ts2phc_slaves);
> -
> -static unsigned int ts2phc_n_slaves;
> -
> -static int ts2phc_slave_array_create(void)
> +static int ts2phc_slave_array_create(struct ts2phc_private *priv)
> {
> + struct ts2phc_slave_array *polling_array;
> struct ts2phc_slave *slave;
> unsigned int i;
>
> - if (polling_array.slave) {
> - return 0;
> + polling_array = malloc(sizeof(*polling_array));
> + if (!polling_array) {
> + pr_err("low memory");
> + return -1;
> }
> - polling_array.slave = malloc(ts2phc_n_slaves * sizeof(*polling_array.slave));
> - if (!polling_array.slave) {
> +
> + polling_array->slave = malloc(priv->n_slaves *
> + sizeof(*polling_array->slave));
> + if (!polling_array->slave) {
> pr_err("low memory");
> return -1;
> }
> - polling_array.pfd = malloc(ts2phc_n_slaves * sizeof(*polling_array.pfd));
> - if (!polling_array.pfd) {
> + polling_array->pfd = malloc(priv->n_slaves *
> + sizeof(*polling_array->pfd));
> + if (!polling_array->pfd) {
> pr_err("low memory");
> - free(polling_array.slave);
> - polling_array.slave = NULL;
> + free(polling_array->slave);
> + polling_array->slave = NULL;
> return -1;
> }
> i = 0;
> - STAILQ_FOREACH(slave, &ts2phc_slaves, list) {
> - polling_array.slave[i] = slave;
> + STAILQ_FOREACH(slave, &priv->slaves, list) {
> + polling_array->slave[i] = slave;
> i++;
> }
> - for (i = 0; i < ts2phc_n_slaves; i++) {
> - polling_array.pfd[i].events = POLLIN | POLLPRI;
> - polling_array.pfd[i].fd = polling_array.slave[i]->fd;
> + for (i = 0; i < priv->n_slaves; i++) {
> + polling_array->pfd[i].events = POLLIN | POLLPRI;
> + polling_array->pfd[i].fd = polling_array->slave[i]->fd;
> }
> +
> + priv->polling_array = polling_array;
> +
> return 0;
> }
>
> -static void ts2phc_slave_array_destroy(void)
> +static void ts2phc_slave_array_destroy(struct ts2phc_private *priv)
> {
> - free(polling_array.slave);
> - free(polling_array.pfd);
> - polling_array.slave = NULL;
> - polling_array.pfd = NULL;
> + struct ts2phc_slave_array *polling_array = priv->polling_array;
> +
> + free(polling_array->slave);
> + free(polling_array->pfd);
> + polling_array->slave = NULL;
> + polling_array->pfd = NULL;
> }
>
> static int ts2phc_slave_clear_fifo(struct ts2phc_slave *slave)
> @@ -143,9 +148,10 @@ static int ts2phc_slave_clear_fifo(struct ts2phc_slave *slave)
> return 0;
> }
>
> -static struct ts2phc_slave *ts2phc_slave_create(struct config *cfg, const char *device)
> +static struct ts2phc_slave *ts2phc_slave_create(struct ts2phc_private *priv,
> + const char *device)
> {
> - enum servo_type servo = config_get_int(cfg, NULL, "clock_servo");
> + enum servo_type servo = config_get_int(priv->cfg, NULL, "clock_servo");
> int err, fadj, junk, max_adj, pulsewidth;
> struct ptp_extts_request extts;
> struct ts2phc_slave *slave;
> @@ -161,13 +167,18 @@ static struct ts2phc_slave *ts2phc_slave_create(struct config *cfg, const char *
> free(slave);
> return NULL;
> }
> - slave->pin_desc.index = config_get_int(cfg, device, "ts2phc.pin_index");
> + slave->pin_desc.index = config_get_int(priv->cfg, device,
> + "ts2phc.pin_index");
> slave->pin_desc.func = PTP_PF_EXTTS;
> - slave->pin_desc.chan = config_get_int(cfg, device, "ts2phc.channel");
> - slave->polarity = config_get_int(cfg, device, "ts2phc.extts_polarity");
> - slave->correction = config_get_int(cfg, device, "ts2phc.extts_correction");
> -
> - pulsewidth = config_get_int(cfg, device, "ts2phc.pulsewidth");
> + slave->pin_desc.chan = config_get_int(priv->cfg, device,
> + "ts2phc.channel");
> + slave->polarity = config_get_int(priv->cfg, device,
> + "ts2phc.extts_polarity");
> + slave->correction = config_get_int(priv->cfg, device,
> + "ts2phc.extts_correction");
> +
> + pulsewidth = config_get_int(priv->cfg, device,
> + "ts2phc.pulsewidth");
> pulsewidth /= 2;
> slave->ignore_upper = 1000000000 - pulsewidth;
> slave->ignore_lower = pulsewidth;
> @@ -177,7 +188,7 @@ static struct ts2phc_slave *ts2phc_slave_create(struct config *cfg, const char *
> pr_err("failed to open clock");
> goto no_posix_clock;
> }
> - slave->no_adj = config_get_int(cfg, NULL, "free_running");
> + slave->no_adj = config_get_int(priv->cfg, NULL, "free_running");
> slave->fd = CLOCKID_TO_FD(slave->clk);
>
> pr_debug("PHC slave %s has ptp index %d", device, junk);
> @@ -190,7 +201,7 @@ static struct ts2phc_slave *ts2phc_slave_create(struct config *cfg, const char *
>
> max_adj = phc_max_adj(slave->clk);
>
> - slave->servo = servo_create(cfg, servo, -fadj, max_adj, 0);
> + slave->servo = servo_create(priv->cfg, servo, -fadj, max_adj, 0);
> if (!slave->servo) {
> pr_err("failed to create servo");
> goto no_servo;
> @@ -346,28 +357,28 @@ static enum extts_result ts2phc_slave_offset(struct ts2phc_slave *slave,
>
> /* public methods */
>
> -int ts2phc_slave_add(struct config *cfg, const char *name)
> +int ts2phc_slave_add(struct ts2phc_private *priv, const char *name)
> {
> struct ts2phc_slave *slave;
>
> /* Create each interface only once. */
> - STAILQ_FOREACH(slave, &ts2phc_slaves, list) {
> + STAILQ_FOREACH(slave, &priv->slaves, list) {
> if (0 == strcmp(name, slave->name)) {
> return 0;
> }
> }
> - slave = ts2phc_slave_create(cfg, name);
> + slave = ts2phc_slave_create(priv, name);
> if (!slave) {
> pr_err("failed to create slave");
> return -1;
> }
> - STAILQ_INSERT_TAIL(&ts2phc_slaves, slave, list);
> - ts2phc_n_slaves++;
> + STAILQ_INSERT_TAIL(&priv->slaves, slave, list);
> + priv->n_slaves++;
>
> return 0;
> }
>
> -int ts2phc_slave_arm(void)
> +int ts2phc_slave_arm(struct ts2phc_private *priv)
> {
> struct ptp_extts_request extts;
> struct ts2phc_slave *slave;
> @@ -375,7 +386,7 @@ int ts2phc_slave_arm(void)
>
> memset(&extts, 0, sizeof(extts));
>
> - STAILQ_FOREACH(slave, &ts2phc_slaves, list) {
> + STAILQ_FOREACH(slave, &priv->slaves, list) {
> extts.index = slave->pin_desc.chan;
> extts.flags = slave->polarity | PTP_ENABLE_FEATURE;
> err = ioctl(slave->fd, PTP_EXTTS_REQUEST2, &extts);
> @@ -387,29 +398,38 @@ int ts2phc_slave_arm(void)
> return 0;
> }
>
> -void ts2phc_slave_cleanup(void)
> +int ts2phc_slaves_init(struct ts2phc_private *priv)
> +{
> + int err;
> +
> + err = ts2phc_slave_array_create(priv);
> + if (err)
> + return err;
> +
> + return ts2phc_slave_arm(priv);
> +}
> +
> +void ts2phc_slave_cleanup(struct ts2phc_private *priv)
> {
> struct ts2phc_slave *slave;
>
> - ts2phc_slave_array_destroy();
> + ts2phc_slave_array_destroy(priv);
>
> - while ((slave = STAILQ_FIRST(&ts2phc_slaves))) {
> - STAILQ_REMOVE_HEAD(&ts2phc_slaves, list);
> + while ((slave = STAILQ_FIRST(&priv->slaves))) {
> + STAILQ_REMOVE_HEAD(&priv->slaves, list);
> ts2phc_slave_destroy(slave);
> - ts2phc_n_slaves--;
> + priv->n_slaves--;
> }
> }
>
> -int ts2phc_slave_poll(struct ts2phc_master *master)
> +int ts2phc_slave_poll(struct ts2phc_private *priv)
> {
> + struct ts2phc_slave_array *polling_array = priv->polling_array;
> struct ts2phc_source_timestamp source_ts;
> unsigned int i;
> int cnt, err;
>
> - if (ts2phc_slave_array_create()) {
> - return -1;
> - }
> - cnt = poll(polling_array.pfd, ts2phc_n_slaves, 2000);
> + cnt = poll(polling_array->pfd, priv->n_slaves, 2000);
> if (cnt < 0) {
> if (EINTR == errno) {
> return 0;
> @@ -422,12 +442,12 @@ int ts2phc_slave_poll(struct ts2phc_master *master)
> return 0;
> }
>
> - err = ts2phc_master_getppstime(master, &source_ts.ts);
> + err = ts2phc_master_getppstime(priv->master, &source_ts.ts);
> source_ts.valid = err ? false : true;
>
> - for (i = 0; i < ts2phc_n_slaves; i++) {
> - if (polling_array.pfd[i].revents & (POLLIN|POLLPRI)) {
> - ts2phc_slave_event(polling_array.slave[i], source_ts);
> + for (i = 0; i < priv->n_slaves; i++) {
> + if (polling_array->pfd[i].revents & (POLLIN|POLLPRI)) {
> + ts2phc_slave_event(polling_array->slave[i], source_ts);
> }
> }
> return 0;
> diff --git a/ts2phc_slave.h b/ts2phc_slave.h
> index 2de5ab7dd0ff..1bad9d297799 100644
> --- a/ts2phc_slave.h
> +++ b/ts2phc_slave.h
> @@ -7,14 +7,14 @@
> #ifndef HAVE_TS2PHC_SLAVE_H
> #define HAVE_TS2PHC_SLAVE_H
>
> -#include "ts2phc_master.h"
> +#include "ts2phc.h"
>
> -int ts2phc_slave_add(struct config *cfg, const char *name);
> +int ts2phc_slave_add(struct ts2phc_private *priv, const char *name);
>
> -int ts2phc_slave_arm(void);
> +int ts2phc_slaves_init(struct ts2phc_private *priv);
>
> -void ts2phc_slave_cleanup(void);
> +void ts2phc_slave_cleanup(struct ts2phc_private *priv);
>
> -int ts2phc_slave_poll(struct ts2phc_master *master);
> +int ts2phc_slave_poll(struct ts2phc_private *priv);
>
> #endif
>
|
|
From: Vladimir O. <ol...@gm...> - 2020-08-01 17:46:51
|
Currently the PHC index is retrieved only through an ethtool ioctl if
the PHC is specified as an Ethernet interface. If it's a char device
such as /dev/ptp5, the phc_index will remain unpopulated. Try to infer
it from the char device's path.
This is useful when trying to determine whether multiple clocks are in
fact the same (such as /dev/ptp3 and sw1p3), just compare their PHC
index.
Signed-off-by: Vladimir Oltean <ol...@gm...>
---
util.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/util.c b/util.c
index 296dd59a08c1..027d694ea854 100644
--- a/util.c
+++ b/util.c
@@ -211,6 +211,16 @@ clockid_t posix_clock_open(const char *device, int *phc_index)
/* check if device is valid phc device */
clkid = phc_open(device);
if (clkid != CLOCK_INVALID) {
+ if (!strncmp(device, "/dev/ptp", strlen("/dev/ptp"))) {
+ int r = get_ranged_int(device + strlen("/dev/ptp"),
+ phc_index, 0, 65535);
+ if (r) {
+ fprintf(stderr,
+ "failed to parse PHC index from %s\n",
+ device);
+ return -1;
+ }
+ }
return clkid;
}
/* check if device is a valid ethernet device */
--
2.25.1
|
|
From: Vladimir O. <ol...@gm...> - 2020-08-01 17:46:51
|
The convention in all other parts of the code that call run_pmc() is to
free the management PTP message if an error code was returned, or pass
the message to the caller otherwise.
run_pmc_events() wasn't doing that, and was leaking a reference to the
message, while also discarding the return code from run_pmc(). Fix that.
Signed-off-by: Vladimir Oltean <ol...@gm...>
---
phc2sys.c | 8 +++++++-
pmc_common.c | 9 +++++++--
pmc_common.h | 2 +-
3 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/phc2sys.c b/phc2sys.c
index c4d72bd7d17a..6c048b887d0b 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -702,6 +702,7 @@ static int do_loop(struct phc2sys_private *priv, int subscriptions)
struct clock *clock;
uint64_t ts;
int64_t offset, delay;
+ int err;
interval.tv_sec = priv->phc_interval;
interval.tv_nsec = (priv->phc_interval - interval.tv_sec) * 1e9;
@@ -712,7 +713,12 @@ static int do_loop(struct phc2sys_private *priv, int subscriptions)
continue;
if (subscriptions) {
- run_pmc_events(&priv->node);
+ err = run_pmc_events(&priv->node);
+ if (err) {
+ pr_err("run_pmc_events returned %d", err);
+ return err;
+ }
+
if (priv->state_changed) {
/* force getting offset, as it may have
* changed after the port state change */
diff --git a/pmc_common.c b/pmc_common.c
index 89d7f40b84fe..cdc1eb4616ae 100644
--- a/pmc_common.c
+++ b/pmc_common.c
@@ -939,11 +939,16 @@ int run_pmc_subscribe(struct pmc_node *node, int timeout)
return 1;
}
-void run_pmc_events(struct pmc_node *node)
+int run_pmc_events(struct pmc_node *node)
{
struct ptp_message *msg;
+ int res;
- run_pmc(node, 0, -1, &msg);
+ res = run_pmc(node, 0, -1, &msg);
+ if (res <= 0)
+ return res;
+ msg_put(msg);
+ return 1;
}
int run_pmc_port_properties(struct pmc_node *node, int timeout,
diff --git a/pmc_common.h b/pmc_common.h
index a28bab767e9c..a3c7e956cba6 100644
--- a/pmc_common.h
+++ b/pmc_common.h
@@ -76,7 +76,7 @@ int run_pmc_subscribe(struct pmc_node *node, int timeout);
int run_pmc_clock_identity(struct pmc_node *node, int timeout);
int run_pmc_wait_sync(struct pmc_node *node, int timeout);
int run_pmc_get_number_ports(struct pmc_node *node, int timeout);
-void run_pmc_events(struct pmc_node *node);
+int run_pmc_events(struct pmc_node *node);
int run_pmc_port_properties(struct pmc_node *node, int timeout,
unsigned int port, int *state,
int *tstamping, char *iface);
--
2.25.1
|
|
From: Vladimir O. <ol...@gm...> - 2020-08-01 17:46:46
|
Slaves in ts2phc are PHC devices that implement the extts kernel API.
They are slaves just in the sense that they timestamp a pulse emitted by
somebody else.
Currently in ts2phc, PPS slaves are also the only candidates for the
clocks that get synchronized. There are 2 aspects that make this too
restrictive:
- Not all PPS slaves may be synchronization slaves. Consider a dynamic
environment of multiple DSA switches using boundary_clock_jbod, and
only one port is in the PS_SLAVE state. In that case, the clock of
that port should be the synchronization master (called the "source
clock" from now on, as far as ts2phc is concerned), regardless of
whether it supports the extts API or not.
- Not all synchronization slaves may be PPS slaves. Specifically, the
"PHC" type of PPS master in ts2phc can also be, fundamentally,
disciplined. The code should be prepared to handle this by recognizing
that things that can be disciplined by a servo should be represented
by a "struct clock", and things that can timestamp external events
should be represented by a "struct ts2phc_slave".
Signed-off-by: Vladimir Oltean <ol...@gm...>
---
ts2phc.c | 69 +++++++++++++++++++++++++++++++++++++++
ts2phc.h | 26 +++++++++++++++
ts2phc_slave.c | 88 ++++++++++++++++++++++----------------------------
3 files changed, 134 insertions(+), 49 deletions(-)
diff --git a/ts2phc.c b/ts2phc.c
index 0be7b18bda71..8a4071d083e3 100644
--- a/ts2phc.c
+++ b/ts2phc.c
@@ -7,12 +7,18 @@
* @note SPDX-License-Identifier: GPL-2.0+
*/
#include <stdlib.h>
+#include <net/if.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "clockadj.h"
#include "config.h"
#include "interface.h"
+#include "phc.h"
#include "print.h"
#include "ts2phc.h"
#include "version.h"
+#include "contain.h"
struct interface {
STAILQ_ENTRY(interface) list;
@@ -29,6 +35,69 @@ static void ts2phc_cleanup(struct ts2phc_private *priv)
}
}
+struct servo *servo_add(struct ts2phc_private *priv, struct clock *clock)
+{
+ enum servo_type type = config_get_int(priv->cfg, NULL, "clock_servo");
+ struct servo *servo;
+ int fadj, max_adj;
+
+ fadj = (int) clockadj_get_freq(clock->clkid);
+ /* Due to a bug in older kernels, the reading may silently fail
+ and return 0. Set the frequency back to make sure fadj is
+ the actual frequency of the clock. */
+ clockadj_set_freq(clock->clkid, fadj);
+
+ max_adj = phc_max_adj(clock->clkid);
+
+ servo = servo_create(priv->cfg, type, -fadj, max_adj, 0);
+ if (!servo)
+ return NULL;
+
+ servo_sync_interval(servo, SERVO_SYNC_INTERVAL);
+
+ return servo;
+}
+
+struct clock *clock_add(struct ts2phc_private *priv, const char *device)
+{
+ clockid_t clkid = CLOCK_INVALID;
+ int phc_index = -1;
+ struct clock *c;
+ int err;
+
+ clkid = posix_clock_open(device, &phc_index);
+ if (clkid == CLOCK_INVALID)
+ return NULL;
+
+ LIST_FOREACH(c, &priv->clocks, list) {
+ if (c->phc_index == phc_index) {
+ /* Already have the clock, don't add it again */
+ posix_clock_close(clkid);
+ return c;
+ }
+ }
+
+ c = calloc(1, sizeof(*c));
+ if (!c) {
+ pr_err("failed to allocate memory for a clock");
+ return NULL;
+ }
+ c->clkid = clkid;
+ c->phc_index = phc_index;
+ c->servo_state = SERVO_UNLOCKED;
+ c->servo = servo_add(priv, c);
+ c->no_adj = config_get_int(priv->cfg, NULL, "free_running");
+ err = asprintf(&c->name, "/dev/ptp%d", phc_index);
+ if (err < 0) {
+ free(c);
+ posix_clock_close(clkid);
+ return NULL;
+ }
+
+ LIST_INSERT_HEAD(&priv->clocks, c, list);
+ return c;
+}
+
static void usage(char *progname)
{
fprintf(stderr,
diff --git a/ts2phc.h b/ts2phc.h
index a5d50fc7e3be..135b795f11dc 100644
--- a/ts2phc.h
+++ b/ts2phc.h
@@ -21,16 +21,42 @@
#ifndef HAVE_TS2PHC_H
#define HAVE_TS2PHC_H
+#include <sys/queue.h>
+#include <time.h>
+#include "servo.h"
+
struct ts2phc_slave_array;
+#define SERVO_SYNC_INTERVAL 1.0
+
+struct clock {
+ LIST_ENTRY(clock) list;
+ LIST_ENTRY(clock) dst_list;
+ clockid_t clkid;
+ int phc_index;
+ int state;
+ int new_state;
+ struct servo *servo;
+ enum servo_state servo_state;
+ char *name;
+ int no_adj;
+ int is_destination;
+};
+
struct ts2phc_private {
struct ts2phc_master *master;
STAILQ_HEAD(slave_ifaces_head, ts2phc_slave) slaves;
unsigned int n_slaves;
struct ts2phc_slave_array *polling_array;
struct config *cfg;
+ struct clock *source;
+ LIST_HEAD(clock_head, clock) clocks;
};
+struct servo *servo_add(struct ts2phc_private *priv, struct clock *clock);
+struct clock *clock_add(struct ts2phc_private *priv, const char *device);
+void clock_add_tstamp(struct clock *clock, struct timespec ts);
+
#include "ts2phc_master.h"
#include "ts2phc_slave.h"
diff --git a/ts2phc_slave.c b/ts2phc_slave.c
index 7b4fbfa70440..5ed76518ea20 100644
--- a/ts2phc_slave.c
+++ b/ts2phc_slave.c
@@ -26,21 +26,17 @@
#define NS_PER_SEC 1000000000LL
#define SAMPLE_WEIGHT 1.0
-#define SERVO_SYNC_INTERVAL 1.0
struct ts2phc_slave {
char *name;
STAILQ_ENTRY(ts2phc_slave) list;
struct ptp_pin_desc pin_desc;
- enum servo_state state;
unsigned int polarity;
int32_t correction;
uint32_t ignore_lower;
uint32_t ignore_upper;
- struct servo *servo;
- clockid_t clk;
+ struct clock *clock;
int no_adj;
- int fd;
};
struct ts2phc_slave_array {
@@ -96,8 +92,10 @@ static int ts2phc_slave_array_create(struct ts2phc_private *priv)
i++;
}
for (i = 0; i < priv->n_slaves; i++) {
+ struct ts2phc_slave *slave = polling_array->slave[i];
+
polling_array->pfd[i].events = POLLIN | POLLPRI;
- polling_array->pfd[i].fd = polling_array->slave[i]->fd;
+ polling_array->pfd[i].fd = CLOCKID_TO_FD(slave->clock->clkid);
}
priv->polling_array = polling_array;
@@ -111,15 +109,15 @@ static void ts2phc_slave_array_destroy(struct ts2phc_private *priv)
free(polling_array->slave);
free(polling_array->pfd);
- polling_array->slave = NULL;
- polling_array->pfd = NULL;
+ free(polling_array);
+ priv->polling_array = NULL;
}
static int ts2phc_slave_clear_fifo(struct ts2phc_slave *slave)
{
struct pollfd pfd = {
.events = POLLIN | POLLPRI,
- .fd = slave->fd,
+ .fd = CLOCKID_TO_FD(slave->clock->clkid),
};
struct ptp_extts_event event;
int cnt, size;
@@ -151,10 +149,9 @@ static int ts2phc_slave_clear_fifo(struct ts2phc_slave *slave)
static struct ts2phc_slave *ts2phc_slave_create(struct ts2phc_private *priv,
const char *device)
{
- enum servo_type servo = config_get_int(priv->cfg, NULL, "clock_servo");
- int err, fadj, junk, max_adj, pulsewidth;
struct ptp_extts_request extts;
struct ts2phc_slave *slave;
+ int err, pulsewidth;
slave = calloc(1, sizeof(*slave));
if (!slave) {
@@ -183,33 +180,23 @@ static struct ts2phc_slave *ts2phc_slave_create(struct ts2phc_private *priv,
slave->ignore_upper = 1000000000 - pulsewidth;
slave->ignore_lower = pulsewidth;
- slave->clk = posix_clock_open(device, &junk);
- if (slave->clk == CLOCK_INVALID) {
+ slave->clock = clock_add(priv, device);
+ if (!slave->clock) {
pr_err("failed to open clock");
goto no_posix_clock;
}
- slave->no_adj = config_get_int(priv->cfg, NULL, "free_running");
- slave->fd = CLOCKID_TO_FD(slave->clk);
-
- pr_debug("PHC slave %s has ptp index %d", device, junk);
-
- fadj = (int) clockadj_get_freq(slave->clk);
- /* Due to a bug in older kernels, the reading may silently fail
- and return 0. Set the frequency back to make sure fadj is
- the actual frequency of the clock. */
- clockadj_set_freq(slave->clk, fadj);
- max_adj = phc_max_adj(slave->clk);
+ pr_debug("PHC slave %s has ptp index %d", device,
+ slave->clock->phc_index);
- slave->servo = servo_create(priv->cfg, servo, -fadj, max_adj, 0);
- if (!slave->servo) {
+ slave->clock->servo = servo_add(priv, slave->clock);
+ if (!slave->clock->servo) {
pr_err("failed to create servo");
goto no_servo;
}
- servo_sync_interval(slave->servo, SERVO_SYNC_INTERVAL);
- if (phc_number_pins(slave->clk) > 0) {
- err = phc_pin_setfunc(slave->clk, &slave->pin_desc);
+ if (phc_number_pins(slave->clock->clkid) > 0) {
+ err = phc_pin_setfunc(slave->clock->clkid, &slave->pin_desc);
if (err < 0) {
pr_err("PTP_PIN_SETFUNC request failed");
goto no_pin_func;
@@ -223,7 +210,8 @@ static struct ts2phc_slave *ts2phc_slave_create(struct ts2phc_private *priv,
memset(&extts, 0, sizeof(extts));
extts.index = slave->pin_desc.chan;
extts.flags = 0;
- if (ioctl(slave->fd, PTP_EXTTS_REQUEST2, &extts)) {
+ if (ioctl(CLOCKID_TO_FD(slave->clock->clkid), PTP_EXTTS_REQUEST2,
+ &extts)) {
pr_err(PTP_EXTTS_REQUEST_FAILED);
}
if (ts2phc_slave_clear_fifo(slave)) {
@@ -233,9 +221,9 @@ static struct ts2phc_slave *ts2phc_slave_create(struct ts2phc_private *priv,
return slave;
no_ext_ts:
no_pin_func:
- servo_destroy(slave->servo);
+ servo_destroy(slave->clock->servo);
no_servo:
- posix_clock_close(slave->clk);
+ posix_clock_close(slave->clock->clkid);
no_posix_clock:
free(slave->name);
free(slave);
@@ -249,11 +237,12 @@ static void ts2phc_slave_destroy(struct ts2phc_slave *slave)
memset(&extts, 0, sizeof(extts));
extts.index = slave->pin_desc.chan;
extts.flags = 0;
- if (ioctl(slave->fd, PTP_EXTTS_REQUEST2, &extts)) {
+ if (ioctl(CLOCKID_TO_FD(slave->clock->clkid), PTP_EXTTS_REQUEST2,
+ &extts)) {
pr_err(PTP_EXTTS_REQUEST_FAILED);
}
- servo_destroy(slave->servo);
- posix_clock_close(slave->clk);
+ servo_destroy(slave->clock->servo);
+ posix_clock_close(slave->clock->clkid);
free(slave->name);
free(slave);
}
@@ -281,27 +270,22 @@ static int ts2phc_slave_event(struct ts2phc_slave *slave,
return 0;
}
- if (!source_ts.valid) {
- pr_debug("%s ignoring invalid master time stamp", slave->name);
- return 0;
- }
-
- adj = servo_sample(slave->servo, offset, extts_ts,
- SAMPLE_WEIGHT, &slave->state);
+ adj = servo_sample(slave->clock->servo, offset, extts_ts,
+ SAMPLE_WEIGHT, &slave->clock->servo_state);
pr_debug("%s master offset %10" PRId64 " s%d freq %+7.0f",
- slave->name, offset, slave->state, adj);
+ slave->name, offset, slave->clock->servo_state, adj);
- switch (slave->state) {
+ switch (slave->clock->servo_state) {
case SERVO_UNLOCKED:
break;
case SERVO_JUMP:
- clockadj_set_freq(slave->clk, -adj);
- clockadj_step(slave->clk, -offset);
+ clockadj_set_freq(slave->clock->clkid, -adj);
+ clockadj_step(slave->clock->clkid, -offset);
break;
case SERVO_LOCKED:
case SERVO_LOCKED_STABLE:
- clockadj_set_freq(slave->clk, -adj);
+ clockadj_set_freq(slave->clock->clkid, -adj);
break;
}
return 0;
@@ -317,7 +301,7 @@ static enum extts_result ts2phc_slave_offset(struct ts2phc_slave *slave,
uint64_t event_ns, source_ns;
int cnt;
- cnt = read(slave->fd, &event, sizeof(event));
+ cnt = read(CLOCKID_TO_FD(slave->clock->clkid), &event, sizeof(event));
if (cnt != sizeof(event)) {
pr_err("read extts event failed: %m");
return EXTTS_ERROR;
@@ -389,7 +373,8 @@ int ts2phc_slave_arm(struct ts2phc_private *priv)
STAILQ_FOREACH(slave, &priv->slaves, list) {
extts.index = slave->pin_desc.chan;
extts.flags = slave->polarity | PTP_ENABLE_FEATURE;
- err = ioctl(slave->fd, PTP_EXTTS_REQUEST2, &extts);
+ err = ioctl(CLOCKID_TO_FD(slave->clock->clkid),
+ PTP_EXTTS_REQUEST2, &extts);
if (err < 0) {
pr_err(PTP_EXTTS_REQUEST_FAILED);
return -1;
@@ -445,6 +430,11 @@ int ts2phc_slave_poll(struct ts2phc_private *priv)
err = ts2phc_master_getppstime(priv->master, &source_ts.ts);
source_ts.valid = err ? false : true;
+ if (!source_ts.valid) {
+ pr_debug("ignoring invalid master time stamp");
+ return 0;
+ }
+
for (i = 0; i < priv->n_slaves; i++) {
if (polling_array->pfd[i].revents & (POLLIN|POLLPRI)) {
ts2phc_slave_event(polling_array->slave[i], source_ts);
--
2.25.1
|
|
From: Vladimir O. <ol...@gm...> - 2020-08-01 17:46:46
|
This propagates the use of "struct ts2phc_private" all the way into the
master API, in preparation of a new use case that will be supported
soon: some PPS masters (to be precise, the "PHC" kind) instantiate a
struct clock which could be disciplined by ts2phc.
When a PHC A emits a pulse and another PHC B timestamps it, the offset
between their precise timestamps can be used to synchronize either one
of them. So far in ts2phc, only the slave PHC (the one using extts) has
been synchronized to the master (the one using perout).
This is partly because there is no proper kernel API to report the
precise timestamp of a perout pulse. We only have the periodic API, and
that doesn't report precise timestamps either; we just use vague
approximations of what the PPS master PHC's time was, based on reading
that PHC immediately after a slave extts event was received by the
application. While this is far from ideal, it does work, and does allow
PHC A to be synchronized to B.
This is particularly useful when using the "automatic" mode of ts2phc,
and the PPS distribution tree is fixed in hardware (as opposed to port
states).
Signed-off-by: Vladimir Oltean <ol...@gm...>
---
ts2phc.c | 2 +-
ts2phc_generic_master.c | 2 +-
ts2phc_generic_master.h | 3 ++-
ts2phc_master.c | 10 ++++++----
ts2phc_master.h | 6 ++++--
ts2phc_nmea_master.c | 5 +++--
ts2phc_nmea_master.h | 3 ++-
ts2phc_phc_master.c | 33 +++++++++++++++++----------------
ts2phc_phc_master.h | 3 ++-
ts2phc_slave.c | 2 +-
10 files changed, 39 insertions(+), 30 deletions(-)
diff --git a/ts2phc.c b/ts2phc.c
index 8a4071d083e3..97e9718c999e 100644
--- a/ts2phc.c
+++ b/ts2phc.c
@@ -260,7 +260,7 @@ int main(int argc, char *argv[])
} else {
pps_type = TS2PHC_MASTER_PHC;
}
- priv.master = ts2phc_master_create(cfg, pps_source, pps_type);
+ priv.master = ts2phc_master_create(&priv, pps_source, pps_type);
if (!priv.master) {
fprintf(stderr, "failed to create master\n");
ts2phc_cleanup(&priv);
diff --git a/ts2phc_generic_master.c b/ts2phc_generic_master.c
index ad4f7f1cf1d7..05dd8f3742fc 100644
--- a/ts2phc_generic_master.c
+++ b/ts2phc_generic_master.c
@@ -47,7 +47,7 @@ static int ts2phc_generic_master_getppstime(struct ts2phc_master *m,
return 0;
}
-struct ts2phc_master *ts2phc_generic_master_create(struct config *cfg,
+struct ts2phc_master *ts2phc_generic_master_create(struct ts2phc_private *priv,
const char *dev)
{
struct ts2phc_generic_master *master;
diff --git a/ts2phc_generic_master.h b/ts2phc_generic_master.h
index ac0ce4f11cb8..c8fc099ad066 100644
--- a/ts2phc_generic_master.h
+++ b/ts2phc_generic_master.h
@@ -6,9 +6,10 @@
#ifndef HAVE_TS2PHC_GENERIC_MASTER_H
#define HAVE_TS2PHC_GENERIC_MASTER_H
+#include "ts2phc.h"
#include "ts2phc_master.h"
-struct ts2phc_master *ts2phc_generic_master_create(struct config *cfg,
+struct ts2phc_master *ts2phc_generic_master_create(struct ts2phc_private *priv,
const char *dev);
#endif
diff --git a/ts2phc_master.c b/ts2phc_master.c
index 9283580df3fc..4617c4aecbe5 100644
--- a/ts2phc_master.c
+++ b/ts2phc_master.c
@@ -3,25 +3,27 @@
* @note Copyright (C) 2019 Richard Cochran <ric...@gm...>
* @note SPDX-License-Identifier: GPL-2.0+
*/
+#include "ts2phc.h"
#include "ts2phc_generic_master.h"
#include "ts2phc_master_private.h"
#include "ts2phc_nmea_master.h"
#include "ts2phc_phc_master.h"
-struct ts2phc_master *ts2phc_master_create(struct config *cfg, const char *dev,
+struct ts2phc_master *ts2phc_master_create(struct ts2phc_private *priv,
+ const char *dev,
enum ts2phc_master_type type)
{
struct ts2phc_master *master = NULL;
switch (type) {
case TS2PHC_MASTER_GENERIC:
- master = ts2phc_generic_master_create(cfg, dev);
+ master = ts2phc_generic_master_create(priv, dev);
break;
case TS2PHC_MASTER_NMEA:
- master = ts2phc_nmea_master_create(cfg, dev);
+ master = ts2phc_nmea_master_create(priv, dev);
break;
case TS2PHC_MASTER_PHC:
- master = ts2phc_phc_master_create(cfg, dev);
+ master = ts2phc_phc_master_create(priv, dev);
break;
}
return master;
diff --git a/ts2phc_master.h b/ts2phc_master.h
index 79765b696d71..a7e7186f79a1 100644
--- a/ts2phc_master.h
+++ b/ts2phc_master.h
@@ -13,6 +13,7 @@ struct config;
/**
* Opaque type
*/
+struct ts2phc_private;
struct ts2phc_master;
/**
@@ -26,12 +27,13 @@ enum ts2phc_master_type {
/**
* Create a new instance of a PPS master clock.
- * @param cfg Pointer to a valid configuration.
+ * @param priv Pointer to the program's data structure.
* @param dev Name of the master clock or NULL.
* @param type The type of the clock to create.
* @return A pointer to a new PPS master clock on success, NULL otherwise.
*/
-struct ts2phc_master *ts2phc_master_create(struct config *cfg, const char *dev,
+struct ts2phc_master *ts2phc_master_create(struct ts2phc_private *priv,
+ const char *dev,
enum ts2phc_master_type type);
/**
diff --git a/ts2phc_nmea_master.c b/ts2phc_nmea_master.c
index 2b9af3b9f31f..70080f4fa225 100644
--- a/ts2phc_nmea_master.c
+++ b/ts2phc_nmea_master.c
@@ -198,7 +198,8 @@ static int ts2phc_nmea_master_getppstime(struct ts2phc_master *master,
return fix_valid ? lstab_error : -1;
}
-struct ts2phc_master *ts2phc_nmea_master_create(struct config *cfg, const char *dev)
+struct ts2phc_master *ts2phc_nmea_master_create(struct ts2phc_private *priv,
+ const char *dev)
{
struct ts2phc_nmea_master *master;
const char *leapfile = NULL; // TODO - read from config.
@@ -214,7 +215,7 @@ struct ts2phc_master *ts2phc_nmea_master_create(struct config *cfg, const char *
}
master->master.destroy = ts2phc_nmea_master_destroy;
master->master.getppstime = ts2phc_nmea_master_getppstime;
- master->config = cfg;
+ master->config = priv->cfg;
pthread_mutex_init(&master->mutex, NULL);
err = pthread_create(&master->worker, NULL, monitor_nmea_status, master);
if (err) {
diff --git a/ts2phc_nmea_master.h b/ts2phc_nmea_master.h
index 7430e20662b9..ddfbae48f83b 100644
--- a/ts2phc_nmea_master.h
+++ b/ts2phc_nmea_master.h
@@ -6,8 +6,9 @@
#ifndef HAVE_TS2PHC_NMEA_MASTER_H
#define HAVE_TS2PHC_NMEA_MASTER_H
+#include "ts2phc.h"
#include "ts2phc_master.h"
-struct ts2phc_master *ts2phc_nmea_master_create(struct config *cfg,
+struct ts2phc_master *ts2phc_nmea_master_create(struct ts2phc_private *priv,
const char *dev);
#endif
diff --git a/ts2phc_phc_master.c b/ts2phc_phc_master.c
index 9f1837bc80eb..363085279ae3 100644
--- a/ts2phc_phc_master.c
+++ b/ts2phc_phc_master.c
@@ -12,15 +12,14 @@
#include "phc.h"
#include "print.h"
#include "missing.h"
+#include "ts2phc.h"
#include "ts2phc_master_private.h"
-#include "ts2phc_phc_master.h"
#include "util.h"
struct ts2phc_phc_master {
struct ts2phc_master master;
- clockid_t clkid;
+ struct clock *clock;
int channel;
- int fd;
};
static int ts2phc_phc_master_activate(struct config *cfg, const char *dev,
@@ -38,10 +37,10 @@ static int ts2phc_phc_master_activate(struct config *cfg, const char *dev,
desc.func = PTP_PF_PEROUT;
desc.chan = master->channel;
- if (phc_pin_setfunc(master->clkid, &desc)) {
+ if (phc_pin_setfunc(master->clock->clkid, &desc)) {
pr_warning("Failed to set the pin. Continuing bravely on...");
}
- if (clock_gettime(master->clkid, &ts)) {
+ if (clock_gettime(master->clock->clkid, &ts)) {
perror("clock_gettime");
return -1;
}
@@ -52,7 +51,8 @@ static int ts2phc_phc_master_activate(struct config *cfg, const char *dev,
perout_request.period.sec = 1;
perout_request.period.nsec = 0;
- if (ioctl(master->fd, PTP_PEROUT_REQUEST2, &perout_request)) {
+ if (ioctl(CLOCKID_TO_FD(master->clock->clkid), PTP_PEROUT_REQUEST2,
+ &perout_request)) {
pr_err(PTP_PEROUT_REQUEST_FAILED);
return -1;
}
@@ -67,10 +67,11 @@ static void ts2phc_phc_master_destroy(struct ts2phc_master *master)
memset(&perout_request, 0, sizeof(perout_request));
perout_request.index = m->channel;
- if (ioctl(m->fd, PTP_PEROUT_REQUEST2, &perout_request)) {
+ if (ioctl(CLOCKID_TO_FD(m->clock->clkid), PTP_PEROUT_REQUEST2,
+ &perout_request)) {
pr_err(PTP_PEROUT_REQUEST_FAILED);
}
- posix_clock_close(m->clkid);
+ posix_clock_close(m->clock->clkid);
free(m);
}
@@ -79,14 +80,13 @@ static int ts2phc_phc_master_getppstime(struct ts2phc_master *m,
{
struct ts2phc_phc_master *master =
container_of(m, struct ts2phc_phc_master, master);
- return clock_gettime(master->clkid, ts);
+ return clock_gettime(master->clock->clkid, ts);
}
-struct ts2phc_master *ts2phc_phc_master_create(struct config *cfg,
+struct ts2phc_master *ts2phc_phc_master_create(struct ts2phc_private *priv,
const char *dev)
{
struct ts2phc_phc_master *master;
- int junk;
master = calloc(1, sizeof(*master));
if (!master) {
@@ -95,16 +95,17 @@ struct ts2phc_master *ts2phc_phc_master_create(struct config *cfg,
master->master.destroy = ts2phc_phc_master_destroy;
master->master.getppstime = ts2phc_phc_master_getppstime;
- master->clkid = posix_clock_open(dev, &junk);
- if (master->clkid == CLOCK_INVALID) {
+ master->clock = clock_add(priv, dev);
+ if (!master->clock) {
free(master);
return NULL;
}
- master->fd = CLOCKID_TO_FD(master->clkid);
+ master->clock->is_destination = 0;
- pr_debug("PHC master %s has ptp index %d", dev, junk);
+ pr_debug("PHC master %s has ptp index %d", dev,
+ master->clock->phc_index);
- if (ts2phc_phc_master_activate(cfg, dev, master)) {
+ if (ts2phc_phc_master_activate(priv->cfg, dev, master)) {
ts2phc_phc_master_destroy(&master->master);
return NULL;
}
diff --git a/ts2phc_phc_master.h b/ts2phc_phc_master.h
index 568df1a403d4..4ac03be7d16c 100644
--- a/ts2phc_phc_master.h
+++ b/ts2phc_phc_master.h
@@ -6,9 +6,10 @@
#ifndef HAVE_TS2PHC_PHC_MASTER_H
#define HAVE_TS2PHC_PHC_MASTER_H
+#include "ts2phc.h"
#include "ts2phc_master.h"
-struct ts2phc_master *ts2phc_phc_master_create(struct config *cfg,
+struct ts2phc_master *ts2phc_phc_master_create(struct ts2phc_private *priv,
const char *dev);
#endif
diff --git a/ts2phc_slave.c b/ts2phc_slave.c
index 5ed76518ea20..7a0522fb0f86 100644
--- a/ts2phc_slave.c
+++ b/ts2phc_slave.c
@@ -15,8 +15,8 @@
#include <time.h>
#include <unistd.h>
-#include "config.h"
#include "clockadj.h"
+#include "config.h"
#include "missing.h"
#include "phc.h"
#include "print.h"
--
2.25.1
|
|
From: Jacob K. <jac...@in...> - 2020-08-05 23:42:24
|
On 8/1/2020 10:46 AM, Vladimir Oltean wrote: > This is particularly useful when using the "automatic" mode of ts2phc, > and the PPS distribution tree is fixed in hardware (as opposed to port > states). > This refers to work not yet implemented by any of its parent commits. It might make sense to re-word it to be clear that this is about the future automatic mode, and why it's important for the case of a fixed tree. |
|
From: Vladimir O. <ol...@gm...> - 2020-08-01 17:46:51
|
This introduces the '-a' option in ts2phc, an option inspired from
phc2sys that puts the clocks in "automatic" mode. In this mode, ts2phc
listens, as a PMC, to port state change events from ptp4l, and detects
which port state machine, if any, has transitioned to PS_SLAVE. That
port's clock will become the synchronization master for the hierarchy
described by ts2phc.
The use case is a multi-switch DSA setup with boundary_clock_jbod, where
there is only one grandmaster, connected to one switch's port. The other
switches, connected together through a PPS signal, must adapt themselves
to this new source of time, while the switch connected to the GM must
not be synchronized by ts2phc because it is already synchronized by
ptp4l.
Signed-off-by: Vladimir Oltean <ol...@gm...>
---
makefile | 3 +-
ts2phc.c | 208 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
ts2phc.h | 11 +++
3 files changed, 220 insertions(+), 2 deletions(-)
diff --git a/makefile b/makefile
index 27c4d7809553..f9fe12dde170 100644
--- a/makefile
+++ b/makefile
@@ -27,7 +27,8 @@ FILTERS = filter.o mave.o mmedian.o
SERVOS = linreg.o ntpshm.o nullf.o pi.o servo.o
TRANSP = raw.o transport.o udp.o udp6.o uds.o
TS2PHC = ts2phc.o lstab.o nmea.o serial.o sock.o ts2phc_generic_master.o \
- ts2phc_master.o ts2phc_phc_master.o ts2phc_nmea_master.o ts2phc_slave.o
+ ts2phc_master.o ts2phc_phc_master.o ts2phc_nmea_master.o ts2phc_slave.o \
+ pmc_common.o transport.o msg.o tlv.o uds.o udp.o udp6.o raw.o
OBJ = bmc.o clock.o clockadj.o clockcheck.o config.o designated_fsm.o \
e2e_tc.o fault.o $(FILTERS) fsm.o hash.o interface.o monitor.o msg.o phc.o \
port.o port_signaling.o pqueue.o print.o ptp4l.o p2p_tc.o rtnl.o $(SERVOS) \
diff --git a/ts2phc.c b/ts2phc.c
index 97e9718c999e..2c8a42c04d0c 100644
--- a/ts2phc.c
+++ b/ts2phc.c
@@ -33,6 +33,91 @@ static void ts2phc_cleanup(struct ts2phc_private *priv)
if (priv->cfg) {
config_destroy(priv->cfg);
}
+ close_pmc_node(&priv->node);
+}
+
+/* FIXME: Copied from phc2sys */
+static int normalize_state(int state)
+{
+ if (state != PS_MASTER && state != PS_SLAVE &&
+ state != PS_PRE_MASTER && state != PS_UNCALIBRATED) {
+ /* treat any other state as "not a master nor a slave" */
+ state = PS_DISABLED;
+ }
+ return state;
+}
+
+/* FIXME: Copied from phc2sys */
+static struct port *port_get(struct ts2phc_private *priv, unsigned int number)
+{
+ struct port *p;
+
+ LIST_FOREACH(p, &priv->ports, list) {
+ if (p->number == number)
+ return p;
+ }
+ return NULL;
+}
+
+/* FIXME: Copied from phc2sys */
+static int clock_compute_state(struct ts2phc_private *priv,
+ struct clock *clock)
+{
+ int state = PS_DISABLED;
+ struct port *p;
+
+ LIST_FOREACH(p, &priv->ports, list) {
+ if (p->clock != clock)
+ continue;
+ /* PS_SLAVE takes the highest precedence, PS_UNCALIBRATED
+ * after that, PS_MASTER is third, PS_PRE_MASTER fourth and
+ * all of that overrides PS_DISABLED, which corresponds
+ * nicely with the numerical values */
+ if (p->state > state)
+ state = p->state;
+ }
+ return state;
+}
+
+#define node_to_ts2phc(node) \
+ container_of(node, struct ts2phc_private, node)
+
+static int ts2phc_recv_subscribed(struct pmc_node *node,
+ struct ptp_message *msg, int excluded)
+{
+ struct ts2phc_private *priv = node_to_ts2phc(node);
+ int mgt_id, state;
+ struct portDS *pds;
+ struct port *port;
+ struct clock *clock;
+
+ mgt_id = get_mgt_id(msg);
+ if (mgt_id == excluded)
+ return 0;
+ switch (mgt_id) {
+ case TLV_PORT_DATA_SET:
+ pds = get_mgt_data(msg);
+ port = port_get(priv, pds->portIdentity.portNumber);
+ if (!port) {
+ pr_info("received data for unknown port %s",
+ pid2str(&pds->portIdentity));
+ return 1;
+ }
+ state = normalize_state(pds->portState);
+ if (port->state != state) {
+ pr_info("port %s changed state",
+ pid2str(&pds->portIdentity));
+ port->state = state;
+ clock = port->clock;
+ state = clock_compute_state(priv, clock);
+ if (clock->state != state || clock->new_state) {
+ clock->new_state = state;
+ priv->state_changed = 1;
+ }
+ }
+ return 1;
+ }
+ return 0;
}
struct servo *servo_add(struct ts2phc_private *priv, struct clock *clock)
@@ -98,6 +183,105 @@ struct clock *clock_add(struct ts2phc_private *priv, const char *device)
return c;
}
+/* FIXME: Copied from phc2sys */
+static struct port *port_add(struct ts2phc_private *priv, unsigned int number,
+ char *device)
+{
+ struct clock *c = NULL;
+ struct port *p, *tmp;
+
+ p = port_get(priv, number);
+ if (p)
+ return p;
+ /* port is a new one, look whether we have the device already on
+ * a different port */
+ LIST_FOREACH(tmp, &priv->ports, list) {
+ if (tmp->number == number) {
+ c = tmp->clock;
+ break;
+ }
+ }
+ if (!c) {
+ c = clock_add(priv, device);
+ if (!c)
+ return NULL;
+ }
+ p = malloc(sizeof(*p));
+ if (!p) {
+ pr_err("failed to allocate memory for a port");
+ return NULL;
+ }
+ p->number = number;
+ p->clock = c;
+ LIST_INSERT_HEAD(&priv->ports, p, list);
+ return p;
+}
+
+static int auto_init_ports(struct ts2phc_private *priv)
+{
+ int state, timestamping;
+ int number_ports, res;
+ char iface[IFNAMSIZ];
+ struct clock *clock;
+ struct port *port;
+ unsigned int i;
+
+ while (1) {
+ if (!is_running())
+ return -1;
+ res = run_pmc_clock_identity(&priv->node, 1000);
+ if (res < 0)
+ return -1;
+ if (res > 0)
+ break;
+ /* res == 0, timeout */
+ pr_notice("Waiting for ptp4l...");
+ }
+
+ number_ports = run_pmc_get_number_ports(&priv->node, 1000);
+ if (number_ports <= 0) {
+ pr_err("failed to get number of ports");
+ return -1;
+ }
+
+ res = run_pmc_subscribe(&priv->node, 1000);
+ if (res <= 0) {
+ pr_err("failed to subscribe");
+ return -1;
+ }
+
+ for (i = 1; i <= number_ports; i++) {
+ res = run_pmc_port_properties(&priv->node, 1000, i, &state,
+ ×tamping, iface);
+ if (res == -1) {
+ /* port does not exist, ignore the port */
+ continue;
+ }
+ if (res <= 0) {
+ pr_err("failed to get port properties");
+ return -1;
+ }
+ if (timestamping == TS_SOFTWARE) {
+ /* ignore ports with software time stamping */
+ continue;
+ }
+ port = port_add(priv, i, iface);
+ if (!port)
+ return -1;
+ port->state = normalize_state(state);
+ }
+ if (LIST_EMPTY(&priv->clocks)) {
+ pr_err("no suitable ports available");
+ return -1;
+ }
+ LIST_FOREACH(clock, &priv->clocks, list) {
+ clock->new_state = clock_compute_state(priv, clock);
+ }
+ priv->state_changed = 1;
+
+ return 0;
+}
+
static void usage(char *progname)
{
fprintf(stderr,
@@ -124,6 +308,7 @@ static void usage(char *progname)
int main(int argc, char *argv[])
{
int c, err = 0, have_slave = 0, index, print_level;
+ char uds_local[MAX_IFNAME_SIZE + 1];
enum ts2phc_master_type pps_type;
struct ts2phc_private priv = {0};
char *config = NULL, *progname;
@@ -131,6 +316,7 @@ int main(int argc, char *argv[])
struct config *cfg = NULL;
struct interface *iface;
struct option *opts;
+ int autocfg = 0;
handle_term_signals();
@@ -145,7 +331,7 @@ int main(int argc, char *argv[])
/* Process the command line arguments. */
progname = strrchr(argv[0], '/');
progname = progname ? 1 + progname : argv[0];
- while (EOF != (c = getopt_long(argc, argv, "c:f:hi:l:mqs:v", opts, &index))) {
+ while (EOF != (c = getopt_long(argc, argv, "ac:f:hi:l:mqs:v", opts, &index))) {
switch (c) {
case 0:
if (config_parse_option(cfg, opts[index].name, optarg)) {
@@ -153,6 +339,9 @@ int main(int argc, char *argv[])
return -1;
}
break;
+ case 'a':
+ autocfg = 1;
+ break;
case 'c':
if (!config_create_interface(optarg, cfg)) {
fprintf(stderr, "failed to add slave\n");
@@ -218,6 +407,23 @@ int main(int argc, char *argv[])
STAILQ_INIT(&priv.slaves);
priv.cfg = cfg;
+ snprintf(uds_local, sizeof(uds_local), "/var/run/ts2phc.%d",
+ getpid());
+
+ if (autocfg) {
+ err = init_pmc_node(cfg, &priv.node, uds_local,
+ ts2phc_recv_subscribed);
+ if (err) {
+ ts2phc_cleanup(&priv);
+ return -1;
+ }
+ err = auto_init_ports(&priv);
+ if (err) {
+ ts2phc_cleanup(&priv);
+ return -1;
+ }
+ }
+
STAILQ_FOREACH(iface, &cfg->interfaces, list) {
if (1 == config_get_int(cfg, interface_name(iface), "ts2phc.master")) {
if (pps_source) {
diff --git a/ts2phc.h b/ts2phc.h
index 135b795f11dc..51ac366c4145 100644
--- a/ts2phc.h
+++ b/ts2phc.h
@@ -23,6 +23,7 @@
#include <sys/queue.h>
#include <time.h>
+#include "pmc_common.h"
#include "servo.h"
struct ts2phc_slave_array;
@@ -43,13 +44,23 @@ struct clock {
int is_destination;
};
+struct port {
+ LIST_ENTRY(port) list;
+ unsigned int number;
+ int state;
+ struct clock *clock;
+};
+
struct ts2phc_private {
struct ts2phc_master *master;
STAILQ_HEAD(slave_ifaces_head, ts2phc_slave) slaves;
unsigned int n_slaves;
struct ts2phc_slave_array *polling_array;
struct config *cfg;
+ struct pmc_node node;
+ int state_changed;
struct clock *source;
+ LIST_HEAD(port_head, port) ports;
LIST_HEAD(clock_head, clock) clocks;
};
--
2.25.1
|
|
From: Vladimir O. <ol...@gm...> - 2020-08-01 17:46:55
|
Since it has been argued that:
- a ts2phc slave deals with extts events
- a clock deals with synchronization via a servo loop
then the code for synchronization should not be part of the
implementation of a ts2phc slave. Move it to the main ts2phc.c.
Signed-off-by: Vladimir Oltean <ol...@gm...>
---
ts2phc.c | 94 ++++++++++++++++++++++-
ts2phc.h | 4 +-
ts2phc_slave.c | 200 +++++++++++++++++++++++--------------------------
3 files changed, 190 insertions(+), 108 deletions(-)
diff --git a/ts2phc.c b/ts2phc.c
index 2c8a42c04d0c..f317c4abb4ad 100644
--- a/ts2phc.c
+++ b/ts2phc.c
@@ -20,6 +20,9 @@
#include "version.h"
#include "contain.h"
+#define NS_PER_SEC 1000000000LL
+#define SAMPLE_WEIGHT 1.0
+
struct interface {
STAILQ_ENTRY(interface) list;
};
@@ -143,6 +146,30 @@ struct servo *servo_add(struct ts2phc_private *priv, struct clock *clock)
return servo;
}
+void clock_add_tstamp(struct clock *clock, tmv_t t)
+{
+ struct timespec ts = tmv_to_timespec(t);
+
+ pr_debug("adding tstamp %ld.%09ld to clock %s",
+ ts.tv_sec, ts.tv_nsec, clock->name);
+ clock->last_ts = t;
+ clock->is_ts_available = 1;
+}
+
+static int clock_get_tstamp(struct clock *clock, tmv_t *ts)
+{
+ if (!clock->is_ts_available)
+ return 0;
+ clock->is_ts_available = 0;
+ *ts = clock->last_ts;
+ return 1;
+}
+
+static void clock_flush_tstamp(struct clock *clock)
+{
+ clock->is_ts_available = 0;
+}
+
struct clock *clock_add(struct ts2phc_private *priv, const char *device)
{
clockid_t clkid = CLOCK_INVALID;
@@ -282,6 +309,64 @@ static int auto_init_ports(struct ts2phc_private *priv)
return 0;
}
+static void ts2phc_synchronize_clocks(struct ts2phc_private *priv)
+{
+ struct timespec source_ts;
+ tmv_t source_tmv;
+ struct clock *c;
+ int valid, err;
+
+ err = ts2phc_master_getppstime(priv->master, &source_ts);
+ if (err < 0) {
+ pr_err("source ts not valid");
+ return;
+ }
+ if (source_ts.tv_nsec > NS_PER_SEC / 2)
+ source_ts.tv_sec++;
+ source_ts.tv_nsec = 0;
+
+ source_tmv = timespec_to_tmv(source_ts);
+
+ LIST_FOREACH(c, &priv->clocks, list) {
+ int64_t offset;
+ double adj;
+ tmv_t ts;
+
+ valid = clock_get_tstamp(c, &ts);
+ if (!valid) {
+ pr_debug("%s timestamp not valid, skipping", c->name);
+ continue;
+ }
+
+ offset = tmv_to_nanoseconds(tmv_sub(ts, source_tmv));
+
+ if (c->no_adj) {
+ pr_info("%s offset %10" PRId64, c->name,
+ offset);
+ continue;
+ }
+
+ adj = servo_sample(c->servo, offset, tmv_to_nanoseconds(ts),
+ SAMPLE_WEIGHT, &c->servo_state);
+
+ pr_info("%s offset %10" PRId64 " s%d freq %+7.0f",
+ c->name, offset, c->servo_state, adj);
+
+ switch (c->servo_state) {
+ case SERVO_UNLOCKED:
+ break;
+ case SERVO_JUMP:
+ clockadj_set_freq(c->clkid, -adj);
+ clockadj_step(c->clkid, -offset);
+ break;
+ case SERVO_LOCKED:
+ case SERVO_LOCKED_STABLE:
+ clockadj_set_freq(c->clkid, -adj);
+ break;
+ }
+ }
+}
+
static void usage(char *progname)
{
fprintf(stderr,
@@ -474,11 +559,18 @@ int main(int argc, char *argv[])
}
while (is_running()) {
+ struct clock *c;
+
+ LIST_FOREACH(c, &priv.clocks, list)
+ clock_flush_tstamp(c);
+
err = ts2phc_slave_poll(&priv);
- if (err) {
+ if (err < 0) {
pr_err("poll failed");
break;
}
+ if (err > 0)
+ ts2phc_synchronize_clocks(&priv);
}
ts2phc_cleanup(&priv);
diff --git a/ts2phc.h b/ts2phc.h
index 51ac366c4145..4f656cc1c741 100644
--- a/ts2phc.h
+++ b/ts2phc.h
@@ -42,6 +42,8 @@ struct clock {
char *name;
int no_adj;
int is_destination;
+ int is_ts_available;
+ tmv_t last_ts;
};
struct port {
@@ -66,7 +68,7 @@ struct ts2phc_private {
struct servo *servo_add(struct ts2phc_private *priv, struct clock *clock);
struct clock *clock_add(struct ts2phc_private *priv, const char *device);
-void clock_add_tstamp(struct clock *clock, struct timespec ts);
+void clock_add_tstamp(struct clock *clock, tmv_t ts);
#include "ts2phc_master.h"
#include "ts2phc_slave.h"
diff --git a/ts2phc_slave.c b/ts2phc_slave.c
index 566cb14436fb..0ecb4eb941b2 100644
--- a/ts2phc_slave.c
+++ b/ts2phc_slave.c
@@ -24,42 +24,29 @@
#include "ts2phc.h"
#include "util.h"
-#define NS_PER_SEC 1000000000LL
-#define SAMPLE_WEIGHT 1.0
-
struct ts2phc_slave {
char *name;
STAILQ_ENTRY(ts2phc_slave) list;
struct ptp_pin_desc pin_desc;
unsigned int polarity;
- int32_t correction;
+ tmv_t correction;
uint32_t ignore_lower;
uint32_t ignore_upper;
struct clock *clock;
- int no_adj;
};
struct ts2phc_slave_array {
struct ts2phc_slave **slave;
+ int *collected_events;
struct pollfd *pfd;
};
-struct ts2phc_source_timestamp {
- struct timespec ts;
- bool valid;
-};
-
enum extts_result {
EXTTS_ERROR = -1,
EXTTS_OK = 0,
EXTTS_IGNORE = 1,
};
-static enum extts_result ts2phc_slave_offset(struct ts2phc_slave *slave,
- struct ts2phc_source_timestamp ts,
- int64_t *offset,
- uint64_t *local_ts);
-
static int ts2phc_slave_array_create(struct ts2phc_private *priv)
{
struct ts2phc_slave_array *polling_array;
@@ -86,6 +73,15 @@ static int ts2phc_slave_array_create(struct ts2phc_private *priv)
polling_array->slave = NULL;
return -1;
}
+ polling_array->collected_events = malloc(priv->n_slaves * sizeof(int));
+ if (!polling_array->collected_events) {
+ pr_err("low memory");
+ free(polling_array->slave);
+ free(polling_array->pfd);
+ polling_array->pfd = NULL;
+ polling_array->slave = NULL;
+ return -1;
+ }
i = 0;
STAILQ_FOREACH(slave, &priv->slaves, list) {
polling_array->slave[i] = slave;
@@ -107,6 +103,9 @@ static void ts2phc_slave_array_destroy(struct ts2phc_private *priv)
{
struct ts2phc_slave_array *polling_array = priv->polling_array;
+ if (!polling_array)
+ return;
+
free(polling_array->slave);
free(polling_array->pfd);
free(polling_array);
@@ -152,6 +151,7 @@ static struct ts2phc_slave *ts2phc_slave_create(struct ts2phc_private *priv,
struct ptp_extts_request extts;
struct ts2phc_slave *slave;
int err, pulsewidth;
+ int32_t correction;
slave = calloc(1, sizeof(*slave));
if (!slave) {
@@ -171,8 +171,9 @@ static struct ts2phc_slave *ts2phc_slave_create(struct ts2phc_private *priv,
"ts2phc.channel");
slave->polarity = config_get_int(priv->cfg, device,
"ts2phc.extts_polarity");
- slave->correction = config_get_int(priv->cfg, device,
- "ts2phc.extts_correction");
+ correction = config_get_int(priv->cfg, device,
+ "ts2phc.extts_correction");
+ slave->correction = nanoseconds_to_tmv(correction);
pulsewidth = config_get_int(priv->cfg, device,
"ts2phc.pulsewidth");
@@ -247,71 +248,32 @@ static void ts2phc_slave_destroy(struct ts2phc_slave *slave)
free(slave);
}
-static int ts2phc_slave_event(struct ts2phc_slave *slave,
- struct ts2phc_source_timestamp source_ts)
+static enum extts_result ts2phc_slave_event(struct ts2phc_private *priv,
+ struct ts2phc_slave *slave)
{
- enum extts_result result;
- uint64_t extts_ts;
- int64_t offset;
- double adj;
-
- result = ts2phc_slave_offset(slave, source_ts, &offset, &extts_ts);
- switch (result) {
- case EXTTS_ERROR:
- return -1;
- case EXTTS_OK:
- break;
- case EXTTS_IGNORE:
- return 0;
- }
-
- if (slave->no_adj) {
- pr_info("%s master offset %10" PRId64, slave->name, offset);
- return 0;
- }
-
- adj = servo_sample(slave->clock->servo, offset, extts_ts,
- SAMPLE_WEIGHT, &slave->clock->servo_state);
-
- pr_info("%s master offset %10" PRId64 " s%d freq %+7.0f",
- slave->name, offset, slave->clock->servo_state, adj);
-
- switch (slave->clock->servo_state) {
- case SERVO_UNLOCKED:
- break;
- case SERVO_JUMP:
- clockadj_set_freq(slave->clock->clkid, -adj);
- clockadj_step(slave->clock->clkid, -offset);
- break;
- case SERVO_LOCKED:
- case SERVO_LOCKED_STABLE:
- clockadj_set_freq(slave->clock->clkid, -adj);
- break;
- }
- return 0;
-}
-
-static enum extts_result ts2phc_slave_offset(struct ts2phc_slave *slave,
- struct ts2phc_source_timestamp src,
- int64_t *offset,
- uint64_t *local_ts)
-{
- struct timespec source_ts = src.ts;
+ enum extts_result result = EXTTS_OK;
struct ptp_extts_event event;
- uint64_t event_ns, source_ns;
- int cnt;
+ struct timespec source_ts;
+ int err, cnt;
+ tmv_t ts;
cnt = read(CLOCKID_TO_FD(slave->clock->clkid), &event, sizeof(event));
if (cnt != sizeof(event)) {
pr_err("read extts event failed: %m");
- return EXTTS_ERROR;
+ result = EXTTS_ERROR;
+ goto out;
}
if (event.index != slave->pin_desc.chan) {
pr_err("extts on unexpected channel");
- return EXTTS_ERROR;
+ result = EXTTS_ERROR;
+ goto out;
+ }
+
+ err = ts2phc_master_getppstime(priv->master, &source_ts);
+ if (err < 0) {
+ pr_debug("source ts not valid");
+ return 0;
}
- event_ns = event.t.sec * NS_PER_SEC;
- event_ns += event.t.nsec;
if (slave->polarity == (PTP_RISING_EDGE | PTP_FALLING_EDGE) &&
source_ts.tv_nsec > slave->ignore_lower &&
@@ -321,20 +283,17 @@ static enum extts_result ts2phc_slave_offset(struct ts2phc_slave *slave,
slave->name, event.index, event.t.sec, event.t.nsec,
(int64_t) source_ts.tv_sec, source_ts.tv_nsec);
- return EXTTS_IGNORE;
- }
- if (source_ts.tv_nsec > 500000000) {
- source_ts.tv_sec++;
+ result = EXTTS_IGNORE;
+ goto out;
}
- source_ns = source_ts.tv_sec * NS_PER_SEC;
- *offset = event_ns + slave->correction - source_ns;
- *local_ts = event_ns + slave->correction;
- pr_debug("%s extts index %u at %lld.%09u corr %d src %" PRIi64
- ".%ld diff %" PRId64,
- slave->name, event.index, event.t.sec, event.t.nsec,
- slave->correction,
- (int64_t) source_ts.tv_sec, source_ts.tv_nsec, *offset);
+out:
+ if (result == EXTTS_ERROR || result == EXTTS_IGNORE)
+ return result;
+
+ ts = pct_to_tmv(event.t);
+ ts = tmv_add(ts, slave->correction);
+ clock_add_tstamp(slave->clock, ts);
return EXTTS_OK;
}
@@ -410,35 +369,64 @@ void ts2phc_slave_cleanup(struct ts2phc_private *priv)
int ts2phc_slave_poll(struct ts2phc_private *priv)
{
struct ts2phc_slave_array *polling_array = priv->polling_array;
- struct ts2phc_source_timestamp source_ts;
+ int all_slaves_have_events = 0;
+ int ignore_any = 0;
unsigned int i;
- int cnt, err;
+ int cnt;
+
+ for (i = 0; i < priv->n_slaves; i++)
+ polling_array->collected_events[i] = 0;
+
+ while (!all_slaves_have_events) {
+ struct ts2phc_slave *slave;
- cnt = poll(polling_array->pfd, priv->n_slaves, 2000);
- if (cnt < 0) {
- if (EINTR == errno) {
+ cnt = poll(polling_array->pfd, priv->n_slaves, 2000);
+ if (cnt < 0) {
+ if (EINTR == errno) {
+ return 0;
+ } else {
+ pr_emerg("poll failed");
+ return -1;
+ }
+ } else if (!cnt) {
+ pr_debug("poll returns zero, no events");
return 0;
- } else {
- pr_emerg("poll failed");
- return -1;
}
- } else if (!cnt) {
- pr_debug("poll returns zero, no events");
- return 0;
- }
- err = ts2phc_master_getppstime(priv->master, &source_ts.ts);
- source_ts.valid = err ? false : true;
+ for (i = 0; i < priv->n_slaves; i++) {
+ if (polling_array->pfd[i].revents & (POLLIN|POLLPRI)) {
+ enum extts_result result;
+
+ slave = polling_array->slave[i];
+
+ result = ts2phc_slave_event(priv, slave);
+ if (result == EXTTS_ERROR)
+ return -EIO;
+ if (result == EXTTS_IGNORE)
+ ignore_any = 1;
+
+ /*
+ * Collect the events anyway, even if we'll
+ * ignore this master edge anyway. We don't
+ * want slave events from different edges
+ * to pile up and mix.
+ */
+ polling_array->collected_events[i]++;
+ }
+ }
- if (!source_ts.valid) {
- pr_debug("ignoring invalid master time stamp");
- return 0;
- }
+ all_slaves_have_events = true;
- for (i = 0; i < priv->n_slaves; i++) {
- if (polling_array->pfd[i].revents & (POLLIN|POLLPRI)) {
- ts2phc_slave_event(polling_array->slave[i], source_ts);
+ for (i = 0; i < priv->n_slaves; i++) {
+ if (!polling_array->collected_events[i]) {
+ all_slaves_have_events = false;
+ break;
+ }
}
}
- return 0;
+
+ if (ignore_any)
+ return 0;
+
+ return 1;
}
--
2.25.1
|
|
From: Vladimir O. <ol...@gm...> - 2020-08-01 17:46:56
|
This is useful when dealing with timestamps returned by various
ancillary PHC ioctl kernel APIs, such as extts.
Signed-off-by: Vladimir Oltean <ol...@gm...>
---
tmv.h | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/tmv.h b/tmv.h
index f4a1a228ff6d..903953434586 100644
--- a/tmv.h
+++ b/tmv.h
@@ -20,6 +20,7 @@
#ifndef HAVE_TMV_H
#define HAVE_TMV_H
+#include <linux/ptp_clock.h>
#include <time.h>
#include "ddt.h"
@@ -160,4 +161,11 @@ static inline tmv_t timestamp_to_tmv(struct timestamp ts)
return t;
}
+static inline tmv_t pct_to_tmv(struct ptp_clock_time pct)
+{
+ tmv_t t;
+ t.ns = pct.sec * NS_PER_SEC + pct.nsec;
+ return t;
+}
+
#endif
--
2.25.1
|
|
From: Vladimir O. <ol...@gm...> - 2020-08-01 17:46:57
|
Interestingly, although tmv_t is a wrapper over nanoseconds, there is no
initializer from a raw nanosecond value. So add one.
Signed-off-by: Vladimir Oltean <ol...@gm...>
---
tmv.h | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/tmv.h b/tmv.h
index 903953434586..0c1155f02f04 100644
--- a/tmv.h
+++ b/tmv.h
@@ -112,6 +112,13 @@ static inline int64_t tmv_to_nanoseconds(tmv_t x)
return x.ns;
}
+static inline tmv_t nanoseconds_to_tmv(int64_t ns)
+{
+ tmv_t t;
+ t.ns = ns;
+ return t;
+}
+
static inline TimeInterval tmv_to_TimeInterval(tmv_t x)
{
if (x.ns < (int64_t)MIN_TMV_TO_TIMEINTERVAL) {
--
2.25.1
|
|
From: Vladimir O. <ol...@gm...> - 2020-08-01 17:46:43
|
We will be reusing some PMC code between phc2sys and ts2phc. In
preparation of that, we would like to extract the PMC related properties
of the current private program data structure of phc2sys, "struct node",
into something smaller that can be shared properly.
The "struct node" name is nice enough, so use that to denote the smaller
data structure for PMC from now on. Rename the bigger data structure to
phc2sys_private.
Signed-off-by: Vladimir Oltean <ol...@gm...>
---
phc2sys.c | 433 ++++++++++++++++++++++++++++--------------------------
1 file changed, 221 insertions(+), 212 deletions(-)
diff --git a/phc2sys.c b/phc2sys.c
index 64bdf2664fe4..a36cbe071d7d 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -99,7 +99,7 @@ struct port {
struct clock *clock;
};
-struct node {
+struct phc2sys_private {
unsigned int stats_max_count;
int sanity_freq_limit;
enum servo_type servo_type;
@@ -124,18 +124,21 @@ struct node {
static struct config *phc2sys_config;
-static int update_pmc(struct node *node, int subscribe);
-static int clock_handle_leap(struct node *node, struct clock *clock,
+static int update_pmc(struct phc2sys_private *priv, int subscribe);
+static int clock_handle_leap(struct phc2sys_private *priv,
+ struct clock *clock,
int64_t offset, uint64_t ts);
-static int run_pmc_get_utc_offset(struct node *node, int timeout);
-static void run_pmc_events(struct node *node);
+static int run_pmc_get_utc_offset(struct phc2sys_private *priv,
+ int timeout);
+static void run_pmc_events(struct phc2sys_private *priv);
static int normalize_state(int state);
-static int run_pmc_port_properties(struct node *node, int timeout,
- unsigned int port,
+static int run_pmc_port_properties(struct phc2sys_private *priv,
+ int timeout, unsigned int port,
int *state, int *tstamping, char *iface);
-static struct servo *servo_add(struct node *node, struct clock *clock)
+static struct servo *servo_add(struct phc2sys_private *priv,
+ struct clock *clock)
{
double ppb;
int max_ppb;
@@ -157,19 +160,19 @@ static struct servo *servo_add(struct node *node, struct clock *clock)
}
}
- servo = servo_create(phc2sys_config, node->servo_type,
+ servo = servo_create(phc2sys_config, priv->servo_type,
-ppb, max_ppb, 0);
if (!servo) {
pr_err("Failed to create servo");
return NULL;
}
- servo_sync_interval(servo, node->phc_interval);
+ servo_sync_interval(servo, priv->phc_interval);
return servo;
}
-static struct clock *clock_add(struct node *node, char *device)
+static struct clock *clock_add(struct phc2sys_private *priv, char *device)
{
struct clock *c;
clockid_t clkid = CLOCK_INVALID;
@@ -198,7 +201,7 @@ static struct clock *clock_add(struct node *node, char *device)
c->source_label = "phc";
}
- if (node->stats_max_count > 0) {
+ if (priv->stats_max_count > 0) {
c->offset_stats = stats_create();
c->freq_stats = stats_create();
c->delay_stats = stats_create();
@@ -209,8 +212,8 @@ static struct clock *clock_add(struct node *node, char *device)
return NULL;
}
}
- if (node->sanity_freq_limit) {
- c->sanity_check = clockcheck_create(node->sanity_freq_limit);
+ if (priv->sanity_freq_limit) {
+ c->sanity_check = clockcheck_create(priv->sanity_freq_limit);
if (!c->sanity_check) {
pr_err("failed to create clock check");
return NULL;
@@ -218,21 +221,21 @@ static struct clock *clock_add(struct node *node, char *device)
}
if (clkid != CLOCK_INVALID)
- c->servo = servo_add(node, c);
+ c->servo = servo_add(priv, c);
if (clkid != CLOCK_INVALID && clkid != CLOCK_REALTIME)
c->sysoff_method = sysoff_probe(CLOCKID_TO_FD(clkid),
- node->phc_readings);
+ priv->phc_readings);
- LIST_INSERT_HEAD(&node->clocks, c, list);
+ LIST_INSERT_HEAD(&priv->clocks, c, list);
return c;
}
-static void clock_cleanup(struct node *node)
+static void clock_cleanup(struct phc2sys_private *priv)
{
struct clock *c, *tmp;
- LIST_FOREACH_SAFE(c, &node->clocks, list, tmp) {
+ LIST_FOREACH_SAFE(c, &priv->clocks, list, tmp) {
if (c->servo) {
servo_destroy(c->servo);
}
@@ -255,45 +258,45 @@ static void clock_cleanup(struct node *node)
}
}
-static void port_cleanup(struct node *node)
+static void port_cleanup(struct phc2sys_private *priv)
{
struct port *p, *tmp;
- LIST_FOREACH_SAFE(p, &node->ports, list, tmp) {
+ LIST_FOREACH_SAFE(p, &priv->ports, list, tmp) {
free(p);
}
}
-static struct port *port_get(struct node *node, unsigned int number)
+static struct port *port_get(struct phc2sys_private *priv, unsigned int number)
{
struct port *p;
- LIST_FOREACH(p, &node->ports, list) {
+ LIST_FOREACH(p, &priv->ports, list) {
if (p->number == number)
return p;
}
return NULL;
}
-static struct port *port_add(struct node *node, unsigned int number,
+static struct port *port_add(struct phc2sys_private *priv, unsigned int number,
char *device)
{
struct port *p;
struct clock *c = NULL, *tmp;
- p = port_get(node, number);
+ p = port_get(priv, number);
if (p)
return p;
/* port is a new one, look whether we have the device already on
* a different port */
- LIST_FOREACH(tmp, &node->clocks, list) {
+ LIST_FOREACH(tmp, &priv->clocks, list) {
if (!strcmp(tmp->device, device)) {
c = tmp;
break;
}
}
if (!c) {
- c = clock_add(node, device);
+ c = clock_add(priv, device);
if (!c)
return NULL;
}
@@ -304,11 +307,12 @@ static struct port *port_add(struct node *node, unsigned int number,
}
p->number = number;
p->clock = c;
- LIST_INSERT_HEAD(&node->ports, p, list);
+ LIST_INSERT_HEAD(&priv->ports, p, list);
return p;
}
-static void clock_reinit(struct node *node, struct clock *clock, int new_state)
+static void clock_reinit(struct phc2sys_private *priv, struct clock *clock,
+ int new_state)
{
int phc_index = -1, phc_switched = 0;
int state, timestamping, ret = -1;
@@ -318,9 +322,9 @@ static void clock_reinit(struct node *node, struct clock *clock, int new_state)
char iface[IFNAMSIZ];
clockid_t clkid = CLOCK_INVALID;
- LIST_FOREACH(p, &node->ports, list) {
+ LIST_FOREACH(p, &priv->ports, list) {
if (p->clock == clock) {
- ret = run_pmc_port_properties(node, 1000, p->number,
+ ret = run_pmc_port_properties(priv, 1000, p->number,
&state, ×tamping,
iface);
if (ret > 0)
@@ -345,7 +349,7 @@ static void clock_reinit(struct node *node, struct clock *clock, int new_state)
clock->clkid = clkid;
clock->phc_index = phc_index;
- servo = servo_add(node, clock);
+ servo = servo_add(priv, clock);
if (servo) {
servo_destroy(clock->servo);
clock->servo = servo;
@@ -367,9 +371,11 @@ static void clock_reinit(struct node *node, struct clock *clock, int new_state)
}
}
-static struct clock *find_dst_clock(struct node *node, int phc_index) {
+static struct clock *find_dst_clock(struct phc2sys_private *priv,
+ int phc_index)
+{
struct clock *c = NULL;
- LIST_FOREACH(c, &node->dst_clocks, dst_list) {
+ LIST_FOREACH(c, &priv->dst_clocks, dst_list) {
if (c->phc_index == phc_index) {
break;
}
@@ -377,26 +383,26 @@ static struct clock *find_dst_clock(struct node *node, int phc_index) {
return c;
}
-static void reconfigure(struct node *node)
+static void reconfigure(struct phc2sys_private *priv)
{
struct clock *c, *rt = NULL, *src = NULL, *last = NULL, *dup = NULL;
int src_cnt = 0, dst_cnt = 0;
pr_info("reconfiguring after port state change");
- node->state_changed = 0;
+ priv->state_changed = 0;
- while (node->dst_clocks.lh_first != NULL) {
- LIST_REMOVE(node->dst_clocks.lh_first, dst_list);
+ while (priv->dst_clocks.lh_first != NULL) {
+ LIST_REMOVE(priv->dst_clocks.lh_first, dst_list);
}
- LIST_FOREACH(c, &node->clocks, list) {
+ LIST_FOREACH(c, &priv->clocks, list) {
if (c->clkid == CLOCK_REALTIME) {
rt = c;
continue;
}
if (c->new_state) {
- clock_reinit(node, c, c->new_state);
+ clock_reinit(priv, c, c->new_state);
c->state = c->new_state;
c->new_state = 0;
}
@@ -408,12 +414,12 @@ static void reconfigure(struct node *node)
case PS_PRE_MASTER:
case PS_MASTER:
case PS_PASSIVE:
- dup = find_dst_clock(node, c->phc_index);
+ dup = find_dst_clock(priv, c->phc_index);
if (!dup) {
pr_info("selecting %s for synchronization",
c->device);
dst_cnt++;
- LIST_INSERT_HEAD(&node->dst_clocks,
+ LIST_INSERT_HEAD(&priv->dst_clocks,
c, dst_list);
} else {
pr_info("skipping %s: %s has the same clock "
@@ -433,10 +439,10 @@ static void reconfigure(struct node *node)
}
if (dst_cnt > 1 && !src) {
if (!rt || rt->dest_only) {
- node->master = last;
+ priv->master = last;
/* Reset to original state in next reconfiguration. */
- node->master->new_state = node->master->state;
- node->master->state = PS_SLAVE;
+ priv->master->new_state = priv->master->state;
+ priv->master->state = PS_SLAVE;
if (rt)
rt->state = PS_SLAVE;
pr_info("no source, selecting %s as the default clock",
@@ -446,23 +452,23 @@ static void reconfigure(struct node *node)
}
if (src_cnt > 1) {
pr_info("multiple master clocks available, postponing sync...");
- node->master = NULL;
+ priv->master = NULL;
return;
}
if (src_cnt > 0 && !src) {
pr_info("master clock not ready, waiting...");
- node->master = NULL;
+ priv->master = NULL;
return;
}
if (!src_cnt && !dst_cnt) {
pr_info("no PHC ready, waiting...");
- node->master = NULL;
+ priv->master = NULL;
return;
}
if ((!src_cnt && (!rt || rt->dest_only)) ||
(!dst_cnt && !rt)) {
pr_info("nothing to synchronize");
- node->master = NULL;
+ priv->master = NULL;
return;
}
if (!src_cnt) {
@@ -471,12 +477,12 @@ static void reconfigure(struct node *node)
} else if (rt) {
if (rt->state != PS_MASTER) {
rt->state = PS_MASTER;
- clock_reinit(node, rt, rt->state);
+ clock_reinit(priv, rt, rt->state);
}
- LIST_INSERT_HEAD(&node->dst_clocks, rt, dst_list);
+ LIST_INSERT_HEAD(&priv->dst_clocks, rt, dst_list);
pr_info("selecting %s for synchronization", rt->device);
}
- node->master = src;
+ priv->master = src;
pr_info("selecting %s as the master clock", src->device);
}
@@ -511,12 +517,12 @@ static int read_phc(clockid_t clkid, clockid_t sysclk, int readings,
return 1;
}
-static int64_t get_sync_offset(struct node *node, struct clock *dst)
+static int64_t get_sync_offset(struct phc2sys_private *priv, struct clock *dst)
{
- int direction = node->forced_sync_offset;
+ int direction = priv->forced_sync_offset;
if (!direction)
- direction = dst->is_utc - node->master->is_utc;
+ direction = dst->is_utc - priv->master->is_utc;
return (int64_t)dst->sync_offset * NS_PER_SEC * direction;
}
@@ -559,16 +565,16 @@ static void update_clock_stats(struct clock *clock, unsigned int max_count,
stats_reset(clock->delay_stats);
}
-static void update_clock(struct node *node, struct clock *clock,
+static void update_clock(struct phc2sys_private *priv, struct clock *clock,
int64_t offset, uint64_t ts, int64_t delay)
{
enum servo_state state;
double ppb;
- if (clock_handle_leap(node, clock, offset, ts))
+ if (clock_handle_leap(priv, clock, offset, ts))
return;
- offset += get_sync_offset(node, clock);
+ offset += get_sync_offset(priv, clock);
if (clock->sanity_check && clockcheck_sample(clock->sanity_check, ts))
servo_reset(clock->servo);
@@ -595,16 +601,16 @@ static void update_clock(struct node *node, struct clock *clock,
}
if (clock->offset_stats) {
- update_clock_stats(clock, node->stats_max_count, offset, ppb, delay);
+ update_clock_stats(clock, priv->stats_max_count, offset, ppb, delay);
} else {
if (delay >= 0) {
pr_info("%s %s offset %9" PRId64 " s%d freq %+7.0f "
"delay %6" PRId64,
- clock->device, node->master->source_label,
+ clock->device, priv->master->source_label,
offset, state, ppb, delay);
} else {
pr_info("%s %s offset %9" PRId64 " s%d freq %+7.0f",
- clock->device, node->master->source_label,
+ clock->device, priv->master->source_label,
offset, state, ppb);
}
}
@@ -642,19 +648,20 @@ static int read_pps(int fd, int64_t *offset, uint64_t *ts)
return 1;
}
-static int do_pps_loop(struct node *node, struct clock *clock, int fd)
+static int do_pps_loop(struct phc2sys_private *priv, struct clock *clock,
+ int fd)
{
int64_t pps_offset, phc_offset, phc_delay;
uint64_t pps_ts, phc_ts;
- clockid_t src = node->master->clkid;
+ clockid_t src = priv->master->clkid;
- node->master->source_label = "pps";
+ priv->master->source_label = "pps";
if (src == CLOCK_INVALID) {
/* The sync offset can't be applied with PPS alone. */
- node->sync_offset = 0;
+ priv->sync_offset = 0;
} else {
- enable_pps_output(node->master->clkid);
+ enable_pps_output(priv->master->clkid);
}
while (is_running()) {
@@ -665,7 +672,7 @@ static int do_pps_loop(struct node *node, struct clock *clock, int fd)
/* If a PHC is available, use it to get the whole number
of seconds in the offset and PPS for the rest. */
if (src != CLOCK_INVALID) {
- if (!read_phc(src, clock->clkid, node->phc_readings,
+ if (!read_phc(src, clock->clkid, priv->phc_readings,
&phc_offset, &phc_ts, &phc_delay))
return -1;
@@ -683,9 +690,9 @@ static int do_pps_loop(struct node *node, struct clock *clock, int fd)
pps_offset = pps_ts - phc_ts;
}
- if (update_pmc(node, 0) < 0)
+ if (update_pmc(priv, 0) < 0)
continue;
- update_clock(node, clock, pps_offset, pps_ts, -1);
+ update_clock(priv, clock, pps_offset, pps_ts, -1);
}
close(fd);
return 0;
@@ -708,45 +715,45 @@ static int update_needed(struct clock *c)
return 0;
}
-static int do_loop(struct node *node, int subscriptions)
+static int do_loop(struct phc2sys_private *priv, int subscriptions)
{
struct timespec interval;
struct clock *clock;
uint64_t ts;
int64_t offset, delay;
- interval.tv_sec = node->phc_interval;
- interval.tv_nsec = (node->phc_interval - interval.tv_sec) * 1e9;
+ interval.tv_sec = priv->phc_interval;
+ interval.tv_nsec = (priv->phc_interval - interval.tv_sec) * 1e9;
while (is_running()) {
clock_nanosleep(CLOCK_MONOTONIC, 0, &interval, NULL);
- if (update_pmc(node, subscriptions) < 0)
+ if (update_pmc(priv, subscriptions) < 0)
continue;
if (subscriptions) {
- run_pmc_events(node);
- if (node->state_changed) {
+ run_pmc_events(priv);
+ if (priv->state_changed) {
/* force getting offset, as it may have
* changed after the port state change */
- if (run_pmc_get_utc_offset(node, 1000) <= 0) {
+ if (run_pmc_get_utc_offset(priv, 1000) <= 0) {
pr_err("failed to get UTC offset");
continue;
}
- reconfigure(node);
+ reconfigure(priv);
}
}
- if (!node->master)
+ if (!priv->master)
continue;
- LIST_FOREACH(clock, &node->dst_clocks, dst_list) {
+ LIST_FOREACH(clock, &priv->dst_clocks, dst_list) {
if (!update_needed(clock))
continue;
/* don't try to synchronize the clock to itself */
- if (clock->clkid == node->master->clkid ||
+ if (clock->clkid == priv->master->clkid ||
(clock->phc_index >= 0 &&
- clock->phc_index == node->master->phc_index) ||
- !strcmp(clock->device, node->master->device))
+ clock->phc_index == priv->master->phc_index) ||
+ !strcmp(clock->device, priv->master->device))
continue;
if (!clock->servo) {
@@ -755,41 +762,42 @@ static int do_loop(struct node *node, int subscriptions)
}
if (clock->clkid == CLOCK_REALTIME &&
- node->master->sysoff_method >= 0) {
+ priv->master->sysoff_method >= 0) {
/* use sysoff */
- if (sysoff_measure(CLOCKID_TO_FD(node->master->clkid),
- node->master->sysoff_method,
- node->phc_readings,
+ if (sysoff_measure(CLOCKID_TO_FD(priv->master->clkid),
+ priv->master->sysoff_method,
+ priv->phc_readings,
&offset, &ts, &delay) < 0)
return -1;
- } else if (node->master->clkid == CLOCK_REALTIME &&
+ } else if (priv->master->clkid == CLOCK_REALTIME &&
clock->sysoff_method >= 0) {
/* use reversed sysoff */
if (sysoff_measure(CLOCKID_TO_FD(clock->clkid),
clock->sysoff_method,
- node->phc_readings,
+ priv->phc_readings,
&offset, &ts, &delay) < 0)
return -1;
offset = -offset;
ts += offset;
} else {
/* use phc */
- if (!read_phc(node->master->clkid, clock->clkid,
- node->phc_readings,
+ if (!read_phc(priv->master->clkid, clock->clkid,
+ priv->phc_readings,
&offset, &ts, &delay))
continue;
}
- update_clock(node, clock, offset, ts, delay);
+ update_clock(priv, clock, offset, ts, delay);
}
}
return 0;
}
-static int check_clock_identity(struct node *node, struct ptp_message *msg)
+static int check_clock_identity(struct phc2sys_private *priv,
+ struct ptp_message *msg)
{
- if (!node->clock_identity_set)
+ if (!priv->clock_identity_set)
return 1;
- return cid_eq(&node->clock_identity,
+ return cid_eq(&priv->clock_identity,
&msg->header.sourcePortIdentity.clockIdentity);
}
@@ -841,12 +849,13 @@ static int normalize_state(int state)
return state;
}
-static int clock_compute_state(struct node *node, struct clock *clock)
+static int clock_compute_state(struct phc2sys_private *priv,
+ struct clock *clock)
{
struct port *p;
int state = PS_DISABLED;
- LIST_FOREACH(p, &node->ports, list) {
+ LIST_FOREACH(p, &priv->ports, list) {
if (p->clock != clock)
continue;
/* PS_SLAVE takes the highest precedence, PS_UNCALIBRATED
@@ -859,8 +868,8 @@ static int clock_compute_state(struct node *node, struct clock *clock)
return state;
}
-static int recv_subscribed(struct node *node, struct ptp_message *msg,
- int excluded)
+static int recv_subscribed(struct phc2sys_private *priv,
+ struct ptp_message *msg, int excluded)
{
int mgt_id, state;
struct portDS *pds;
@@ -873,7 +882,7 @@ static int recv_subscribed(struct node *node, struct ptp_message *msg,
switch (mgt_id) {
case TLV_PORT_DATA_SET:
pds = get_mgt_data(msg);
- port = port_get(node, pds->portIdentity.portNumber);
+ port = port_get(priv, pds->portIdentity.portNumber);
if (!port) {
pr_info("received data for unknown port %s",
pid2str(&pds->portIdentity));
@@ -885,10 +894,10 @@ static int recv_subscribed(struct node *node, struct ptp_message *msg,
pid2str(&pds->portIdentity));
port->state = state;
clock = port->clock;
- state = clock_compute_state(node, clock);
+ state = clock_compute_state(priv, clock);
if (clock->state != state || clock->new_state) {
clock->new_state = state;
- node->state_changed = 1;
+ priv->state_changed = 1;
}
}
return 1;
@@ -896,26 +905,26 @@ static int recv_subscribed(struct node *node, struct ptp_message *msg,
return 0;
}
-static void send_subscription(struct node *node)
+static void send_subscription(struct phc2sys_private *priv)
{
struct subscribe_events_np sen;
memset(&sen, 0, sizeof(sen));
sen.duration = PMC_SUBSCRIBE_DURATION;
sen.bitmask[0] = 1 << NOTIFY_PORT_STATE;
- pmc_send_set_action(node->pmc, TLV_SUBSCRIBE_EVENTS_NP, &sen, sizeof(sen));
+ pmc_send_set_action(priv->pmc, TLV_SUBSCRIBE_EVENTS_NP, &sen, sizeof(sen));
}
-static int init_pmc(struct config *cfg, struct node *node)
+static int init_pmc(struct config *cfg, struct phc2sys_private *priv)
{
char uds_local[MAX_IFNAME_SIZE + 1];
snprintf(uds_local, sizeof(uds_local), "/var/run/phc2sys.%d",
getpid());
- node->pmc = pmc_create(cfg, TRANS_UDS, uds_local, 0,
+ priv->pmc = pmc_create(cfg, TRANS_UDS, uds_local, 0,
config_get_int(cfg, NULL, "domainNumber"),
config_get_int(cfg, NULL, "transportSpecific") << 4, 1);
- if (!node->pmc) {
+ if (!priv->pmc) {
pr_err("failed to create pmc");
return -1;
}
@@ -929,7 +938,7 @@ static int init_pmc(struct config *cfg, struct node *node)
* -1: error reported by the other side
* -2: local error, fatal
*/
-static int run_pmc(struct node *node, int timeout, int ds_id,
+static int run_pmc(struct phc2sys_private *priv, int timeout, int ds_id,
struct ptp_message **msg)
{
#define N_FD 1
@@ -937,9 +946,9 @@ static int run_pmc(struct node *node, int timeout, int ds_id,
int cnt, res;
while (1) {
- pollfd[0].fd = pmc_get_transport_fd(node->pmc);
+ pollfd[0].fd = pmc_get_transport_fd(priv->pmc);
pollfd[0].events = POLLIN|POLLPRI;
- if (!node->pmc_ds_requested && ds_id >= 0)
+ if (!priv->pmc_ds_requested && ds_id >= 0)
pollfd[0].events |= POLLOUT;
cnt = poll(pollfd, N_FD, timeout);
@@ -949,7 +958,7 @@ static int run_pmc(struct node *node, int timeout, int ds_id,
}
if (!cnt) {
/* Request the data set again in the next run. */
- node->pmc_ds_requested = 0;
+ priv->pmc_ds_requested = 0;
return 0;
}
@@ -958,24 +967,24 @@ static int run_pmc(struct node *node, int timeout, int ds_id,
!(pollfd[0].revents & (POLLIN|POLLPRI))) {
switch (ds_id) {
case TLV_SUBSCRIBE_EVENTS_NP:
- send_subscription(node);
+ send_subscription(priv);
break;
default:
- pmc_send_get_action(node->pmc, ds_id);
+ pmc_send_get_action(priv->pmc, ds_id);
break;
}
- node->pmc_ds_requested = 1;
+ priv->pmc_ds_requested = 1;
}
if (!(pollfd[0].revents & (POLLIN|POLLPRI)))
continue;
- *msg = pmc_recv(node->pmc);
+ *msg = pmc_recv(priv->pmc);
if (!*msg)
continue;
- if (!check_clock_identity(node, *msg)) {
+ if (!check_clock_identity(priv, *msg)) {
msg_put(*msg);
*msg = NULL;
continue;
@@ -983,21 +992,21 @@ static int run_pmc(struct node *node, int timeout, int ds_id,
res = is_msg_mgt(*msg);
if (res < 0 && get_mgt_err_id(*msg) == ds_id) {
- node->pmc_ds_requested = 0;
+ priv->pmc_ds_requested = 0;
return -1;
}
- if (res <= 0 || recv_subscribed(node, *msg, ds_id) ||
+ if (res <= 0 || recv_subscribed(priv, *msg, ds_id) ||
get_mgt_id(*msg) != ds_id) {
msg_put(*msg);
*msg = NULL;
continue;
}
- node->pmc_ds_requested = 0;
+ priv->pmc_ds_requested = 0;
return 1;
}
}
-static int run_pmc_wait_sync(struct node *node, int timeout)
+static int run_pmc_wait_sync(struct phc2sys_private *priv, int timeout)
{
struct ptp_message *msg;
int res;
@@ -1005,7 +1014,7 @@ static int run_pmc_wait_sync(struct node *node, int timeout)
Enumeration8 portState;
while (1) {
- res = run_pmc(node, timeout, TLV_PORT_DATA_SET, &msg);
+ res = run_pmc(priv, timeout, TLV_PORT_DATA_SET, &msg);
if (res <= 0)
return res;
@@ -1019,47 +1028,47 @@ static int run_pmc_wait_sync(struct node *node, int timeout)
return 1;
}
/* try to get more data sets (for other ports) */
- node->pmc_ds_requested = 1;
+ priv->pmc_ds_requested = 1;
}
}
-static int run_pmc_get_utc_offset(struct node *node, int timeout)
+static int run_pmc_get_utc_offset(struct phc2sys_private *priv, int timeout)
{
struct ptp_message *msg;
int res;
struct timePropertiesDS *tds;
- res = run_pmc(node, timeout, TLV_TIME_PROPERTIES_DATA_SET, &msg);
+ res = run_pmc(priv, timeout, TLV_TIME_PROPERTIES_DATA_SET, &msg);
if (res <= 0)
return res;
tds = (struct timePropertiesDS *)get_mgt_data(msg);
if (tds->flags & PTP_TIMESCALE) {
- node->sync_offset = tds->currentUtcOffset;
+ priv->sync_offset = tds->currentUtcOffset;
if (tds->flags & LEAP_61)
- node->leap = 1;
+ priv->leap = 1;
else if (tds->flags & LEAP_59)
- node->leap = -1;
+ priv->leap = -1;
else
- node->leap = 0;
- node->utc_offset_traceable = tds->flags & UTC_OFF_VALID &&
+ priv->leap = 0;
+ priv->utc_offset_traceable = tds->flags & UTC_OFF_VALID &&
tds->flags & TIME_TRACEABLE;
} else {
- node->sync_offset = 0;
- node->leap = 0;
- node->utc_offset_traceable = 0;
+ priv->sync_offset = 0;
+ priv->leap = 0;
+ priv->utc_offset_traceable = 0;
}
msg_put(msg);
return 1;
}
-static int run_pmc_get_number_ports(struct node *node, int timeout)
+static int run_pmc_get_number_ports(struct phc2sys_private *priv, int timeout)
{
struct ptp_message *msg;
int res;
struct defaultDS *dds;
- res = run_pmc(node, timeout, TLV_DEFAULT_DATA_SET, &msg);
+ res = run_pmc(priv, timeout, TLV_DEFAULT_DATA_SET, &msg);
if (res <= 0)
return res;
@@ -1069,26 +1078,26 @@ static int run_pmc_get_number_ports(struct node *node, int timeout)
return res;
}
-static int run_pmc_subscribe(struct node *node, int timeout)
+static int run_pmc_subscribe(struct phc2sys_private *priv, int timeout)
{
struct ptp_message *msg;
int res;
- res = run_pmc(node, timeout, TLV_SUBSCRIBE_EVENTS_NP, &msg);
+ res = run_pmc(priv, timeout, TLV_SUBSCRIBE_EVENTS_NP, &msg);
if (res <= 0)
return res;
msg_put(msg);
return 1;
}
-static void run_pmc_events(struct node *node)
+static void run_pmc_events(struct phc2sys_private *priv)
{
struct ptp_message *msg;
- run_pmc(node, 0, -1, &msg);
+ run_pmc(priv, 0, -1, &msg);
}
-static int run_pmc_port_properties(struct node *node, int timeout,
+static int run_pmc_port_properties(struct phc2sys_private *priv, int timeout,
unsigned int port,
int *state, int *tstamping, char *iface)
{
@@ -1096,9 +1105,9 @@ static int run_pmc_port_properties(struct node *node, int timeout,
int res, len;
struct port_properties_np *ppn;
- pmc_target_port(node->pmc, port);
+ pmc_target_port(priv->pmc, port);
while (1) {
- res = run_pmc(node, timeout, TLV_PORT_PROPERTIES_NP, &msg);
+ res = run_pmc(priv, timeout, TLV_PORT_PROPERTIES_NP, &msg);
if (res <= 0)
goto out;
@@ -1121,35 +1130,35 @@ static int run_pmc_port_properties(struct node *node, int timeout,
break;
}
out:
- pmc_target_all(node->pmc);
+ pmc_target_all(priv->pmc);
return res;
}
-static int run_pmc_clock_identity(struct node *node, int timeout)
+static int run_pmc_clock_identity(struct phc2sys_private *priv, int timeout)
{
struct ptp_message *msg;
struct defaultDS *dds;
int res;
- res = run_pmc(node, timeout, TLV_DEFAULT_DATA_SET, &msg);
+ res = run_pmc(priv, timeout, TLV_DEFAULT_DATA_SET, &msg);
if (res <= 0)
return res;
dds = (struct defaultDS *)get_mgt_data(msg);
- memcpy(&node->clock_identity, &dds->clockIdentity,
+ memcpy(&priv->clock_identity, &dds->clockIdentity,
sizeof(struct ClockIdentity));
- node->clock_identity_set = 1;
+ priv->clock_identity_set = 1;
msg_put(msg);
return 1;
}
-static void close_pmc(struct node *node)
+static void close_pmc(struct phc2sys_private *priv)
{
- pmc_destroy(node->pmc);
- node->pmc = NULL;
+ pmc_destroy(priv->pmc);
+ priv->pmc = NULL;
}
-static int auto_init_ports(struct node *node, int add_rt)
+static int auto_init_ports(struct phc2sys_private *priv, int add_rt)
{
struct port *port;
struct clock *clock;
@@ -1161,7 +1170,7 @@ static int auto_init_ports(struct node *node, int add_rt)
while (1) {
if (!is_running())
return -1;
- res = run_pmc_clock_identity(node, 1000);
+ res = run_pmc_clock_identity(priv, 1000);
if (res < 0)
return -1;
if (res > 0)
@@ -1170,20 +1179,20 @@ static int auto_init_ports(struct node *node, int add_rt)
pr_notice("Waiting for ptp4l...");
}
- number_ports = run_pmc_get_number_ports(node, 1000);
+ number_ports = run_pmc_get_number_ports(priv, 1000);
if (number_ports <= 0) {
pr_err("failed to get number of ports");
return -1;
}
- res = run_pmc_subscribe(node, 1000);
+ res = run_pmc_subscribe(priv, 1000);
if (res <= 0) {
pr_err("failed to subscribe");
return -1;
}
for (i = 1; i <= number_ports; i++) {
- res = run_pmc_port_properties(node, 1000, i, &state,
+ res = run_pmc_port_properties(priv, 1000, i, &state,
×tamping, iface);
if (res == -1) {
/* port does not exist, ignore the port */
@@ -1197,22 +1206,22 @@ static int auto_init_ports(struct node *node, int add_rt)
/* ignore ports with software time stamping */
continue;
}
- port = port_add(node, i, iface);
+ port = port_add(priv, i, iface);
if (!port)
return -1;
port->state = normalize_state(state);
}
- if (LIST_EMPTY(&node->clocks)) {
+ if (LIST_EMPTY(&priv->clocks)) {
pr_err("no suitable ports available");
return -1;
}
- LIST_FOREACH(clock, &node->clocks, list) {
- clock->new_state = clock_compute_state(node, clock);
+ LIST_FOREACH(clock, &priv->clocks, list) {
+ clock->new_state = clock_compute_state(priv, clock);
}
- node->state_changed = 1;
+ priv->state_changed = 1;
if (add_rt) {
- clock = clock_add(node, "CLOCK_REALTIME");
+ clock = clock_add(priv, "CLOCK_REALTIME");
if (!clock)
return -1;
if (add_rt == 1)
@@ -1220,7 +1229,7 @@ static int auto_init_ports(struct node *node, int add_rt)
}
/* get initial offset */
- if (run_pmc_get_utc_offset(node, 1000) <= 0) {
+ if (run_pmc_get_utc_offset(priv, 1000) <= 0) {
pr_err("failed to get UTC offset");
return -1;
}
@@ -1228,7 +1237,7 @@ static int auto_init_ports(struct node *node, int add_rt)
}
/* Returns: -1 in case of error, 0 otherwise */
-static int update_pmc(struct node *node, int subscribe)
+static int update_pmc(struct phc2sys_private *priv, int subscribe)
{
struct timespec tp;
uint64_t ts;
@@ -1239,33 +1248,33 @@ static int update_pmc(struct node *node, int subscribe)
}
ts = tp.tv_sec * NS_PER_SEC + tp.tv_nsec;
- if (node->pmc &&
- !(ts > node->pmc_last_update &&
- ts - node->pmc_last_update < PMC_UPDATE_INTERVAL)) {
+ if (priv->pmc &&
+ !(ts > priv->pmc_last_update &&
+ ts - priv->pmc_last_update < PMC_UPDATE_INTERVAL)) {
if (subscribe)
- run_pmc_subscribe(node, 0);
- if (run_pmc_get_utc_offset(node, 0) > 0)
- node->pmc_last_update = ts;
+ run_pmc_subscribe(priv, 0);
+ if (run_pmc_get_utc_offset(priv, 0) > 0)
+ priv->pmc_last_update = ts;
}
return 0;
}
/* Returns: non-zero to skip clock update */
-static int clock_handle_leap(struct node *node, struct clock *clock,
+static int clock_handle_leap(struct phc2sys_private *priv, struct clock *clock,
int64_t offset, ui...
[truncated message content] |
|
From: Jacob K. <jac...@in...> - 2020-08-05 23:15:08
|
On 8/1/2020 10:46 AM, Vladimir Oltean wrote:
> We will be reusing some PMC code between phc2sys and ts2phc. In
> preparation of that, we would like to extract the PMC related properties
> of the current private program data structure of phc2sys, "struct node",
> into something smaller that can be shared properly.
>
> The "struct node" name is nice enough, so use that to denote the smaller
> data structure for PMC from now on. Rename the bigger data structure to
> phc2sys_private.
If this gets extracted out to another file I feel like node might be too
generic. But the change to phc2sys_private seems reasonable.
The patch is noisy, but I checked using word-diff and it only changes
the name.
Reviewed-by: Jacob Keller <jac...@in...>
>
> Signed-off-by: Vladimir Oltean <ol...@gm...>
> ---
> phc2sys.c | 433 ++++++++++++++++++++++++++++--------------------------
> 1 file changed, 221 insertions(+), 212 deletions(-)
>
> diff --git a/phc2sys.c b/phc2sys.c
> index 64bdf2664fe4..a36cbe071d7d 100644
> --- a/phc2sys.c
> +++ b/phc2sys.c
> @@ -99,7 +99,7 @@ struct port {
> struct clock *clock;
> };
>
> -struct node {
> +struct phc2sys_private {
> unsigned int stats_max_count;
> int sanity_freq_limit;
> enum servo_type servo_type;
> @@ -124,18 +124,21 @@ struct node {
>
> static struct config *phc2sys_config;
>
> -static int update_pmc(struct node *node, int subscribe);
> -static int clock_handle_leap(struct node *node, struct clock *clock,
> +static int update_pmc(struct phc2sys_private *priv, int subscribe);
> +static int clock_handle_leap(struct phc2sys_private *priv,
> + struct clock *clock,
> int64_t offset, uint64_t ts);
> -static int run_pmc_get_utc_offset(struct node *node, int timeout);
> -static void run_pmc_events(struct node *node);
> +static int run_pmc_get_utc_offset(struct phc2sys_private *priv,
> + int timeout);
> +static void run_pmc_events(struct phc2sys_private *priv);
>
> static int normalize_state(int state);
> -static int run_pmc_port_properties(struct node *node, int timeout,
> - unsigned int port,
> +static int run_pmc_port_properties(struct phc2sys_private *priv,
> + int timeout, unsigned int port,
> int *state, int *tstamping, char *iface);
>
> -static struct servo *servo_add(struct node *node, struct clock *clock)
> +static struct servo *servo_add(struct phc2sys_private *priv,
> + struct clock *clock)
> {
> double ppb;
> int max_ppb;
> @@ -157,19 +160,19 @@ static struct servo *servo_add(struct node *node, struct clock *clock)
> }
> }
>
> - servo = servo_create(phc2sys_config, node->servo_type,
> + servo = servo_create(phc2sys_config, priv->servo_type,
> -ppb, max_ppb, 0);
> if (!servo) {
> pr_err("Failed to create servo");
> return NULL;
> }
>
> - servo_sync_interval(servo, node->phc_interval);
> + servo_sync_interval(servo, priv->phc_interval);
>
> return servo;
> }
>
> -static struct clock *clock_add(struct node *node, char *device)
> +static struct clock *clock_add(struct phc2sys_private *priv, char *device)
> {
> struct clock *c;
> clockid_t clkid = CLOCK_INVALID;
> @@ -198,7 +201,7 @@ static struct clock *clock_add(struct node *node, char *device)
> c->source_label = "phc";
> }
>
> - if (node->stats_max_count > 0) {
> + if (priv->stats_max_count > 0) {
> c->offset_stats = stats_create();
> c->freq_stats = stats_create();
> c->delay_stats = stats_create();
> @@ -209,8 +212,8 @@ static struct clock *clock_add(struct node *node, char *device)
> return NULL;
> }
> }
> - if (node->sanity_freq_limit) {
> - c->sanity_check = clockcheck_create(node->sanity_freq_limit);
> + if (priv->sanity_freq_limit) {
> + c->sanity_check = clockcheck_create(priv->sanity_freq_limit);
> if (!c->sanity_check) {
> pr_err("failed to create clock check");
> return NULL;
> @@ -218,21 +221,21 @@ static struct clock *clock_add(struct node *node, char *device)
> }
>
> if (clkid != CLOCK_INVALID)
> - c->servo = servo_add(node, c);
> + c->servo = servo_add(priv, c);
>
> if (clkid != CLOCK_INVALID && clkid != CLOCK_REALTIME)
> c->sysoff_method = sysoff_probe(CLOCKID_TO_FD(clkid),
> - node->phc_readings);
> + priv->phc_readings);
>
> - LIST_INSERT_HEAD(&node->clocks, c, list);
> + LIST_INSERT_HEAD(&priv->clocks, c, list);
> return c;
> }
>
> -static void clock_cleanup(struct node *node)
> +static void clock_cleanup(struct phc2sys_private *priv)
> {
> struct clock *c, *tmp;
>
> - LIST_FOREACH_SAFE(c, &node->clocks, list, tmp) {
> + LIST_FOREACH_SAFE(c, &priv->clocks, list, tmp) {
> if (c->servo) {
> servo_destroy(c->servo);
> }
> @@ -255,45 +258,45 @@ static void clock_cleanup(struct node *node)
> }
> }
>
> -static void port_cleanup(struct node *node)
> +static void port_cleanup(struct phc2sys_private *priv)
> {
> struct port *p, *tmp;
>
> - LIST_FOREACH_SAFE(p, &node->ports, list, tmp) {
> + LIST_FOREACH_SAFE(p, &priv->ports, list, tmp) {
> free(p);
> }
> }
>
> -static struct port *port_get(struct node *node, unsigned int number)
> +static struct port *port_get(struct phc2sys_private *priv, unsigned int number)
> {
> struct port *p;
>
> - LIST_FOREACH(p, &node->ports, list) {
> + LIST_FOREACH(p, &priv->ports, list) {
> if (p->number == number)
> return p;
> }
> return NULL;
> }
>
> -static struct port *port_add(struct node *node, unsigned int number,
> +static struct port *port_add(struct phc2sys_private *priv, unsigned int number,
> char *device)
> {
> struct port *p;
> struct clock *c = NULL, *tmp;
>
> - p = port_get(node, number);
> + p = port_get(priv, number);
> if (p)
> return p;
> /* port is a new one, look whether we have the device already on
> * a different port */
> - LIST_FOREACH(tmp, &node->clocks, list) {
> + LIST_FOREACH(tmp, &priv->clocks, list) {
> if (!strcmp(tmp->device, device)) {
> c = tmp;
> break;
> }
> }
> if (!c) {
> - c = clock_add(node, device);
> + c = clock_add(priv, device);
> if (!c)
> return NULL;
> }
> @@ -304,11 +307,12 @@ static struct port *port_add(struct node *node, unsigned int number,
> }
> p->number = number;
> p->clock = c;
> - LIST_INSERT_HEAD(&node->ports, p, list);
> + LIST_INSERT_HEAD(&priv->ports, p, list);
> return p;
> }
>
> -static void clock_reinit(struct node *node, struct clock *clock, int new_state)
> +static void clock_reinit(struct phc2sys_private *priv, struct clock *clock,
> + int new_state)
> {
> int phc_index = -1, phc_switched = 0;
> int state, timestamping, ret = -1;
> @@ -318,9 +322,9 @@ static void clock_reinit(struct node *node, struct clock *clock, int new_state)
> char iface[IFNAMSIZ];
> clockid_t clkid = CLOCK_INVALID;
>
> - LIST_FOREACH(p, &node->ports, list) {
> + LIST_FOREACH(p, &priv->ports, list) {
> if (p->clock == clock) {
> - ret = run_pmc_port_properties(node, 1000, p->number,
> + ret = run_pmc_port_properties(priv, 1000, p->number,
> &state, ×tamping,
> iface);
> if (ret > 0)
> @@ -345,7 +349,7 @@ static void clock_reinit(struct node *node, struct clock *clock, int new_state)
> clock->clkid = clkid;
> clock->phc_index = phc_index;
>
> - servo = servo_add(node, clock);
> + servo = servo_add(priv, clock);
> if (servo) {
> servo_destroy(clock->servo);
> clock->servo = servo;
> @@ -367,9 +371,11 @@ static void clock_reinit(struct node *node, struct clock *clock, int new_state)
> }
> }
>
> -static struct clock *find_dst_clock(struct node *node, int phc_index) {
> +static struct clock *find_dst_clock(struct phc2sys_private *priv,
> + int phc_index)
> +{
> struct clock *c = NULL;
> - LIST_FOREACH(c, &node->dst_clocks, dst_list) {
> + LIST_FOREACH(c, &priv->dst_clocks, dst_list) {
> if (c->phc_index == phc_index) {
> break;
> }
> @@ -377,26 +383,26 @@ static struct clock *find_dst_clock(struct node *node, int phc_index) {
> return c;
> }
>
> -static void reconfigure(struct node *node)
> +static void reconfigure(struct phc2sys_private *priv)
> {
> struct clock *c, *rt = NULL, *src = NULL, *last = NULL, *dup = NULL;
> int src_cnt = 0, dst_cnt = 0;
>
> pr_info("reconfiguring after port state change");
> - node->state_changed = 0;
> + priv->state_changed = 0;
>
> - while (node->dst_clocks.lh_first != NULL) {
> - LIST_REMOVE(node->dst_clocks.lh_first, dst_list);
> + while (priv->dst_clocks.lh_first != NULL) {
> + LIST_REMOVE(priv->dst_clocks.lh_first, dst_list);
> }
>
> - LIST_FOREACH(c, &node->clocks, list) {
> + LIST_FOREACH(c, &priv->clocks, list) {
> if (c->clkid == CLOCK_REALTIME) {
> rt = c;
> continue;
> }
>
> if (c->new_state) {
> - clock_reinit(node, c, c->new_state);
> + clock_reinit(priv, c, c->new_state);
> c->state = c->new_state;
> c->new_state = 0;
> }
> @@ -408,12 +414,12 @@ static void reconfigure(struct node *node)
> case PS_PRE_MASTER:
> case PS_MASTER:
> case PS_PASSIVE:
> - dup = find_dst_clock(node, c->phc_index);
> + dup = find_dst_clock(priv, c->phc_index);
> if (!dup) {
> pr_info("selecting %s for synchronization",
> c->device);
> dst_cnt++;
> - LIST_INSERT_HEAD(&node->dst_clocks,
> + LIST_INSERT_HEAD(&priv->dst_clocks,
> c, dst_list);
> } else {
> pr_info("skipping %s: %s has the same clock "
> @@ -433,10 +439,10 @@ static void reconfigure(struct node *node)
> }
> if (dst_cnt > 1 && !src) {
> if (!rt || rt->dest_only) {
> - node->master = last;
> + priv->master = last;
> /* Reset to original state in next reconfiguration. */
> - node->master->new_state = node->master->state;
> - node->master->state = PS_SLAVE;
> + priv->master->new_state = priv->master->state;
> + priv->master->state = PS_SLAVE;
> if (rt)
> rt->state = PS_SLAVE;
> pr_info("no source, selecting %s as the default clock",
> @@ -446,23 +452,23 @@ static void reconfigure(struct node *node)
> }
> if (src_cnt > 1) {
> pr_info("multiple master clocks available, postponing sync...");
> - node->master = NULL;
> + priv->master = NULL;
> return;
> }
> if (src_cnt > 0 && !src) {
> pr_info("master clock not ready, waiting...");
> - node->master = NULL;
> + priv->master = NULL;
> return;
> }
> if (!src_cnt && !dst_cnt) {
> pr_info("no PHC ready, waiting...");
> - node->master = NULL;
> + priv->master = NULL;
> return;
> }
> if ((!src_cnt && (!rt || rt->dest_only)) ||
> (!dst_cnt && !rt)) {
> pr_info("nothing to synchronize");
> - node->master = NULL;
> + priv->master = NULL;
> return;
> }
> if (!src_cnt) {
> @@ -471,12 +477,12 @@ static void reconfigure(struct node *node)
> } else if (rt) {
> if (rt->state != PS_MASTER) {
> rt->state = PS_MASTER;
> - clock_reinit(node, rt, rt->state);
> + clock_reinit(priv, rt, rt->state);
> }
> - LIST_INSERT_HEAD(&node->dst_clocks, rt, dst_list);
> + LIST_INSERT_HEAD(&priv->dst_clocks, rt, dst_list);
> pr_info("selecting %s for synchronization", rt->device);
> }
> - node->master = src;
> + priv->master = src;
> pr_info("selecting %s as the master clock", src->device);
> }
>
> @@ -511,12 +517,12 @@ static int read_phc(clockid_t clkid, clockid_t sysclk, int readings,
> return 1;
> }
>
> -static int64_t get_sync_offset(struct node *node, struct clock *dst)
> +static int64_t get_sync_offset(struct phc2sys_private *priv, struct clock *dst)
> {
> - int direction = node->forced_sync_offset;
> + int direction = priv->forced_sync_offset;
>
> if (!direction)
> - direction = dst->is_utc - node->master->is_utc;
> + direction = dst->is_utc - priv->master->is_utc;
> return (int64_t)dst->sync_offset * NS_PER_SEC * direction;
> }
>
> @@ -559,16 +565,16 @@ static void update_clock_stats(struct clock *clock, unsigned int max_count,
> stats_reset(clock->delay_stats);
> }
>
> -static void update_clock(struct node *node, struct clock *clock,
> +static void update_clock(struct phc2sys_private *priv, struct clock *clock,
> int64_t offset, uint64_t ts, int64_t delay)
> {
> enum servo_state state;
> double ppb;
>
> - if (clock_handle_leap(node, clock, offset, ts))
> + if (clock_handle_leap(priv, clock, offset, ts))
> return;
>
> - offset += get_sync_offset(node, clock);
> + offset += get_sync_offset(priv, clock);
>
> if (clock->sanity_check && clockcheck_sample(clock->sanity_check, ts))
> servo_reset(clock->servo);
> @@ -595,16 +601,16 @@ static void update_clock(struct node *node, struct clock *clock,
> }
>
> if (clock->offset_stats) {
> - update_clock_stats(clock, node->stats_max_count, offset, ppb, delay);
> + update_clock_stats(clock, priv->stats_max_count, offset, ppb, delay);
> } else {
> if (delay >= 0) {
> pr_info("%s %s offset %9" PRId64 " s%d freq %+7.0f "
> "delay %6" PRId64,
> - clock->device, node->master->source_label,
> + clock->device, priv->master->source_label,
> offset, state, ppb, delay);
> } else {
> pr_info("%s %s offset %9" PRId64 " s%d freq %+7.0f",
> - clock->device, node->master->source_label,
> + clock->device, priv->master->source_label,
> offset, state, ppb);
> }
> }
> @@ -642,19 +648,20 @@ static int read_pps(int fd, int64_t *offset, uint64_t *ts)
> return 1;
> }
>
> -static int do_pps_loop(struct node *node, struct clock *clock, int fd)
> +static int do_pps_loop(struct phc2sys_private *priv, struct clock *clock,
> + int fd)
> {
> int64_t pps_offset, phc_offset, phc_delay;
> uint64_t pps_ts, phc_ts;
> - clockid_t src = node->master->clkid;
> + clockid_t src = priv->master->clkid;
>
> - node->master->source_label = "pps";
> + priv->master->source_label = "pps";
>
> if (src == CLOCK_INVALID) {
> /* The sync offset can't be applied with PPS alone. */
> - node->sync_offset = 0;
> + priv->sync_offset = 0;
> } else {
> - enable_pps_output(node->master->clkid);
> + enable_pps_output(priv->master->clkid);
> }
>
> while (is_running()) {
> @@ -665,7 +672,7 @@ static int do_pps_loop(struct node *node, struct clock *clock, int fd)
> /* If a PHC is available, use it to get the whole number
> of seconds in the offset and PPS for the rest. */
> if (src != CLOCK_INVALID) {
> - if (!read_phc(src, clock->clkid, node->phc_readings,
> + if (!read_phc(src, clock->clkid, priv->phc_readings,
> &phc_offset, &phc_ts, &phc_delay))
> return -1;
>
> @@ -683,9 +690,9 @@ static int do_pps_loop(struct node *node, struct clock *clock, int fd)
> pps_offset = pps_ts - phc_ts;
> }
>
> - if (update_pmc(node, 0) < 0)
> + if (update_pmc(priv, 0) < 0)
> continue;
> - update_clock(node, clock, pps_offset, pps_ts, -1);
> + update_clock(priv, clock, pps_offset, pps_ts, -1);
> }
> close(fd);
> return 0;
> @@ -708,45 +715,45 @@ static int update_needed(struct clock *c)
> return 0;
> }
>
> -static int do_loop(struct node *node, int subscriptions)
> +static int do_loop(struct phc2sys_private *priv, int subscriptions)
> {
> struct timespec interval;
> struct clock *clock;
> uint64_t ts;
> int64_t offset, delay;
>
> - interval.tv_sec = node->phc_interval;
> - interval.tv_nsec = (node->phc_interval - interval.tv_sec) * 1e9;
> + interval.tv_sec = priv->phc_interval;
> + interval.tv_nsec = (priv->phc_interval - interval.tv_sec) * 1e9;
>
> while (is_running()) {
> clock_nanosleep(CLOCK_MONOTONIC, 0, &interval, NULL);
> - if (update_pmc(node, subscriptions) < 0)
> + if (update_pmc(priv, subscriptions) < 0)
> continue;
>
> if (subscriptions) {
> - run_pmc_events(node);
> - if (node->state_changed) {
> + run_pmc_events(priv);
> + if (priv->state_changed) {
> /* force getting offset, as it may have
> * changed after the port state change */
> - if (run_pmc_get_utc_offset(node, 1000) <= 0) {
> + if (run_pmc_get_utc_offset(priv, 1000) <= 0) {
> pr_err("failed to get UTC offset");
> continue;
> }
> - reconfigure(node);
> + reconfigure(priv);
> }
> }
> - if (!node->master)
> + if (!priv->master)
> continue;
>
> - LIST_FOREACH(clock, &node->dst_clocks, dst_list) {
> + LIST_FOREACH(clock, &priv->dst_clocks, dst_list) {
> if (!update_needed(clock))
> continue;
>
> /* don't try to synchronize the clock to itself */
> - if (clock->clkid == node->master->clkid ||
> + if (clock->clkid == priv->master->clkid ||
> (clock->phc_index >= 0 &&
> - clock->phc_index == node->master->phc_index) ||
> - !strcmp(clock->device, node->master->device))
> + clock->phc_index == priv->master->phc_index) ||
> + !strcmp(clock->device, priv->master->device))
> continue;
>
> if (!clock->servo) {
> @@ -755,41 +762,42 @@ static int do_loop(struct node *node, int subscriptions)
> }
>
> if (clock->clkid == CLOCK_REALTIME &&
> - node->master->sysoff_method >= 0) {
> + priv->master->sysoff_method >= 0) {
> /* use sysoff */
> - if (sysoff_measure(CLOCKID_TO_FD(node->master->clkid),
> - node->master->sysoff_method,
> - node->phc_readings,
> + if (sysoff_measure(CLOCKID_TO_FD(priv->master->clkid),
> + priv->master->sysoff_method,
> + priv->phc_readings,
> &offset, &ts, &delay) < 0)
> return -1;
> - } else if (node->master->clkid == CLOCK_REALTIME &&
> + } else if (priv->master->clkid == CLOCK_REALTIME &&
> clock->sysoff_method >= 0) {
> /* use reversed sysoff */
> if (sysoff_measure(CLOCKID_TO_FD(clock->clkid),
> clock->sysoff_method,
> - node->phc_readings,
> + priv->phc_readings,
> &offset, &ts, &delay) < 0)
> return -1;
> offset = -offset;
> ts += offset;
> } else {
> /* use phc */
> - if (!read_phc(node->master->clkid, clock->clkid,
> - node->phc_readings,
> + if (!read_phc(priv->master->clkid, clock->clkid,
> + priv->phc_readings,
> &offset, &ts, &delay))
> continue;
> }
> - update_clock(node, clock, offset, ts, delay);
> + update_clock(priv, clock, offset, ts, delay);
> }
> }
> return 0;
> }
>
> -static int check_clock_identity(struct node *node, struct ptp_message *msg)
> +static int check_clock_identity(struct phc2sys_private *priv,
> + struct ptp_message *msg)
> {
> - if (!node->clock_identity_set)
> + if (!priv->clock_identity_set)
> return 1;
> - return cid_eq(&node->clock_identity,
> + return cid_eq(&priv->clock_identity,
> &msg->header.sourcePortIdentity.clockIdentity);
> }
>
> @@ -841,12 +849,13 @@ static int normalize_state(int state)
> return state;
> }
>
> -static int clock_compute_state(struct node *node, struct clock *clock)
> +static int clock_compute_state(struct phc2sys_private *priv,
> + struct clock *clock)
> {
> struct port *p;
> int state = PS_DISABLED;
>
> - LIST_FOREACH(p, &node->ports, list) {
> + LIST_FOREACH(p, &priv->ports, list) {
> if (p->clock != clock)
> continue;
> /* PS_SLAVE takes the highest precedence, PS_UNCALIBRATED
> @@ -859,8 +868,8 @@ static int clock_compute_state(struct node *node, struct clock *clock)
> return state;
> }
>
> -static int recv_subscribed(struct node *node, struct ptp_message *msg,
> - int excluded)
> +static int recv_subscribed(struct phc2sys_private *priv,
> + struct ptp_message *msg, int excluded)
> {
> int mgt_id, state;
> struct portDS *pds;
> @@ -873,7 +882,7 @@ static int recv_subscribed(struct node *node, struct ptp_message *msg,
> switch (mgt_id) {
> case TLV_PORT_DATA_SET:
> pds = get_mgt_data(msg);
> - port = port_get(node, pds->portIdentity.portNumber);
> + port = port_get(priv, pds->portIdentity.portNumber);
> if (!port) {
> pr_info("received data for unknown port %s",
> pid2str(&pds->portIdentity));
> @@ -885,10 +894,10 @@ static int recv_subscribed(struct node *node, struct ptp_message *msg,
> pid2str(&pds->portIdentity));
> port->state = state;
> clock = port->clock;
> - state = clock_compute_state(node, clock);
> + state = clock_compute_state(priv, clock);
> if (clock->state != state || clock->new_state) {
> clock->new_state = state;
> - node->state_changed = 1;
> + priv->state_changed = 1;
> }
> }
> return 1;
> @@ -896,26 +905,26 @@ static int recv_subscribed(struct node *node, struct ptp_message *msg,
> return 0;
> }
>
> -static void send_subscription(struct node *node)
> +static void send_subscription(struct phc2sys_private *priv)
> {
> struct subscribe_events_np sen;
>
> memset(&sen, 0, sizeof(sen));
> sen.duration = PMC_SUBSCRIBE_DURATION;
> sen.bitmask[0] = 1 << NOTIFY_PORT_STATE;
> - pmc_send_set_action(node->pmc, TLV_SUBSCRIBE_EVENTS_NP, &sen, sizeof(sen));
> + pmc_send_set_action(priv->pmc, TLV_SUBSCRIBE_EVENTS_NP, &sen, sizeof(sen));
> }
>
> -static int init_pmc(struct config *cfg, struct node *node)
> +static int init_pmc(struct config *cfg, struct phc2sys_private *priv)
> {
> char uds_local[MAX_IFNAME_SIZE + 1];
>
> snprintf(uds_local, sizeof(uds_local), "/var/run/phc2sys.%d",
> getpid());
> - node->pmc = pmc_create(cfg, TRANS_UDS, uds_local, 0,
> + priv->pmc = pmc_create(cfg, TRANS_UDS, uds_local, 0,
> config_get_int(cfg, NULL, "domainNumber"),
> config_get_int(cfg, NULL, "transportSpecific") << 4, 1);
> - if (!node->pmc) {
> + if (!priv->pmc) {
> pr_err("failed to create pmc");
> return -1;
> }
> @@ -929,7 +938,7 @@ static int init_pmc(struct config *cfg, struct node *node)
> * -1: error reported by the other side
> * -2: local error, fatal
> */
> -static int run_pmc(struct node *node, int timeout, int ds_id,
> +static int run_pmc(struct phc2sys_private *priv, int timeout, int ds_id,
> struct ptp_message **msg)
> {
> #define N_FD 1
> @@ -937,9 +946,9 @@ static int run_pmc(struct node *node, int timeout, int ds_id,
> int cnt, res;
>
> while (1) {
> - pollfd[0].fd = pmc_get_transport_fd(node->pmc);
> + pollfd[0].fd = pmc_get_transport_fd(priv->pmc);
> pollfd[0].events = POLLIN|POLLPRI;
> - if (!node->pmc_ds_requested && ds_id >= 0)
> + if (!priv->pmc_ds_requested && ds_id >= 0)
> pollfd[0].events |= POLLOUT;
>
> cnt = poll(pollfd, N_FD, timeout);
> @@ -949,7 +958,7 @@ static int run_pmc(struct node *node, int timeout, int ds_id,
> }
> if (!cnt) {
> /* Request the data set again in the next run. */
> - node->pmc_ds_requested = 0;
> + priv->pmc_ds_requested = 0;
> return 0;
> }
>
> @@ -958,24 +967,24 @@ static int run_pmc(struct node *node, int timeout, int ds_id,
> !(pollfd[0].revents & (POLLIN|POLLPRI))) {
> switch (ds_id) {
> case TLV_SUBSCRIBE_EVENTS_NP:
> - send_subscription(node);
> + send_subscription(priv);
> break;
> default:
> - pmc_send_get_action(node->pmc, ds_id);
> + pmc_send_get_action(priv->pmc, ds_id);
> break;
> }
> - node->pmc_ds_requested = 1;
> + priv->pmc_ds_requested = 1;
> }
>
> if (!(pollfd[0].revents & (POLLIN|POLLPRI)))
> continue;
>
> - *msg = pmc_recv(node->pmc);
> + *msg = pmc_recv(priv->pmc);
>
> if (!*msg)
> continue;
>
> - if (!check_clock_identity(node, *msg)) {
> + if (!check_clock_identity(priv, *msg)) {
> msg_put(*msg);
> *msg = NULL;
> continue;
> @@ -983,21 +992,21 @@ static int run_pmc(struct node *node, int timeout, int ds_id,
>
> res = is_msg_mgt(*msg);
> if (res < 0 && get_mgt_err_id(*msg) == ds_id) {
> - node->pmc_ds_requested = 0;
> + priv->pmc_ds_requested = 0;
> return -1;
> }
> - if (res <= 0 || recv_subscribed(node, *msg, ds_id) ||
> + if (res <= 0 || recv_subscribed(priv, *msg, ds_id) ||
> get_mgt_id(*msg) != ds_id) {
> msg_put(*msg);
> *msg = NULL;
> continue;
> }
> - node->pmc_ds_requested = 0;
> + priv->pmc_ds_requested = 0;
> return 1;
> }
> }
>
> -static int run_pmc_wait_sync(struct node *node, int timeout)
> +static int run_pmc_wait_sync(struct phc2sys_private *priv, int timeout)
> {
> struct ptp_message *msg;
> int res;
> @@ -1005,7 +1014,7 @@ static int run_pmc_wait_sync(struct node *node, int timeout)
> Enumeration8 portState;
>
> while (1) {
> - res = run_pmc(node, timeout, TLV_PORT_DATA_SET, &msg);
> + res = run_pmc(priv, timeout, TLV_PORT_DATA_SET, &msg);
> if (res <= 0)
> return res;
>
> @@ -1019,47 +1028,47 @@ static int run_pmc_wait_sync(struct node *node, int timeout)
> return 1;
> }
> /* try to get more data sets (for other ports) */
> - node->pmc_ds_requested = 1;
> + priv->pmc_ds_requested = 1;
> }
> }
>
> -static int run_pmc_get_utc_offset(struct node *node, int timeout)
> +static int run_pmc_get_utc_offset(struct phc2sys_private *priv, int timeout)
> {
> struct ptp_message *msg;
> int res;
> struct timePropertiesDS *tds;
>
> - res = run_pmc(node, timeout, TLV_TIME_PROPERTIES_DATA_SET, &msg);
> + res = run_pmc(priv, timeout, TLV_TIME_PROPERTIES_DATA_SET, &msg);
> if (res <= 0)
> return res;
>
> tds = (struct timePropertiesDS *)get_mgt_data(msg);
> if (tds->flags & PTP_TIMESCALE) {
> - node->sync_offset = tds->currentUtcOffset;
> + priv->sync_offset = tds->currentUtcOffset;
> if (tds->flags & LEAP_61)
> - node->leap = 1;
> + priv->leap = 1;
> else if (tds->flags & LEAP_59)
> - node->leap = -1;
> + priv->leap = -1;
> else
> - node->leap = 0;
> - node->utc_offset_traceable = tds->flags & UTC_OFF_VALID &&
> + priv->leap = 0;
> + priv->utc_offset_traceable = tds->flags & UTC_OFF_VALID &&
> tds->flags & TIME_TRACEABLE;
> } else {
> - node->sync_offset = 0;
> - node->leap = 0;
> - node->utc_offset_traceable = 0;
> + priv->sync_offset = 0;
> + priv->leap = 0;
> + priv->utc_offset_traceable = 0;
> }
> msg_put(msg);
> return 1;
> }
>
> -static int run_pmc_get_number_ports(struct node *node, int timeout)
> +static int run_pmc_get_number_ports(struct phc2sys_private *priv, int timeout)
> {
> struct ptp_message *msg;
> int res;
> struct defaultDS *dds;
>
> - res = run_pmc(node, timeout, TLV_DEFAULT_DATA_SET, &msg);
> + res = run_pmc(priv, timeout, TLV_DEFAULT_DATA_SET, &msg);
> if (res <= 0)
> return res;
>
> @@ -1069,26 +1078,26 @@ static int run_pmc_get_number_ports(struct node *node, int timeout)
> return res;
> }
>
> -static int run_pmc_subscribe(struct node *node, int timeout)
> +static int run_pmc_subscribe(struct phc2sys_private *priv, int timeout)
> {
> struct ptp_message *msg;
> int res;
>
> - res = run_pmc(node, timeout, TLV_SUBSCRIBE_EVENTS_NP, &msg);
> + res = run_pmc(priv, timeout, TLV_SUBSCRIBE_EVENTS_NP, &msg);
> if (res <= 0)
> return res;
> msg_put(msg);
> return 1;
> }
>
> -static void run_pmc_events(struct node *node)
> +static void run_pmc_events(struct phc2sys_private *priv)
> {
> struct ptp_message *msg;
>
> - run_pmc(node, 0, -1, &msg);
> + run_pmc(priv, 0, -1, &msg);
> }
>
> -static int run_pmc_port_properties(struct node *node, int timeout,
> +static int run_pmc_port_properties(struct phc2sys_private *priv, int timeout,
> unsigned int port,
> int *state, int *tstamping, char *iface)
> {
> @@ -1096,9 +1105,9 @@ static int run_pmc_port_properties(struct node *node, int timeout,
> int res, len;
> struct port_properties_np *ppn;
>
> - pmc_target_port(node->pmc, port);
> + pmc_target_port(priv->pmc, port);
> while (1) {
> - res = run_pmc(node, timeout, TLV_PORT_PROPERTIES_NP, &msg);
> + res = run_pmc(priv, timeout, TLV_PORT_PROPERTIES_NP, &msg);
> if (res <= 0)
> goto out;
>
> @@ -1121,35 +1130,35 @@ static int run_pmc_port_properties(struct node *node, int timeout,
> break;
> }
> out:
> - pmc_target_all(node->pmc);
> + pmc_target_all(priv->pmc);
> return res;
> }
>
> -static int run_pmc_clock_identity(struct node *node, int timeout)
> +static int run_pmc_clock_identity(struct phc2sys_private *priv, int timeout)
> {
> struct ptp_message *msg;
> struct defaultDS *dds;
> int res;
>
> - res = run_pmc(node, timeout, TLV_DEFAULT_DATA_SET, &msg);
> + res = run_pmc(priv, timeout, TLV_DEFAULT_DATA_SET, &msg);
> if (res <= 0)
> return res;
>
> dds = (struct defaultDS *)get_mgt_data(msg);
> - memcpy(&node->clock_identity, &dds->clockIdentity,
> + memcpy(&priv->clock_identity, &dds->clockIdentity,
> sizeof(struct ClockIdentity));
> - node->clock_identity_set = 1;
> + priv->clock_identity_set = 1;
> msg_put(msg);
> return 1;
> }
>
> -static void close_pmc(struct node *node)
> +static void close_pmc(struct phc2sys_private *priv)
> {
> - pmc_destroy(node->pmc);
> - node->pmc = NULL;
> + pmc_destroy(priv->pmc);
> + priv->pmc = NULL;
> }
>
> -static int auto_init_ports(struct node *node, int add_rt)
> +static int auto_init_ports(struct phc2sys_private *priv, int add_rt)
> {
> struct port *port;
> struct clock *clock;
> @@ -1161,7 +1170,7 @@ static int auto_init_ports(struct node *node, int add_rt)
> while (1) {
> if (!is_running())
> return -1;
> - res = run_pmc_clock_identity(node, 1000);
> + res = run_pmc_clock_identity(priv, 1000);
> if (res < 0)
> return -1;
> if (res > 0)
> @@ -1170,20 +1179,20 @@ static int auto_init_ports(struct node *node, int add_rt)
> pr_notice("Waiting for ptp4l...");
> }
>
> - number_ports = run_pmc_get_number_ports(node, 1000);
> + number_ports = run_pmc_get_number_ports(priv, 1000);
> if (number_ports <= 0) {
> pr_err("failed to get number of ports");
> return -1;
> }
>
> - res = run_pmc_subscribe(node, 1000);
> + res = run_pmc_subscribe(priv, 1000);
> if (res <= 0) {
> pr_err("failed to subscribe");
> return -1;
> }
>
> for (i = 1; i <= number_ports; i++) {
> - res = run_pmc_port_properties(node, 1000, i, &state,
> + res = run_pmc_port_properties(priv, 1000, i, &state,
> ×tamping, iface);
> if (res == -1) {
> /* port does not exist, ignore the port */
> @@ -1197,22 +1206,22 @@ static int auto_init_ports(struct node *node, int add_rt)
> /* ignore ports with software ...
[truncated message content] |
|
From: Vladimir O. <ol...@gm...> - 2020-08-01 17:46:44
|
Move the code for sending various messages to ptp4l via pmc to a common
translation module, outside of phc2sys. This makes it available to other
programs that want to subscribe to port state change events too, such as
ts2phc.
This creates a smaller structure within phc2sys_private, which embeds
all properties related to the PMC. This structure is called "pmc_node",
which is somewhat reminiscent of the old name of phc2sys_private (struct
node). But the advantage is that struct pmc_node can be reused by other
modules.
Signed-off-by: Vladimir Oltean <ol...@gm...>
---
phc2sys.c | 404 +++++----------------------------------------------
pmc_common.c | 337 ++++++++++++++++++++++++++++++++++++++++++
pmc_common.h | 35 +++++
3 files changed, 407 insertions(+), 369 deletions(-)
diff --git a/phc2sys.c b/phc2sys.c
index a36cbe071d7d..c4d72bd7d17a 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -56,18 +56,13 @@
#include "uds.h"
#include "util.h"
#include "version.h"
+#include "contain.h"
#define KP 0.7
#define KI 0.3
#define NS_PER_SEC 1000000000LL
#define PHC_PPS_OFFSET_LIMIT 10000000
-#define PMC_UPDATE_INTERVAL (60 * NS_PER_SEC)
-#define PMC_SUBSCRIBE_DURATION 180 /* 3 minutes */
-/* Note that PMC_SUBSCRIBE_DURATION has to be longer than
- * PMC_UPDATE_INTERVAL otherwise subscription will time out before it is
- * renewed.
- */
struct clock {
LIST_ENTRY(clock) list;
@@ -105,17 +100,10 @@ struct phc2sys_private {
enum servo_type servo_type;
int phc_readings;
double phc_interval;
- int sync_offset;
int forced_sync_offset;
- int utc_offset_traceable;
- int leap;
int kernel_leap;
- struct pmc *pmc;
- int pmc_ds_requested;
- uint64_t pmc_last_update;
int state_changed;
- int clock_identity_set;
- struct ClockIdentity clock_identity;
+ struct pmc_node node;
LIST_HEAD(port_head, port) ports;
LIST_HEAD(clock_head, clock) clocks;
LIST_HEAD(dst_clock_head, clock) dst_clocks;
@@ -124,18 +112,11 @@ struct phc2sys_private {
static struct config *phc2sys_config;
-static int update_pmc(struct phc2sys_private *priv, int subscribe);
static int clock_handle_leap(struct phc2sys_private *priv,
struct clock *clock,
int64_t offset, uint64_t ts);
-static int run_pmc_get_utc_offset(struct phc2sys_private *priv,
- int timeout);
-static void run_pmc_events(struct phc2sys_private *priv);
static int normalize_state(int state);
-static int run_pmc_port_properties(struct phc2sys_private *priv,
- int timeout, unsigned int port,
- int *state, int *tstamping, char *iface);
static struct servo *servo_add(struct phc2sys_private *priv,
struct clock *clock)
@@ -324,7 +305,7 @@ static void clock_reinit(struct phc2sys_private *priv, struct clock *clock,
LIST_FOREACH(p, &priv->ports, list) {
if (p->clock == clock) {
- ret = run_pmc_port_properties(priv, 1000, p->number,
+ ret = run_pmc_port_properties(&priv->node, 1000, p->number,
&state, ×tamping,
iface);
if (ret > 0)
@@ -659,7 +640,7 @@ static int do_pps_loop(struct phc2sys_private *priv, struct clock *clock,
if (src == CLOCK_INVALID) {
/* The sync offset can't be applied with PPS alone. */
- priv->sync_offset = 0;
+ priv->node.sync_offset = 0;
} else {
enable_pps_output(priv->master->clkid);
}
@@ -690,7 +671,7 @@ static int do_pps_loop(struct phc2sys_private *priv, struct clock *clock,
pps_offset = pps_ts - phc_ts;
}
- if (update_pmc(priv, 0) < 0)
+ if (update_pmc_node(&priv->node, 0) < 0)
continue;
update_clock(priv, clock, pps_offset, pps_ts, -1);
}
@@ -727,15 +708,15 @@ static int do_loop(struct phc2sys_private *priv, int subscriptions)
while (is_running()) {
clock_nanosleep(CLOCK_MONOTONIC, 0, &interval, NULL);
- if (update_pmc(priv, subscriptions) < 0)
+ if (update_pmc_node(&priv->node, subscriptions) < 0)
continue;
if (subscriptions) {
- run_pmc_events(priv);
+ run_pmc_events(&priv->node);
if (priv->state_changed) {
/* force getting offset, as it may have
* changed after the port state change */
- if (run_pmc_get_utc_offset(priv, 1000) <= 0) {
+ if (run_pmc_get_utc_offset(&priv->node, 1000) <= 0) {
pr_err("failed to get UTC offset");
continue;
}
@@ -792,53 +773,6 @@ static int do_loop(struct phc2sys_private *priv, int subscriptions)
return 0;
}
-static int check_clock_identity(struct phc2sys_private *priv,
- struct ptp_message *msg)
-{
- if (!priv->clock_identity_set)
- return 1;
- return cid_eq(&priv->clock_identity,
- &msg->header.sourcePortIdentity.clockIdentity);
-}
-
-static int is_msg_mgt(struct ptp_message *msg)
-{
- struct TLV *tlv;
-
- if (msg_type(msg) != MANAGEMENT)
- return 0;
- if (management_action(msg) != RESPONSE)
- return 0;
- if (msg_tlv_count(msg) != 1)
- return 0;
- tlv = (struct TLV *) msg->management.suffix;
- if (tlv->type == TLV_MANAGEMENT)
- return 1;
- if (tlv->type == TLV_MANAGEMENT_ERROR_STATUS)
- return -1;
- return 0;
-}
-
-static int get_mgt_id(struct ptp_message *msg)
-{
- struct management_tlv *mgt = (struct management_tlv *) msg->management.suffix;
- return mgt->id;
-}
-
-static void *get_mgt_data(struct ptp_message *msg)
-{
- struct management_tlv *mgt = (struct management_tlv *) msg->management.suffix;
- return mgt->data;
-}
-
-static int get_mgt_err_id(struct ptp_message *msg)
-{
- struct management_error_status *mgt;
-
- mgt = (struct management_error_status *)msg->management.suffix;
- return mgt->id;
-}
-
static int normalize_state(int state)
{
if (state != PS_MASTER && state != PS_SLAVE &&
@@ -868,9 +802,13 @@ static int clock_compute_state(struct phc2sys_private *priv,
return state;
}
-static int recv_subscribed(struct phc2sys_private *priv,
- struct ptp_message *msg, int excluded)
+#define node_to_phc2sys(node) \
+ container_of(node, struct phc2sys_private, node)
+
+static int phc2sys_recv_subscribed(struct pmc_node *node,
+ struct ptp_message *msg, int excluded)
{
+ struct phc2sys_private *priv = node_to_phc2sys(node);
int mgt_id, state;
struct portDS *pds;
struct port *port;
@@ -905,259 +843,6 @@ static int recv_subscribed(struct phc2sys_private *priv,
return 0;
}
-static void send_subscription(struct phc2sys_private *priv)
-{
- struct subscribe_events_np sen;
-
- memset(&sen, 0, sizeof(sen));
- sen.duration = PMC_SUBSCRIBE_DURATION;
- sen.bitmask[0] = 1 << NOTIFY_PORT_STATE;
- pmc_send_set_action(priv->pmc, TLV_SUBSCRIBE_EVENTS_NP, &sen, sizeof(sen));
-}
-
-static int init_pmc(struct config *cfg, struct phc2sys_private *priv)
-{
- char uds_local[MAX_IFNAME_SIZE + 1];
-
- snprintf(uds_local, sizeof(uds_local), "/var/run/phc2sys.%d",
- getpid());
- priv->pmc = pmc_create(cfg, TRANS_UDS, uds_local, 0,
- config_get_int(cfg, NULL, "domainNumber"),
- config_get_int(cfg, NULL, "transportSpecific") << 4, 1);
- if (!priv->pmc) {
- pr_err("failed to create pmc");
- return -1;
- }
-
- return 0;
-}
-
-/* Return values:
- * 1: success
- * 0: timeout
- * -1: error reported by the other side
- * -2: local error, fatal
- */
-static int run_pmc(struct phc2sys_private *priv, int timeout, int ds_id,
- struct ptp_message **msg)
-{
-#define N_FD 1
- struct pollfd pollfd[N_FD];
- int cnt, res;
-
- while (1) {
- pollfd[0].fd = pmc_get_transport_fd(priv->pmc);
- pollfd[0].events = POLLIN|POLLPRI;
- if (!priv->pmc_ds_requested && ds_id >= 0)
- pollfd[0].events |= POLLOUT;
-
- cnt = poll(pollfd, N_FD, timeout);
- if (cnt < 0) {
- pr_err("poll failed");
- return -2;
- }
- if (!cnt) {
- /* Request the data set again in the next run. */
- priv->pmc_ds_requested = 0;
- return 0;
- }
-
- /* Send a new request if there are no pending messages. */
- if ((pollfd[0].revents & POLLOUT) &&
- !(pollfd[0].revents & (POLLIN|POLLPRI))) {
- switch (ds_id) {
- case TLV_SUBSCRIBE_EVENTS_NP:
- send_subscription(priv);
- break;
- default:
- pmc_send_get_action(priv->pmc, ds_id);
- break;
- }
- priv->pmc_ds_requested = 1;
- }
-
- if (!(pollfd[0].revents & (POLLIN|POLLPRI)))
- continue;
-
- *msg = pmc_recv(priv->pmc);
-
- if (!*msg)
- continue;
-
- if (!check_clock_identity(priv, *msg)) {
- msg_put(*msg);
- *msg = NULL;
- continue;
- }
-
- res = is_msg_mgt(*msg);
- if (res < 0 && get_mgt_err_id(*msg) == ds_id) {
- priv->pmc_ds_requested = 0;
- return -1;
- }
- if (res <= 0 || recv_subscribed(priv, *msg, ds_id) ||
- get_mgt_id(*msg) != ds_id) {
- msg_put(*msg);
- *msg = NULL;
- continue;
- }
- priv->pmc_ds_requested = 0;
- return 1;
- }
-}
-
-static int run_pmc_wait_sync(struct phc2sys_private *priv, int timeout)
-{
- struct ptp_message *msg;
- int res;
- void *data;
- Enumeration8 portState;
-
- while (1) {
- res = run_pmc(priv, timeout, TLV_PORT_DATA_SET, &msg);
- if (res <= 0)
- return res;
-
- data = get_mgt_data(msg);
- portState = ((struct portDS *)data)->portState;
- msg_put(msg);
-
- switch (portState) {
- case PS_MASTER:
- case PS_SLAVE:
- return 1;
- }
- /* try to get more data sets (for other ports) */
- priv->pmc_ds_requested = 1;
- }
-}
-
-static int run_pmc_get_utc_offset(struct phc2sys_private *priv, int timeout)
-{
- struct ptp_message *msg;
- int res;
- struct timePropertiesDS *tds;
-
- res = run_pmc(priv, timeout, TLV_TIME_PROPERTIES_DATA_SET, &msg);
- if (res <= 0)
- return res;
-
- tds = (struct timePropertiesDS *)get_mgt_data(msg);
- if (tds->flags & PTP_TIMESCALE) {
- priv->sync_offset = tds->currentUtcOffset;
- if (tds->flags & LEAP_61)
- priv->leap = 1;
- else if (tds->flags & LEAP_59)
- priv->leap = -1;
- else
- priv->leap = 0;
- priv->utc_offset_traceable = tds->flags & UTC_OFF_VALID &&
- tds->flags & TIME_TRACEABLE;
- } else {
- priv->sync_offset = 0;
- priv->leap = 0;
- priv->utc_offset_traceable = 0;
- }
- msg_put(msg);
- return 1;
-}
-
-static int run_pmc_get_number_ports(struct phc2sys_private *priv, int timeout)
-{
- struct ptp_message *msg;
- int res;
- struct defaultDS *dds;
-
- res = run_pmc(priv, timeout, TLV_DEFAULT_DATA_SET, &msg);
- if (res <= 0)
- return res;
-
- dds = (struct defaultDS *)get_mgt_data(msg);
- res = dds->numberPorts;
- msg_put(msg);
- return res;
-}
-
-static int run_pmc_subscribe(struct phc2sys_private *priv, int timeout)
-{
- struct ptp_message *msg;
- int res;
-
- res = run_pmc(priv, timeout, TLV_SUBSCRIBE_EVENTS_NP, &msg);
- if (res <= 0)
- return res;
- msg_put(msg);
- return 1;
-}
-
-static void run_pmc_events(struct phc2sys_private *priv)
-{
- struct ptp_message *msg;
-
- run_pmc(priv, 0, -1, &msg);
-}
-
-static int run_pmc_port_properties(struct phc2sys_private *priv, int timeout,
- unsigned int port,
- int *state, int *tstamping, char *iface)
-{
- struct ptp_message *msg;
- int res, len;
- struct port_properties_np *ppn;
-
- pmc_target_port(priv->pmc, port);
- while (1) {
- res = run_pmc(priv, timeout, TLV_PORT_PROPERTIES_NP, &msg);
- if (res <= 0)
- goto out;
-
- ppn = get_mgt_data(msg);
- if (ppn->portIdentity.portNumber != port) {
- msg_put(msg);
- continue;
- }
-
- *state = ppn->port_state;
- *tstamping = ppn->timestamping;
- len = ppn->interface.length;
- if (len > IFNAMSIZ - 1)
- len = IFNAMSIZ - 1;
- memcpy(iface, ppn->interface.text, len);
- iface[len] = '\0';
-
- msg_put(msg);
- res = 1;
- break;
- }
-out:
- pmc_target_all(priv->pmc);
- return res;
-}
-
-static int run_pmc_clock_identity(struct phc2sys_private *priv, int timeout)
-{
- struct ptp_message *msg;
- struct defaultDS *dds;
- int res;
-
- res = run_pmc(priv, timeout, TLV_DEFAULT_DATA_SET, &msg);
- if (res <= 0)
- return res;
-
- dds = (struct defaultDS *)get_mgt_data(msg);
- memcpy(&priv->clock_identity, &dds->clockIdentity,
- sizeof(struct ClockIdentity));
- priv->clock_identity_set = 1;
- msg_put(msg);
- return 1;
-}
-
-static void close_pmc(struct phc2sys_private *priv)
-{
- pmc_destroy(priv->pmc);
- priv->pmc = NULL;
-}
-
static int auto_init_ports(struct phc2sys_private *priv, int add_rt)
{
struct port *port;
@@ -1170,7 +855,7 @@ static int auto_init_ports(struct phc2sys_private *priv, int add_rt)
while (1) {
if (!is_running())
return -1;
- res = run_pmc_clock_identity(priv, 1000);
+ res = run_pmc_clock_identity(&priv->node, 1000);
if (res < 0)
return -1;
if (res > 0)
@@ -1179,20 +864,20 @@ static int auto_init_ports(struct phc2sys_private *priv, int add_rt)
pr_notice("Waiting for ptp4l...");
}
- number_ports = run_pmc_get_number_ports(priv, 1000);
+ number_ports = run_pmc_get_number_ports(&priv->node, 1000);
if (number_ports <= 0) {
pr_err("failed to get number of ports");
return -1;
}
- res = run_pmc_subscribe(priv, 1000);
+ res = run_pmc_subscribe(&priv->node, 1000);
if (res <= 0) {
pr_err("failed to subscribe");
return -1;
}
for (i = 1; i <= number_ports; i++) {
- res = run_pmc_port_properties(priv, 1000, i, &state,
+ res = run_pmc_port_properties(&priv->node, 1000, i, &state,
×tamping, iface);
if (res == -1) {
/* port does not exist, ignore the port */
@@ -1229,44 +914,20 @@ static int auto_init_ports(struct phc2sys_private *priv, int add_rt)
}
/* get initial offset */
- if (run_pmc_get_utc_offset(priv, 1000) <= 0) {
+ if (run_pmc_get_utc_offset(&priv->node, 1000) <= 0) {
pr_err("failed to get UTC offset");
return -1;
}
return 0;
}
-/* Returns: -1 in case of error, 0 otherwise */
-static int update_pmc(struct phc2sys_private *priv, int subscribe)
-{
- struct timespec tp;
- uint64_t ts;
-
- if (clock_gettime(CLOCK_MONOTONIC, &tp)) {
- pr_err("failed to read clock: %m");
- return -1;
- }
- ts = tp.tv_sec * NS_PER_SEC + tp.tv_nsec;
-
- if (priv->pmc &&
- !(ts > priv->pmc_last_update &&
- ts - priv->pmc_last_update < PMC_UPDATE_INTERVAL)) {
- if (subscribe)
- run_pmc_subscribe(priv, 0);
- if (run_pmc_get_utc_offset(priv, 0) > 0)
- priv->pmc_last_update = ts;
- }
-
- return 0;
-}
-
/* Returns: non-zero to skip clock update */
static int clock_handle_leap(struct phc2sys_private *priv, struct clock *clock,
int64_t offset, uint64_t ts)
{
- int clock_leap, node_leap = priv->leap;
+ int clock_leap, node_leap = priv->node.leap;
- clock->sync_offset = priv->sync_offset;
+ clock->sync_offset = priv->node.sync_offset;
if ((node_leap || clock->leap_set) &&
clock->is_utc != priv->master->is_utc) {
@@ -1307,7 +968,7 @@ static int clock_handle_leap(struct phc2sys_private *priv, struct clock *clock,
}
}
- if (priv->utc_offset_traceable &&
+ if (priv->node.utc_offset_traceable &&
clock->utc_offset_set != clock->sync_offset) {
if (clock->clkid == CLOCK_REALTIME)
sysclk_set_tai_offset(clock->sync_offset);
@@ -1361,6 +1022,7 @@ static void usage(char *progname)
int main(int argc, char *argv[])
{
char *config = NULL, *dst_name = NULL, *progname, *src_name = NULL;
+ char uds_local[MAX_IFNAME_SIZE + 1];
struct clock *src, *dst;
struct config *cfg;
struct option *opts;
@@ -1469,7 +1131,7 @@ int main(int argc, char *argv[])
goto end;
break;
case 'O':
- if (get_arg_val_i(c, optarg, &priv.sync_offset,
+ if (get_arg_val_i(c, optarg, &priv.node.sync_offset,
INT_MIN, INT_MAX))
goto end;
priv.forced_sync_offset = -1;
@@ -1589,8 +1251,12 @@ int main(int argc, char *argv[])
priv.kernel_leap = config_get_int(cfg, NULL, "kernel_leap");
priv.sanity_freq_limit = config_get_int(cfg, NULL, "sanity_freq_limit");
+ snprintf(uds_local, sizeof(uds_local), "/var/run/phc2sys.%d",
+ getpid());
+
if (autocfg) {
- if (init_pmc(cfg, &priv))
+ if (init_pmc_node(cfg, &priv.node, uds_local,
+ phc2sys_recv_subscribed))
goto end;
if (auto_init_ports(&priv, rt) < 0)
goto end;
@@ -1627,11 +1293,12 @@ int main(int argc, char *argv[])
r = -1;
if (wait_sync) {
- if (init_pmc(cfg, &priv))
+ if (init_pmc_node(cfg, &priv.node, uds_local,
+ phc2sys_recv_subscribed))
goto end;
while (is_running()) {
- r = run_pmc_wait_sync(&priv, 1000);
+ r = run_pmc_wait_sync(&priv.node, 1000);
if (r < 0)
goto end;
if (r > 0)
@@ -1641,7 +1308,7 @@ int main(int argc, char *argv[])
}
if (!priv.forced_sync_offset) {
- r = run_pmc_get_utc_offset(&priv, 1000);
+ r = run_pmc_get_utc_offset(&priv.node, 1000);
if (r <= 0) {
pr_err("failed to get UTC offset");
goto end;
@@ -1651,7 +1318,7 @@ int main(int argc, char *argv[])
if (priv.forced_sync_offset ||
(src->clkid != CLOCK_REALTIME && dst->clkid != CLOCK_REALTIME) ||
src->clkid == CLOCK_INVALID)
- close_pmc(&priv);
+ close_pmc_node(&priv.node);
}
if (pps_fd >= 0) {
@@ -1664,8 +1331,7 @@ int main(int argc, char *argv[])
}
end:
- if (priv.pmc)
- close_pmc(&priv);
+ close_pmc_node(&priv.node);
clock_cleanup(&priv);
port_cleanup(&priv);
config_destroy(cfg);
diff --git a/pmc_common.c b/pmc_common.c
index f07f6f65568f..89d7f40b84fe 100644
--- a/pmc_common.c
+++ b/pmc_common.c
@@ -22,6 +22,8 @@
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
+#include <net/if.h>
+#include <poll.h>
#include "notification.h"
#include "print.h"
@@ -56,6 +58,13 @@
/* Includes one extra byte to make length even. */
#define EMPTY_PTP_TEXT 2
+#define PMC_UPDATE_INTERVAL (60 * NS_PER_SEC)
+#define PMC_SUBSCRIBE_DURATION 180 /* 3 minutes */
+/* Note that PMC_SUBSCRIBE_DURATION has to be longer than
+ * PMC_UPDATE_INTERVAL otherwise subscription will time out before it is
+ * renewed.
+ */
+
static void do_get_action(struct pmc *pmc, int action, int index, char *str);
static void do_set_action(struct pmc *pmc, int action, int index, char *str);
static void not_supported(struct pmc *pmc, int action, int index, char *str);
@@ -711,3 +720,331 @@ int pmc_do_command(struct pmc *pmc, char *str)
return 0;
}
+
+static void send_subscription(struct pmc_node *node)
+{
+ struct subscribe_events_np sen;
+
+ memset(&sen, 0, sizeof(sen));
+ sen.duration = PMC_SUBSCRIBE_DURATION;
+ sen.bitmask[0] = 1 << NOTIFY_PORT_STATE;
+ pmc_send_set_action(node->pmc, TLV_SUBSCRIBE_EVENTS_NP, &sen, sizeof(sen));
+}
+
+static int check_clock_identity(struct pmc_node *node, struct ptp_message *msg)
+{
+ if (!node->clock_identity_set)
+ return 1;
+ return cid_eq(&node->clock_identity,
+ &msg->header.sourcePortIdentity.clockIdentity);
+}
+
+static int is_msg_mgt(struct ptp_message *msg)
+{
+ struct TLV *tlv;
+
+ if (msg_type(msg) != MANAGEMENT)
+ return 0;
+ if (management_action(msg) != RESPONSE)
+ return 0;
+ if (msg_tlv_count(msg) != 1)
+ return 0;
+ tlv = (struct TLV *) msg->management.suffix;
+ if (tlv->type == TLV_MANAGEMENT)
+ return 1;
+ if (tlv->type == TLV_MANAGEMENT_ERROR_STATUS)
+ return -1;
+ return 0;
+}
+
+int get_mgt_id(struct ptp_message *msg)
+{
+ struct management_tlv *mgt;
+
+ mgt = (struct management_tlv *) msg->management.suffix;
+ return mgt->id;
+}
+
+void *get_mgt_data(struct ptp_message *msg)
+{
+ struct management_tlv *mgt;
+
+ mgt = (struct management_tlv *) msg->management.suffix;
+ return mgt->data;
+}
+
+static int get_mgt_err_id(struct ptp_message *msg)
+{
+ struct management_error_status *mgt;
+
+ mgt = (struct management_error_status *)msg->management.suffix;
+ return mgt->id;
+}
+
+/* Return values:
+ * 1: success
+ * 0: timeout
+ * -1: error reported by the other side
+ * -2: local error, fatal
+ */
+static int run_pmc(struct pmc_node *node, int timeout, int ds_id,
+ struct ptp_message **msg)
+{
+#define N_FD 1
+ struct pollfd pollfd[N_FD];
+ int cnt, res;
+
+ while (1) {
+ pollfd[0].fd = pmc_get_transport_fd(node->pmc);
+ pollfd[0].events = POLLIN|POLLPRI;
+ if (!node->pmc_ds_requested && ds_id >= 0)
+ pollfd[0].events |= POLLOUT;
+
+ cnt = poll(pollfd, N_FD, timeout);
+ if (cnt < 0) {
+ pr_err("poll failed");
+ return -2;
+ }
+ if (!cnt) {
+ /* Request the data set again in the next run. */
+ node->pmc_ds_requested = 0;
+ return 0;
+ }
+
+ /* Send a new request if there are no pending messages. */
+ if ((pollfd[0].revents & POLLOUT) &&
+ !(pollfd[0].revents & (POLLIN|POLLPRI))) {
+ switch (ds_id) {
+ case TLV_SUBSCRIBE_EVENTS_NP:
+ send_subscription(node);
+ break;
+ default:
+ pmc_send_get_action(node->pmc, ds_id);
+ break;
+ }
+ node->pmc_ds_requested = 1;
+ }
+
+ if (!(pollfd[0].revents & (POLLIN|POLLPRI)))
+ continue;
+
+ *msg = pmc_recv(node->pmc);
+
+ if (!*msg)
+ continue;
+
+ if (!check_clock_identity(node, *msg)) {
+ msg_put(*msg);
+ *msg = NULL;
+ continue;
+ }
+
+ res = is_msg_mgt(*msg);
+ if (res < 0 && get_mgt_err_id(*msg) == ds_id) {
+ node->pmc_ds_requested = 0;
+ return -1;
+ }
+ if (res <= 0 || node->recv_subscribed(node, *msg, ds_id) ||
+ get_mgt_id(*msg) != ds_id) {
+ msg_put(*msg);
+ *msg = NULL;
+ continue;
+ }
+ node->pmc_ds_requested = 0;
+ return 1;
+ }
+}
+
+int run_pmc_wait_sync(struct pmc_node *node, int timeout)
+{
+ struct ptp_message *msg;
+ Enumeration8 portState;
+ void *data;
+ int res;
+
+ while (1) {
+ res = run_pmc(node, timeout, TLV_PORT_DATA_SET, &msg);
+ if (res <= 0)
+ return res;
+
+ data = get_mgt_data(msg);
+ portState = ((struct portDS *)data)->portState;
+ msg_put(msg);
+
+ switch (portState) {
+ case PS_MASTER:
+ case PS_SLAVE:
+ return 1;
+ }
+ /* try to get more data sets (for other ports) */
+ node->pmc_ds_requested = 1;
+ }
+}
+
+int run_pmc_get_utc_offset(struct pmc_node *node, int timeout)
+{
+ struct ptp_message *msg;
+ int res;
+ struct timePropertiesDS *tds;
+
+ res = run_pmc(node, timeout, TLV_TIME_PROPERTIES_DATA_SET, &msg);
+ if (res <= 0)
+ return res;
+
+ tds = (struct timePropertiesDS *)get_mgt_data(msg);
+ if (tds->flags & PTP_TIMESCALE) {
+ node->sync_offset = tds->currentUtcOffset;
+ if (tds->flags & LEAP_61)
+ node->leap = 1;
+ else if (tds->flags & LEAP_59)
+ node->leap = -1;
+ else
+ node->leap = 0;
+ node->utc_offset_traceable = tds->flags & UTC_OFF_VALID &&
+ tds->flags & TIME_TRACEABLE;
+ } else {
+ node->sync_offset = 0;
+ node->leap = 0;
+ node->utc_offset_traceable = 0;
+ }
+ msg_put(msg);
+ return 1;
+}
+
+int run_pmc_get_number_ports(struct pmc_node *node, int timeout)
+{
+ struct ptp_message *msg;
+ int res;
+ struct defaultDS *dds;
+
+ res = run_pmc(node, timeout, TLV_DEFAULT_DATA_SET, &msg);
+ if (res <= 0)
+ return res;
+
+ dds = (struct defaultDS *)get_mgt_data(msg);
+ res = dds->numberPorts;
+ msg_put(msg);
+ return res;
+}
+
+int run_pmc_subscribe(struct pmc_node *node, int timeout)
+{
+ struct ptp_message *msg;
+ int res;
+
+ res = run_pmc(node, timeout, TLV_SUBSCRIBE_EVENTS_NP, &msg);
+ if (res <= 0)
+ return res;
+ msg_put(msg);
+ return 1;
+}
+
+void run_pmc_events(struct pmc_node *node)
+{
+ struct ptp_message *msg;
+
+ run_pmc(node, 0, -1, &msg);
+}
+
+int run_pmc_port_properties(struct pmc_node *node, int timeout,
+ unsigned int port, int *state,
+ int *tstamping, char *iface)
+{
+ struct ptp_message *msg;
+ int res, len;
+ struct port_properties_np *ppn;
+
+ pmc_target_port(node->pmc, port);
+ while (1) {
+ res = run_pmc(node, timeout, TLV_PORT_PROPERTIES_NP, &msg);
+ if (res <= 0)
+ goto out;
+
+ ppn = get_mgt_data(msg);
+ if (ppn->portIdentity.portNumber != port) {
+ msg_put(msg);
+ continue;
+ }
+
+ *state = ppn->port_state;
+ *tstamping = ppn->timestamping;
+ len = ppn->interface.length;
+ if (len > IFNAMSIZ - 1)
+ len = IFNAMSIZ - 1;
+ memcpy(iface, ppn->interface.text, len);
+ iface[len] = '\0';
+
+ msg_put(msg);
+ res = 1;
+ break;
+ }
+out:
+ pmc_target_all(node->pmc);
+ return res;
+}
+
+int run_pmc_clock_identity(struct pmc_node *node, int timeout)
+{
+ struct ptp_message *msg;
+ struct defaultDS *dds;
+ int res;
+
+ res = run_pmc(node, timeout, TLV_DEFAULT_DATA_SET, &msg);
+ if (res <= 0)
+ return res;
+
+ dds = (struct defaultDS *)get_mgt_data(msg);
+ memcpy(&node->clock_identity, &dds->clockIdentity,
+ sizeof(struct ClockIdentity));
+ node->clock_identity_set = 1;
+ msg_put(msg);
+ return 1;
+}
+
+/* Returns: -1 in case of error, 0 otherwise */
+int update_pmc_node(struct pmc_node *node, int subscribe)
+{
+ struct timespec tp;
+ uint64_t ts;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &tp)) {
+ pr_err("failed to read clock: %m");
+ return -1;
+ }
+ ts = tp.tv_sec * NS_PER_SEC + tp.tv_nsec;
+
+ if (node->pmc &&
+ !(ts > node->pmc_last_update &&
+ ts - node->pmc_last_update < PMC_UPDATE_INTERVAL)) {
+ if (subscribe)
+ run_pmc_subscribe(node, 0);
+ if (run_pmc_get_utc_offset(node, 0) > 0)
+ node->pmc_last_update = ts;
+ }
+
+ return 0;
+}
+
+int init_pmc_node(struct config *cfg, struct pmc_node *node, const char *uds,
+ pmc_node_recv_subscribed_t *recv_subscribed)
+{
+ node->pmc = pmc_create(cfg, TRANS_UDS, uds, 0,
+ config_get_int(cfg, NULL, "domainNumber"),
+ config_get_int(cfg, NULL, "transportSpecific") << 4, 1);
+ if (!node->pmc) {
+ pr_err("failed to create pmc");
+ return -1;
+ }
+ node->recv_subscribed = recv_subscribed;
+
+ return 0;
+}
+
+void close_pmc_node(struct pmc_node *node)
+{
+ if (!node->pmc)
+ return;
+
+ pmc_destroy(node->pmc);
+ node->pmc = NULL;
+}
diff --git a/pmc_common.h b/pmc_common.h
index 9fa72deb4c87..a28bab767e9c 100644
--- a/pmc_common.h
+++ b/pmc_common.h
@@ -24,6 +24,7 @@
#include "config.h"
#include "msg.h"
#include "transport.h"
+#include "fsm.h"
struct pmc;
@@ -49,4 +50,38 @@ void pmc_target_all(struct pmc *pmc);
const char *pmc_action_string(int action);
int pmc_do_command(struct pmc *pmc, char *str);
+struct pmc_node;
+
+typedef int pmc_node_recv_subscribed_t(struct pmc_node *node,
+ struct ptp_message *msg,
+ int excluded);
+
+struct pmc_node {
+ struct pmc *pmc;
+ int pmc_ds_requested;
+ uint64_t pmc_last_update;
+ int sync_offset;
+ int leap;
+ int utc_offset_traceable;
+ int clock_identity_set;
+ struct ClockIdentity clock_identity;
+ pmc_node_recv_subscribed_t *recv_subscribed;
+};
+
+int init_pmc_node(struct config *cfg, struct pmc_node *node, const char *uds,
+ pmc_node_recv_subscribed_t *recv_subscribed);
+void close_pmc_node(struct pmc_node *node);
+int update_pmc_node(struct pmc_node *node, int subscribe);
+int run_pmc_subscribe(struct pmc_node *node, int timeout);
+int run_pmc_clock_identity(struct pmc_node *node, int timeout);
+int run_pmc_wait_sync(struct pmc_node *node, int timeout);
+int run_pmc_get_number_ports(struct pmc_node *node, int timeout);
+void run_pmc_events(struct pmc_node *node);
+int run_pmc_port_properties(struct pmc_node *node, int timeout,
+ unsigned int port, int *state,
+ int *tstamping, char *iface);
+int run_pmc_get_utc_offset(struct pmc_node *node, int timeout);
+int get_mgt_id(struct ptp_message *msg);
+void *get_mgt_data(struct ptp_message *msg);
+
#endif
--
2.25.1
|
|
From: Jacob K. <jac...@in...> - 2020-08-05 23:19:23
|
On 8/1/2020 10:46 AM, Vladimir Oltean wrote:
> Move the code for sending various messages to ptp4l via pmc to a common
> translation module, outside of phc2sys. This makes it available to other
> programs that want to subscribe to port state change events too, such as
> ts2phc.
>
> This creates a smaller structure within phc2sys_private, which embeds
> all properties related to the PMC. This structure is called "pmc_node",
> which is somewhat reminiscent of the old name of phc2sys_private (struct
> node). But the advantage is that struct pmc_node can be reused by other
> modules.
Ah, perfect: pmc_node is not too generic, so this is great.
I looked this over using git diff with the moved lines coloring options,
and the only places where the new code differs is in name change from
priv to pmc_node.
Makes sense.
Reviewed-by: Jacob Keller <jac...@in...>
>
> Signed-off-by: Vladimir Oltean <ol...@gm...>
> ---
> phc2sys.c | 404 +++++----------------------------------------------
> pmc_common.c | 337 ++++++++++++++++++++++++++++++++++++++++++
> pmc_common.h | 35 +++++
> 3 files changed, 407 insertions(+), 369 deletions(-)
>
> diff --git a/phc2sys.c b/phc2sys.c
> index a36cbe071d7d..c4d72bd7d17a 100644
> --- a/phc2sys.c
> +++ b/phc2sys.c
> @@ -56,18 +56,13 @@
> #include "uds.h"
> #include "util.h"
> #include "version.h"
> +#include "contain.h"
>
> #define KP 0.7
> #define KI 0.3
> #define NS_PER_SEC 1000000000LL
>
> #define PHC_PPS_OFFSET_LIMIT 10000000
> -#define PMC_UPDATE_INTERVAL (60 * NS_PER_SEC)
> -#define PMC_SUBSCRIBE_DURATION 180 /* 3 minutes */
> -/* Note that PMC_SUBSCRIBE_DURATION has to be longer than
> - * PMC_UPDATE_INTERVAL otherwise subscription will time out before it is
> - * renewed.
> - */
>
> struct clock {
> LIST_ENTRY(clock) list;
> @@ -105,17 +100,10 @@ struct phc2sys_private {
> enum servo_type servo_type;
> int phc_readings;
> double phc_interval;
> - int sync_offset;
> int forced_sync_offset;
> - int utc_offset_traceable;
> - int leap;
> int kernel_leap;
> - struct pmc *pmc;
> - int pmc_ds_requested;
> - uint64_t pmc_last_update;
> int state_changed;
> - int clock_identity_set;
> - struct ClockIdentity clock_identity;
> + struct pmc_node node;
> LIST_HEAD(port_head, port) ports;
> LIST_HEAD(clock_head, clock) clocks;
> LIST_HEAD(dst_clock_head, clock) dst_clocks;
> @@ -124,18 +112,11 @@ struct phc2sys_private {
>
> static struct config *phc2sys_config;
>
> -static int update_pmc(struct phc2sys_private *priv, int subscribe);
> static int clock_handle_leap(struct phc2sys_private *priv,
> struct clock *clock,
> int64_t offset, uint64_t ts);
> -static int run_pmc_get_utc_offset(struct phc2sys_private *priv,
> - int timeout);
> -static void run_pmc_events(struct phc2sys_private *priv);
>
> static int normalize_state(int state);
> -static int run_pmc_port_properties(struct phc2sys_private *priv,
> - int timeout, unsigned int port,
> - int *state, int *tstamping, char *iface);
>
> static struct servo *servo_add(struct phc2sys_private *priv,
> struct clock *clock)
> @@ -324,7 +305,7 @@ static void clock_reinit(struct phc2sys_private *priv, struct clock *clock,
>
> LIST_FOREACH(p, &priv->ports, list) {
> if (p->clock == clock) {
> - ret = run_pmc_port_properties(priv, 1000, p->number,
> + ret = run_pmc_port_properties(&priv->node, 1000, p->number,
> &state, ×tamping,
> iface);
> if (ret > 0)
> @@ -659,7 +640,7 @@ static int do_pps_loop(struct phc2sys_private *priv, struct clock *clock,
>
> if (src == CLOCK_INVALID) {
> /* The sync offset can't be applied with PPS alone. */
> - priv->sync_offset = 0;
> + priv->node.sync_offset = 0;
> } else {
> enable_pps_output(priv->master->clkid);
> }
> @@ -690,7 +671,7 @@ static int do_pps_loop(struct phc2sys_private *priv, struct clock *clock,
> pps_offset = pps_ts - phc_ts;
> }
>
> - if (update_pmc(priv, 0) < 0)
> + if (update_pmc_node(&priv->node, 0) < 0)
> continue;
> update_clock(priv, clock, pps_offset, pps_ts, -1);
> }
> @@ -727,15 +708,15 @@ static int do_loop(struct phc2sys_private *priv, int subscriptions)
>
> while (is_running()) {
> clock_nanosleep(CLOCK_MONOTONIC, 0, &interval, NULL);
> - if (update_pmc(priv, subscriptions) < 0)
> + if (update_pmc_node(&priv->node, subscriptions) < 0)
> continue;
>
> if (subscriptions) {
> - run_pmc_events(priv);
> + run_pmc_events(&priv->node);
> if (priv->state_changed) {
> /* force getting offset, as it may have
> * changed after the port state change */
> - if (run_pmc_get_utc_offset(priv, 1000) <= 0) {
> + if (run_pmc_get_utc_offset(&priv->node, 1000) <= 0) {
> pr_err("failed to get UTC offset");
> continue;
> }
> @@ -792,53 +773,6 @@ static int do_loop(struct phc2sys_private *priv, int subscriptions)
> return 0;
> }
>
> -static int check_clock_identity(struct phc2sys_private *priv,
> - struct ptp_message *msg)
> -{
> - if (!priv->clock_identity_set)
> - return 1;
> - return cid_eq(&priv->clock_identity,
> - &msg->header.sourcePortIdentity.clockIdentity);
> -}
> -
> -static int is_msg_mgt(struct ptp_message *msg)
> -{
> - struct TLV *tlv;
> -
> - if (msg_type(msg) != MANAGEMENT)
> - return 0;
> - if (management_action(msg) != RESPONSE)
> - return 0;
> - if (msg_tlv_count(msg) != 1)
> - return 0;
> - tlv = (struct TLV *) msg->management.suffix;
> - if (tlv->type == TLV_MANAGEMENT)
> - return 1;
> - if (tlv->type == TLV_MANAGEMENT_ERROR_STATUS)
> - return -1;
> - return 0;
> -}
> -
> -static int get_mgt_id(struct ptp_message *msg)
> -{
> - struct management_tlv *mgt = (struct management_tlv *) msg->management.suffix;
> - return mgt->id;
> -}
> -
> -static void *get_mgt_data(struct ptp_message *msg)
> -{
> - struct management_tlv *mgt = (struct management_tlv *) msg->management.suffix;
> - return mgt->data;
> -}
> -
> -static int get_mgt_err_id(struct ptp_message *msg)
> -{
> - struct management_error_status *mgt;
> -
> - mgt = (struct management_error_status *)msg->management.suffix;
> - return mgt->id;
> -}
> -
> static int normalize_state(int state)
> {
> if (state != PS_MASTER && state != PS_SLAVE &&
> @@ -868,9 +802,13 @@ static int clock_compute_state(struct phc2sys_private *priv,
> return state;
> }
>
> -static int recv_subscribed(struct phc2sys_private *priv,
> - struct ptp_message *msg, int excluded)
> +#define node_to_phc2sys(node) \
> + container_of(node, struct phc2sys_private, node)
> +
> +static int phc2sys_recv_subscribed(struct pmc_node *node,
> + struct ptp_message *msg, int excluded)
> {
> + struct phc2sys_private *priv = node_to_phc2sys(node);
> int mgt_id, state;
> struct portDS *pds;
> struct port *port;
> @@ -905,259 +843,6 @@ static int recv_subscribed(struct phc2sys_private *priv,
> return 0;
> }
>
> -static void send_subscription(struct phc2sys_private *priv)
> -{
> - struct subscribe_events_np sen;
> -
> - memset(&sen, 0, sizeof(sen));
> - sen.duration = PMC_SUBSCRIBE_DURATION;
> - sen.bitmask[0] = 1 << NOTIFY_PORT_STATE;
> - pmc_send_set_action(priv->pmc, TLV_SUBSCRIBE_EVENTS_NP, &sen, sizeof(sen));
> -}
> -
> -static int init_pmc(struct config *cfg, struct phc2sys_private *priv)
> -{
> - char uds_local[MAX_IFNAME_SIZE + 1];
> -
> - snprintf(uds_local, sizeof(uds_local), "/var/run/phc2sys.%d",
> - getpid());
> - priv->pmc = pmc_create(cfg, TRANS_UDS, uds_local, 0,
> - config_get_int(cfg, NULL, "domainNumber"),
> - config_get_int(cfg, NULL, "transportSpecific") << 4, 1);
> - if (!priv->pmc) {
> - pr_err("failed to create pmc");
> - return -1;
> - }
> -
> - return 0;
> -}
> -
> -/* Return values:
> - * 1: success
> - * 0: timeout
> - * -1: error reported by the other side
> - * -2: local error, fatal
> - */
> -static int run_pmc(struct phc2sys_private *priv, int timeout, int ds_id,
> - struct ptp_message **msg)
> -{
> -#define N_FD 1
> - struct pollfd pollfd[N_FD];
> - int cnt, res;
> -
> - while (1) {
> - pollfd[0].fd = pmc_get_transport_fd(priv->pmc);
> - pollfd[0].events = POLLIN|POLLPRI;
> - if (!priv->pmc_ds_requested && ds_id >= 0)
> - pollfd[0].events |= POLLOUT;
> -
> - cnt = poll(pollfd, N_FD, timeout);
> - if (cnt < 0) {
> - pr_err("poll failed");
> - return -2;
> - }
> - if (!cnt) {
> - /* Request the data set again in the next run. */
> - priv->pmc_ds_requested = 0;
> - return 0;
> - }
> -
> - /* Send a new request if there are no pending messages. */
> - if ((pollfd[0].revents & POLLOUT) &&
> - !(pollfd[0].revents & (POLLIN|POLLPRI))) {
> - switch (ds_id) {
> - case TLV_SUBSCRIBE_EVENTS_NP:
> - send_subscription(priv);
> - break;
> - default:
> - pmc_send_get_action(priv->pmc, ds_id);
> - break;
> - }
> - priv->pmc_ds_requested = 1;
> - }
> -
> - if (!(pollfd[0].revents & (POLLIN|POLLPRI)))
> - continue;
> -
> - *msg = pmc_recv(priv->pmc);
> -
> - if (!*msg)
> - continue;
> -
> - if (!check_clock_identity(priv, *msg)) {
> - msg_put(*msg);
> - *msg = NULL;
> - continue;
> - }
> -
> - res = is_msg_mgt(*msg);
> - if (res < 0 && get_mgt_err_id(*msg) == ds_id) {
> - priv->pmc_ds_requested = 0;
> - return -1;
> - }
> - if (res <= 0 || recv_subscribed(priv, *msg, ds_id) ||
> - get_mgt_id(*msg) != ds_id) {
> - msg_put(*msg);
> - *msg = NULL;
> - continue;
> - }
> - priv->pmc_ds_requested = 0;
> - return 1;
> - }
> -}
> -
> -static int run_pmc_wait_sync(struct phc2sys_private *priv, int timeout)
> -{
> - struct ptp_message *msg;
> - int res;
> - void *data;
> - Enumeration8 portState;
> -
> - while (1) {
> - res = run_pmc(priv, timeout, TLV_PORT_DATA_SET, &msg);
> - if (res <= 0)
> - return res;
> -
> - data = get_mgt_data(msg);
> - portState = ((struct portDS *)data)->portState;
> - msg_put(msg);
> -
> - switch (portState) {
> - case PS_MASTER:
> - case PS_SLAVE:
> - return 1;
> - }
> - /* try to get more data sets (for other ports) */
> - priv->pmc_ds_requested = 1;
> - }
> -}
> -
> -static int run_pmc_get_utc_offset(struct phc2sys_private *priv, int timeout)
> -{
> - struct ptp_message *msg;
> - int res;
> - struct timePropertiesDS *tds;
> -
> - res = run_pmc(priv, timeout, TLV_TIME_PROPERTIES_DATA_SET, &msg);
> - if (res <= 0)
> - return res;
> -
> - tds = (struct timePropertiesDS *)get_mgt_data(msg);
> - if (tds->flags & PTP_TIMESCALE) {
> - priv->sync_offset = tds->currentUtcOffset;
> - if (tds->flags & LEAP_61)
> - priv->leap = 1;
> - else if (tds->flags & LEAP_59)
> - priv->leap = -1;
> - else
> - priv->leap = 0;
> - priv->utc_offset_traceable = tds->flags & UTC_OFF_VALID &&
> - tds->flags & TIME_TRACEABLE;
> - } else {
> - priv->sync_offset = 0;
> - priv->leap = 0;
> - priv->utc_offset_traceable = 0;
> - }
> - msg_put(msg);
> - return 1;
> -}
> -
> -static int run_pmc_get_number_ports(struct phc2sys_private *priv, int timeout)
> -{
> - struct ptp_message *msg;
> - int res;
> - struct defaultDS *dds;
> -
> - res = run_pmc(priv, timeout, TLV_DEFAULT_DATA_SET, &msg);
> - if (res <= 0)
> - return res;
> -
> - dds = (struct defaultDS *)get_mgt_data(msg);
> - res = dds->numberPorts;
> - msg_put(msg);
> - return res;
> -}
> -
> -static int run_pmc_subscribe(struct phc2sys_private *priv, int timeout)
> -{
> - struct ptp_message *msg;
> - int res;
> -
> - res = run_pmc(priv, timeout, TLV_SUBSCRIBE_EVENTS_NP, &msg);
> - if (res <= 0)
> - return res;
> - msg_put(msg);
> - return 1;
> -}
> -
> -static void run_pmc_events(struct phc2sys_private *priv)
> -{
> - struct ptp_message *msg;
> -
> - run_pmc(priv, 0, -1, &msg);
> -}
> -
> -static int run_pmc_port_properties(struct phc2sys_private *priv, int timeout,
> - unsigned int port,
> - int *state, int *tstamping, char *iface)
> -{
> - struct ptp_message *msg;
> - int res, len;
> - struct port_properties_np *ppn;
> -
> - pmc_target_port(priv->pmc, port);
> - while (1) {
> - res = run_pmc(priv, timeout, TLV_PORT_PROPERTIES_NP, &msg);
> - if (res <= 0)
> - goto out;
> -
> - ppn = get_mgt_data(msg);
> - if (ppn->portIdentity.portNumber != port) {
> - msg_put(msg);
> - continue;
> - }
> -
> - *state = ppn->port_state;
> - *tstamping = ppn->timestamping;
> - len = ppn->interface.length;
> - if (len > IFNAMSIZ - 1)
> - len = IFNAMSIZ - 1;
> - memcpy(iface, ppn->interface.text, len);
> - iface[len] = '\0';
> -
> - msg_put(msg);
> - res = 1;
> - break;
> - }
> -out:
> - pmc_target_all(priv->pmc);
> - return res;
> -}
> -
> -static int run_pmc_clock_identity(struct phc2sys_private *priv, int timeout)
> -{
> - struct ptp_message *msg;
> - struct defaultDS *dds;
> - int res;
> -
> - res = run_pmc(priv, timeout, TLV_DEFAULT_DATA_SET, &msg);
> - if (res <= 0)
> - return res;
> -
> - dds = (struct defaultDS *)get_mgt_data(msg);
> - memcpy(&priv->clock_identity, &dds->clockIdentity,
> - sizeof(struct ClockIdentity));
> - priv->clock_identity_set = 1;
> - msg_put(msg);
> - return 1;
> -}
> -
> -static void close_pmc(struct phc2sys_private *priv)
> -{
> - pmc_destroy(priv->pmc);
> - priv->pmc = NULL;
> -}
> -
> static int auto_init_ports(struct phc2sys_private *priv, int add_rt)
> {
> struct port *port;
> @@ -1170,7 +855,7 @@ static int auto_init_ports(struct phc2sys_private *priv, int add_rt)
> while (1) {
> if (!is_running())
> return -1;
> - res = run_pmc_clock_identity(priv, 1000);
> + res = run_pmc_clock_identity(&priv->node, 1000);
> if (res < 0)
> return -1;
> if (res > 0)
> @@ -1179,20 +864,20 @@ static int auto_init_ports(struct phc2sys_private *priv, int add_rt)
> pr_notice("Waiting for ptp4l...");
> }
>
> - number_ports = run_pmc_get_number_ports(priv, 1000);
> + number_ports = run_pmc_get_number_ports(&priv->node, 1000);
> if (number_ports <= 0) {
> pr_err("failed to get number of ports");
> return -1;
> }
>
> - res = run_pmc_subscribe(priv, 1000);
> + res = run_pmc_subscribe(&priv->node, 1000);
> if (res <= 0) {
> pr_err("failed to subscribe");
> return -1;
> }
>
> for (i = 1; i <= number_ports; i++) {
> - res = run_pmc_port_properties(priv, 1000, i, &state,
> + res = run_pmc_port_properties(&priv->node, 1000, i, &state,
> ×tamping, iface);
> if (res == -1) {
> /* port does not exist, ignore the port */
> @@ -1229,44 +914,20 @@ static int auto_init_ports(struct phc2sys_private *priv, int add_rt)
> }
>
> /* get initial offset */
> - if (run_pmc_get_utc_offset(priv, 1000) <= 0) {
> + if (run_pmc_get_utc_offset(&priv->node, 1000) <= 0) {
> pr_err("failed to get UTC offset");
> return -1;
> }
> return 0;
> }
>
> -/* Returns: -1 in case of error, 0 otherwise */
> -static int update_pmc(struct phc2sys_private *priv, int subscribe)
> -{
> - struct timespec tp;
> - uint64_t ts;
> -
> - if (clock_gettime(CLOCK_MONOTONIC, &tp)) {
> - pr_err("failed to read clock: %m");
> - return -1;
> - }
> - ts = tp.tv_sec * NS_PER_SEC + tp.tv_nsec;
> -
> - if (priv->pmc &&
> - !(ts > priv->pmc_last_update &&
> - ts - priv->pmc_last_update < PMC_UPDATE_INTERVAL)) {
> - if (subscribe)
> - run_pmc_subscribe(priv, 0);
> - if (run_pmc_get_utc_offset(priv, 0) > 0)
> - priv->pmc_last_update = ts;
> - }
> -
> - return 0;
> -}
> -
> /* Returns: non-zero to skip clock update */
> static int clock_handle_leap(struct phc2sys_private *priv, struct clock *clock,
> int64_t offset, uint64_t ts)
> {
> - int clock_leap, node_leap = priv->leap;
> + int clock_leap, node_leap = priv->node.leap;
>
> - clock->sync_offset = priv->sync_offset;
> + clock->sync_offset = priv->node.sync_offset;
>
> if ((node_leap || clock->leap_set) &&
> clock->is_utc != priv->master->is_utc) {
> @@ -1307,7 +968,7 @@ static int clock_handle_leap(struct phc2sys_private *priv, struct clock *clock,
> }
> }
>
> - if (priv->utc_offset_traceable &&
> + if (priv->node.utc_offset_traceable &&
> clock->utc_offset_set != clock->sync_offset) {
> if (clock->clkid == CLOCK_REALTIME)
> sysclk_set_tai_offset(clock->sync_offset);
> @@ -1361,6 +1022,7 @@ static void usage(char *progname)
> int main(int argc, char *argv[])
> {
> char *config = NULL, *dst_name = NULL, *progname, *src_name = NULL;
> + char uds_local[MAX_IFNAME_SIZE + 1];
> struct clock *src, *dst;
> struct config *cfg;
> struct option *opts;
> @@ -1469,7 +1131,7 @@ int main(int argc, char *argv[])
> goto end;
> break;
> case 'O':
> - if (get_arg_val_i(c, optarg, &priv.sync_offset,
> + if (get_arg_val_i(c, optarg, &priv.node.sync_offset,
> INT_MIN, INT_MAX))
> goto end;
> priv.forced_sync_offset = -1;
> @@ -1589,8 +1251,12 @@ int main(int argc, char *argv[])
> priv.kernel_leap = config_get_int(cfg, NULL, "kernel_leap");
> priv.sanity_freq_limit = config_get_int(cfg, NULL, "sanity_freq_limit");
>
> + snprintf(uds_local, sizeof(uds_local), "/var/run/phc2sys.%d",
> + getpid());
> +
> if (autocfg) {
> - if (init_pmc(cfg, &priv))
> + if (init_pmc_node(cfg, &priv.node, uds_local,
> + phc2sys_recv_subscribed))
> goto end;
> if (auto_init_ports(&priv, rt) < 0)
> goto end;
> @@ -1627,11 +1293,12 @@ int main(int argc, char *argv[])
> r = -1;
>
> if (wait_sync) {
> - if (init_pmc(cfg, &priv))
> + if (init_pmc_node(cfg, &priv.node, uds_local,
> + phc2sys_recv_subscribed))
> goto end;
>
> while (is_running()) {
> - r = run_pmc_wait_sync(&priv, 1000);
> + r = run_pmc_wait_sync(&priv.node, 1000);
> if (r < 0)
> goto end;
> if (r > 0)
> @@ -1641,7 +1308,7 @@ int main(int argc, char *argv[])
> }
>
> if (!priv.forced_sync_offset) {
> - r = run_pmc_get_utc_offset(&priv, 1000);
> + r = run_pmc_get_utc_offset(&priv.node, 1000);
> if (r <= 0) {
> pr_err("failed to get UTC offset");
> goto end;
> @@ -1651,7 +1318,7 @@ int main(int argc, char *argv[])
> if (priv.forced_sync_offset ||
> (src->clkid != CLOCK_REALTIME && dst->clkid != CLOCK_REALTIME) ||
> src->clkid == CLOCK_INVALID)
> - close_pmc(&priv);
> + close_pmc_node(&priv.node);
> }
>
> if (pps_fd >= 0) {
> @@ -1664,8 +1331,7 @@ int main(int argc, char *argv[])
> }
>
> end:
> - if (priv.pmc)
> - close_pmc(&priv);
> + close_pmc_node(&priv.node);
> clock_cleanup(&priv);
> port_cleanup(&priv);
> config_destroy(cfg);
> diff --git a/pmc_common.c b/pmc_common.c
> index f07f6f65568f..89d7f40b84fe 100644
> --- a/pmc_common.c
> +++ b/pmc_common.c
> @@ -22,6 +22,8 @@
> #include <string.h>
> #include <sys/types.h>
> #include <unistd.h>
> +#include <net/if.h>
> +#include <poll.h>
>
> #include "notification.h"
> #include "print.h"
> @@ -56,6 +58,13 @@
> /* Includes one extra byte to make length even. */
> #define EMPTY_PTP_TEXT 2
>
> +#define PMC_UPDATE_INTERVAL (60 * NS_PER_SEC)
> +#define PMC_SUBSCRIBE_DURATION 180 /* 3 minutes */
> +/* Note that PMC_SUBSCRIBE_DURATION has to be longer than
> + * PMC_UPDATE_INTERVAL otherwise subscription will time out before it is
> + * renewed.
> + */
> +
> static void do_get_action(struct pmc *pmc, int action, int index, char *str);
> static void do_set_action(struct pmc *pmc, int action, int index, char *str);
> static void not_supported(struct pmc *pmc, int action, int index, char *str);
> @@ -711,3 +720,331 @@ int pmc_do_command(struct pmc *pmc, char *str)
>
> return 0;
> }
> +
> +static void send_subscription(struct pmc_node *node)
> +{
> + struct subscribe_events_np sen;
> +
> + memset(&sen, 0, sizeof(sen));
> + sen.duration = PMC_SUBSCRIBE_DURATION;
> + sen.bitmask[0] = 1 << NOTIFY_PORT_STATE;
> + pmc_send_set_action(node->pmc, TLV_SUBSCRIBE_EVENTS_NP, &sen, sizeof(sen));
> +}
> +
> +static int check_clock_identity(struct pmc_node *node, struct ptp_message *msg)
> +{
> + if (!node->clock_identity_set)
> + return 1;
> + return cid_eq(&node->clock_identity,
> + &msg->header.sourcePortIdentity.clockIdentity);
> +}
> +
> +static int is_msg_mgt(struct ptp_message *msg)
> +{
> + struct TLV *tlv;
> +
> + if (msg_type(msg) != MANAGEMENT)
> + return 0;
> + if (management_action(msg) != RESPONSE)
> + return 0;
> + if (msg_tlv_count(msg) != 1)
> + return 0;
> + tlv = (struct TLV *) msg->management.suffix;
> + if (tlv->type == TLV_MANAGEMENT)
> + return 1;
> + if (tlv->type == TLV_MANAGEMENT_ERROR_STATUS)
> + return -1;
> + return 0;
> +}
> +
> +int get_mgt_id(struct ptp_message *msg)
> +{
> + struct management_tlv *mgt;
> +
> + mgt = (struct management_tlv *) msg->management.suffix;
> + return mgt->id;
> +}
> +
> +void *get_mgt_data(struct ptp_message *msg)
> +{
> + struct management_tlv *mgt;
> +
> + mgt = (struct management_tlv *) msg->management.suffix;
> + return mgt->data;
> +}
> +
> +static int get_mgt_err_id(struct ptp_message *msg)
> +{
> + struct management_error_status *mgt;
> +
> + mgt = (struct management_error_status *)msg->management.suffix;
> + return mgt->id;
> +}
> +
> +/* Return values:
> + * 1: success
> + * 0: timeout
> + * -1: error reported by the other side
> + * -2: local error, fatal
> + */
> +static int run_pmc(struct pmc_node *node, int timeout, int ds_id,
> + struct ptp_message **msg)
> +{
> +#define N_FD 1
> + struct pollfd pollfd[N_FD];
> + int cnt, res;
> +
> + while (1) {
> + pollfd[0].fd = pmc_get_transport_fd(node->pmc);
> + pollfd[0].events = POLLIN|POLLPRI;
> + if (!node->pmc_ds_requested && ds_id >= 0)
> + pollfd[0].events |= POLLOUT;
> +
> + cnt = poll(pollfd, N_FD, timeout);
> + if (cnt < 0) {
> + pr_err("poll failed");
> + return -2;
> + }
> + if (!cnt) {
> + /* Request the data set again in the next run. */
> + node->pmc_ds_requested = 0;
> + return 0;
> + }
> +
> + /* Send a new request if there are no pending messages. */
> + if ((pollfd[0].revents & POLLOUT) &&
> + !(pollfd[0].revents & (POLLIN|POLLPRI))) {
> + switch (ds_id) {
> + case TLV_SUBSCRIBE_EVENTS_NP:
> + send_subscription(node);
> + break;
> + default:
> + pmc_send_get_action(node->pmc, ds_id);
> + break;
> + }
> + node->pmc_ds_requested = 1;
> + }
> +
> + if (!(pollfd[0].revents & (POLLIN|POLLPRI)))
> + continue;
> +
> + *msg = pmc_recv(node->pmc);
> +
> + if (!*msg)
> + continue;
> +
> + if (!check_clock_identity(node, *msg)) {
> + msg_put(*msg);
> + *msg = NULL;
> + continue;
> + }
> +
> + res = is_msg_mgt(*msg);
> + if (res < 0 && get_mgt_err_id(*msg) == ds_id) {
> + node->pmc_ds_requested = 0;
> + return -1;
> + }
> + if (res <= 0 || node->recv_subscribed(node, *msg, ds_id) ||
> + get_mgt_id(*msg) != ds_id) {
> + msg_put(*msg);
> + *msg = NULL;
> + continue;
> + }
> + node->pmc_ds_requested = 0;
> + return 1;
> + }
> +}
> +
> +int run_pmc_wait_sync(struct pmc_node *node, int timeout)
> +{
> + struct ptp_message *msg;
> + Enumeration8 portState;
> + void *data;
> + int res;
> +
> + while (1) {
> + res = run_pmc(node, timeout, TLV_PORT_DATA_SET, &msg);
> + if (res <= 0)
> + return res;
> +
> + data = get_mgt_data(msg);
> + portState = ((struct portDS *)data)->portState;
> + msg_put(msg);
> +
> + switch (portState) {
> + case PS_MASTER:
> + case PS_SLAVE:
> + return 1;
> + }
> + /* try to get more data sets (for other ports) */
> + node->pmc_ds_requested = 1;
> + }
> +}
> +
> +int run_pmc_get_utc_offset(struct pmc_node *node, int timeout)
> +{
> + struct ptp_message *msg;
> + int res;
> + struct timePropertiesDS *tds;
> +
> + res = run_pmc(node, timeout, TLV_TIME_PROPERTIES_DATA_SET, &msg);
> + if (res <= 0)
> + return res;
> +
> + tds = (struct timePropertiesDS *)get_mgt_data(msg);
> + if (tds->flags & PTP_TIMESCALE) {
> + node->sync_offset = tds->currentUtcOffset;
> + if (tds->flags & LEAP_61)
> + node->leap = 1;
> + else if (tds->flags & LEAP_59)
> + node->leap = -1;
> + else
> + node->leap = 0;
> + node->utc_offset_traceable = tds->flags & UTC_OFF_VALID &&
> + tds->flags & TIME_TRACEABLE;
> + } else {
> + node->sync_offset = 0;
> + node->leap = 0;
> + node->utc_offset_traceable = 0;
> + }
> + msg_put(msg);
> + return 1;
> +}
> +
> +int run_pmc_get_number_ports(struct pmc_node *node, int timeout)
> +{
> + struct ptp_message *msg;
> + int res;
> + struct defaultDS *dds;
> +
> + res = run_pmc(node, timeout, TLV_DEFAULT_DATA_SET, &msg);
> + if (res <= 0)
> + return res;
> +
> + dds = (struct defaultDS *)get_mgt_data(msg);
> + res = dds->numberPorts;
> + msg_put(msg);
> + return res;
> +}
> +
> +int run_pmc_subscribe(struct pmc_node *node, int timeout)
> +{
> + struct ptp_message *msg;
> + int res;
> +
> + res = run_pmc(node, timeout, TLV_SUBSCRIBE_EVENTS_NP, &msg);
> + if (res <= 0)
> + return res;
> + msg_put(msg);
> + return 1;
> +}
> +
> +void run_pmc_events(struct pmc_node *node)
> +{
> + struct ptp_message *msg;
> +
> + run_pmc(node, 0, -1, &msg);
> +}
> +
> +int run_pmc_port_properties(struct pmc_node *node, int timeout,
> + unsigned int port, int *state,
> + int *tstamping, char *iface)
> +{
> + struct ptp_message *msg;
> + int res, len;
> + struct port_properties_np *ppn;
> +
> + pmc_target_port(node->pmc, port);
> + while (1) {
> + res = run_pmc(node, timeout, TLV_PORT_PROPERTIES_NP, &msg);
> + if (res <= 0)
> + goto out;
> +
> + ppn = get_mgt_data(msg);
> + if (ppn->portIdentity.portNumber != port) {
> + msg_put(msg);
> + continue;
> + }
> +
> + *state = ppn->port_state;
> + *tstamping = ppn->timestamping;
> + len = ppn->interface.length;
> + if (len > IFNAMSIZ - 1)
> + len = IFNAMSIZ - 1;
> + memcpy(iface, ppn->interface.text, len);
> + iface[len] = '\0';
> +
> + msg_put(msg);
> + res = 1;
> + break;
> + }
> +out:
> + pmc_target_all(node->pmc);
> + return res;
> +}
> +
> +int run_pmc_clock_identity(struct pmc_node *node, int timeout)
> +{
> + struct ptp_message *msg;
> + struct defaultDS *dds;
> + int res;
> +
> + res = run_pmc(node, timeout, TLV_DEFAULT_DATA_SET, &msg);
> + if (res <= 0)
> + return res;
> +
> + dds = (struct defaultDS *)get_mgt_data(msg);
> + memcpy(&node->clock_identity, &dds->clockIdentity,
> + sizeof(struct ClockIdentity));
> + node->clock_identity_set = 1;
> + msg_put(msg);
> + return 1;
> +}
> +
> +/* Returns: -1 in case of error, 0 otherwise */
> +int update_pmc_node(struct pmc_node *node, int subscribe)
> +{
> + struct timespec tp;
> + uint64_t ts;
> +
> + if (clock_gettime(CLOCK_MONOTONIC, &tp)) {
> + pr_err("failed to read clock: %m");
> + return -1;
> + }
> + ts = tp.tv_sec * NS_PER_SEC + tp.tv_nsec;
> +
> + if (node->pmc &&
> + !(ts > node->pmc_last_update &&
> + ts - node->pmc_last_update < PMC_UPDATE_INTERVAL)) {
> + if (subscribe)
> + run_pmc_subscribe(node, 0);
> + if (run_pmc_get_utc_offset(node, 0) > 0)
> + node->pmc_last_update = ts;
> + }
> +
> + return 0;
> +}
> +
> +int init_pmc_node(struct config *cfg, struct pmc_node *node, const char *uds,
> + pmc_node_recv_subscribed_t *recv_subscribed)
> +{
> + node->pmc = pmc_create(cfg, TRANS_UDS, uds, 0,
> + config_get_int(cfg, NULL, "domainNumber"),
> + config_get_int(cfg, NULL, "transportSpecific") << 4, 1);
> + if (!node->pmc) {
> + pr_err("failed to create pmc");
> + return -1;
> + }
> + node->recv_subscribed = recv_subscribed;
> +
> + return 0;
> +}
> +
> +void close_pmc_node(struct pmc_node *node)
> +{
> + if (!node->pmc)
> + return;
> +
> + pmc_destroy(node->pmc);
> + node->pmc = NULL;
> +}
> diff --git a/pmc_common.h b/pmc_common.h
> index 9fa72deb4c87..a28bab767e9c 100644
> --- a/pmc_common.h
> +++ b/pmc_common.h
> @@ -24,6 +24,7 @@
> #include "config.h"
> #include "msg.h"
> #include "transport.h"
> +#include "fsm.h"
>
> struct pmc;
>
> @@ -49,4 +50,38 @@ void pmc_target_all(struct pmc *pmc);
> const char *pmc_action_string(int action);
> int pmc_do_command(struct pmc *pmc, char *str);
>
> +struct pmc_node;
> +
> +typedef int pmc_node_recv_subscribed_t(struct pmc_node *node,
> + struct ptp_message *msg,
> + int excluded);
> +
> +struct pmc_node {
> + struct pmc *pmc;
> + int pmc_ds_requested;
> + uint64_t pmc_last_update;
> + int sync_offset;
> + int leap;
> + int utc_offset_traceable;
> + int clock_identity_set;
> + struct ClockIdentity clock_identity;
> + pmc_node_recv_subscribed_t *recv_subscribed;
> +};
> +
> +int init_pmc_node(struct config *cfg, struct pmc_node *node, const char *uds,
> + pmc_node_recv_subscribed_t *recv_subscribed);
> +void close_pmc_node(struct pmc_node *node);
> +int update_pmc_node(struct pmc_node *node, int subscribe);
> +int run_pmc_subscribe(struct pmc_node *node, int timeout);
> +int run_pmc_clock_identity(struct pmc_node *node, int timeout);
> +int run_pmc_wait_sync(struct pmc_node *node, int timeout);
> +int run_pmc_get_number_ports(struct pmc_node *node, int timeout);
> +void run_pmc_events(struct pmc_node *node);
> +int run_pmc_port_properties(struct pmc_node *node, int timeout,
> + unsigned int port, int *state,
> + int *tstamping, char *iface);
> +int run_pmc_get_utc_offset(struct pmc_node *node, int timeout);
> +int get_mgt_id(struct ptp_message *msg);
> +void *get_mgt_data(struct ptp_message *msg);
> +
> #endif
>
|
|
From: Vladimir O. <ol...@gm...> - 2020-08-01 17:46:51
|
Make this information more visible by default, since it is the key
output of this program.
Signed-off-by: Vladimir Oltean <ol...@gm...>
---
ts2phc_slave.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/ts2phc_slave.c b/ts2phc_slave.c
index 7a0522fb0f86..566cb14436fb 100644
--- a/ts2phc_slave.c
+++ b/ts2phc_slave.c
@@ -273,8 +273,8 @@ static int ts2phc_slave_event(struct ts2phc_slave *slave,
adj = servo_sample(slave->clock->servo, offset, extts_ts,
SAMPLE_WEIGHT, &slave->clock->servo_state);
- pr_debug("%s master offset %10" PRId64 " s%d freq %+7.0f",
- slave->name, offset, slave->clock->servo_state, adj);
+ pr_info("%s master offset %10" PRId64 " s%d freq %+7.0f",
+ slave->name, offset, slave->clock->servo_state, adj);
switch (slave->clock->servo_state) {
case SERVO_UNLOCKED:
--
2.25.1
|
|
From: Jacob K. <jac...@in...> - 2020-08-05 23:46:00
|
On 8/1/2020 10:46 AM, Vladimir Oltean wrote:
> Make this information more visible by default, since it is the key
> output of this program.
>
> Signed-off-by: Vladimir Oltean <ol...@gm...>
Yep.
Reviewed-by: Jacob Keller <jac...@in...>
> ---
> ts2phc_slave.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/ts2phc_slave.c b/ts2phc_slave.c
> index 7a0522fb0f86..566cb14436fb 100644
> --- a/ts2phc_slave.c
> +++ b/ts2phc_slave.c
> @@ -273,8 +273,8 @@ static int ts2phc_slave_event(struct ts2phc_slave *slave,
> adj = servo_sample(slave->clock->servo, offset, extts_ts,
> SAMPLE_WEIGHT, &slave->clock->servo_state);
>
> - pr_debug("%s master offset %10" PRId64 " s%d freq %+7.0f",
> - slave->name, offset, slave->clock->servo_state, adj);
> + pr_info("%s master offset %10" PRId64 " s%d freq %+7.0f",
> + slave->name, offset, slave->clock->servo_state, adj);
>
> switch (slave->clock->servo_state) {
> case SERVO_UNLOCKED:
>
|
|
From: Vladimir O. <ol...@gm...> - 2020-08-01 17:46:51
|
Monitor the port state change events from ptp4l, and use that
information to determine the "source" clock.
Then synchronize all other clocks in our list to that source, by feeding
into their respective servo loop an offset equal to the delta between
their timestamp and the timestamp of the source clock. All timestamps
are representative of the same event, which is the most recent perout
pulse of the ts2phc master.
Signed-off-by: Vladimir Oltean <ol...@gm...>
---
ts2phc.c | 133 ++++++++++++++++++++++++++++++++++++++++++++-----
ts2phc_slave.c | 1 +
2 files changed, 122 insertions(+), 12 deletions(-)
diff --git a/ts2phc.c b/ts2phc.c
index f317c4abb4ad..e3d42760dc45 100644
--- a/ts2phc.c
+++ b/ts2phc.c
@@ -309,29 +309,119 @@ static int auto_init_ports(struct ts2phc_private *priv)
return 0;
}
-static void ts2phc_synchronize_clocks(struct ts2phc_private *priv)
+static void ts2phc_reconfigure(struct ts2phc_private *priv)
+{
+ struct clock *c, *src = NULL, *last = NULL;
+ int src_cnt = 0, dst_cnt = 0;
+
+ pr_info("reconfiguring after port state change");
+ priv->state_changed = 0;
+
+ LIST_FOREACH(c, &priv->clocks, list) {
+ if (c->new_state) {
+ c->state = c->new_state;
+ c->new_state = 0;
+ }
+
+ switch (c->state) {
+ case PS_FAULTY:
+ case PS_DISABLED:
+ case PS_LISTENING:
+ case PS_PRE_MASTER:
+ case PS_MASTER:
+ case PS_PASSIVE:
+ if (!c->is_destination) {
+ pr_info("selecting %s for synchronization",
+ c->name);
+ c->is_destination = 1;
+ }
+ dst_cnt++;
+ break;
+ case PS_UNCALIBRATED:
+ src_cnt++;
+ break;
+ case PS_SLAVE:
+ src = c;
+ src_cnt++;
+ break;
+ }
+ last = c;
+ }
+ if (dst_cnt >= 1 && !src) {
+ priv->source = last;
+ priv->source->is_destination = 0;
+ /* Reset to original state in next reconfiguration. */
+ priv->source->new_state = priv->source->state;
+ priv->source->state = PS_SLAVE;
+ pr_info("no source, selecting %s as the default clock",
+ last->name);
+ return;
+ }
+ if (src_cnt > 1) {
+ pr_info("multiple source clocks available, postponing sync...");
+ priv->source = NULL;
+ return;
+ }
+ if (src_cnt > 0 && !src) {
+ pr_info("source clock not ready, waiting...");
+ priv->source = NULL;
+ return;
+ }
+ if (!src_cnt && !dst_cnt) {
+ pr_info("no PHC ready, waiting...");
+ priv->source = NULL;
+ return;
+ }
+ if (!src_cnt) {
+ pr_info("nothing to synchronize");
+ priv->source = NULL;
+ return;
+ }
+ src->is_destination = 0;
+ priv->source = src;
+ pr_info("selecting %s as the source clock", src->name);
+}
+
+static void ts2phc_synchronize_clocks(struct ts2phc_private *priv, int autocfg)
{
- struct timespec source_ts;
tmv_t source_tmv;
struct clock *c;
int valid, err;
- err = ts2phc_master_getppstime(priv->master, &source_ts);
- if (err < 0) {
- pr_err("source ts not valid");
- return;
- }
- if (source_ts.tv_nsec > NS_PER_SEC / 2)
- source_ts.tv_sec++;
- source_ts.tv_nsec = 0;
+ if (autocfg) {
+ if (!priv->source) {
+ pr_debug("no source, skipping");
+ return;
+ }
+ valid = clock_get_tstamp(priv->source, &source_tmv);
+ if (!valid) {
+ pr_err("source clock (%s) timestamp not valid, skipping",
+ priv->source->name);
+ return;
+ }
+ } else {
+ struct timespec source_ts;
- source_tmv = timespec_to_tmv(source_ts);
+ err = ts2phc_master_getppstime(priv->master, &source_ts);
+ if (err < 0) {
+ pr_err("source ts not valid");
+ return;
+ }
+ if (source_ts.tv_nsec > NS_PER_SEC / 2)
+ source_ts.tv_sec++;
+ source_ts.tv_nsec = 0;
+
+ source_tmv = timespec_to_tmv(source_ts);
+ }
LIST_FOREACH(c, &priv->clocks, list) {
int64_t offset;
double adj;
tmv_t ts;
+ if (!c->is_destination)
+ continue;
+
valid = clock_get_tstamp(c, &ts);
if (!valid) {
pr_debug("%s timestamp not valid, skipping", c->name);
@@ -561,6 +651,25 @@ int main(int argc, char *argv[])
while (is_running()) {
struct clock *c;
+ if (autocfg) {
+ /*
+ * Make sure ptp4l sees us as alive and doesn't prune
+ * us from the list of subscribers
+ */
+ err = update_pmc_node(&priv.node, 1);
+ if (err < 0) {
+ pr_err("update_pmc_node returned %d", err);
+ break;
+ }
+ err = run_pmc_events(&priv.node);
+ if (err < 0) {
+ pr_err("run_pmc_events returned %d", err);
+ break;
+ }
+ if (priv.state_changed)
+ ts2phc_reconfigure(&priv);
+ }
+
LIST_FOREACH(c, &priv.clocks, list)
clock_flush_tstamp(c);
@@ -570,7 +679,7 @@ int main(int argc, char *argv[])
break;
}
if (err > 0)
- ts2phc_synchronize_clocks(&priv);
+ ts2phc_synchronize_clocks(&priv, autocfg);
}
ts2phc_cleanup(&priv);
diff --git a/ts2phc_slave.c b/ts2phc_slave.c
index 0ecb4eb941b2..e3bce3b7f051 100644
--- a/ts2phc_slave.c
+++ b/ts2phc_slave.c
@@ -186,6 +186,7 @@ static struct ts2phc_slave *ts2phc_slave_create(struct ts2phc_private *priv,
pr_err("failed to open clock");
goto no_posix_clock;
}
+ slave->clock->is_destination = 1;
pr_debug("PHC slave %s has ptp index %d", device,
slave->clock->phc_index);
--
2.25.1
|
|
[Linuxptp-devel] [RFC PATCH 15/15] ts2phc_phc_master: make use of
new kernel API for perout waveform
From: Vladimir O. <ol...@gm...> - 2020-08-01 17:46:55
|
This API was introduced for 2 reasons:
1. Some hardware can emit PPS signals but not starting from arbitrary
absolute times, but rather phase-aligned to the beginning of a
second. We _could_ patch ts2phc to always specify a start time of
0.000000000 to PTP_PEROUT_REQUEST, but in practice, we would never
know whether that would actually work with all in-tree PHC drivers.
So there was a need for a new flag that only specifies the phase of
the periodic signal, and not the absolute start time.
2. Some hardware can, rather unfortunately, not distinguish between a
rising and a falling extts edge. And, since whatever rises also has
to fall before rising again, the strategy in ts2phc is to set a
'large' pulse width (half the period) and ignore the extts event
corresponding to the mid-way between one second and another. This is
all fine, but currently, ts2phc.pulsewidth is a read-only property in
the config file. The kernel is not instructed in any way to use this
value, it is simply that must be configured based on prior knowledge
of the PHC's implementation. This API changes that.
The introduction of a phase adjustment for the master PHC means we have
to adjust our approximation of the precise perout timestamp. We put that
code into a common function and convert all call sites to call that. We
also need to do the same thing for the edge ignoring logic.
Signed-off-by: Vladimir Oltean <ol...@gm...>
---
config.c | 1 +
missing.h | 53 ++++++++++++++++++++++++++++
ts2phc.8 | 5 +++
ts2phc.c | 86 ++++++++++++++++++++++++++++++---------------
ts2phc.h | 1 +
ts2phc_phc_master.c | 20 +++++++++--
ts2phc_slave.c | 16 +++++++--
7 files changed, 150 insertions(+), 32 deletions(-)
diff --git a/config.c b/config.c
index d3446b4c8f27..a10f30998d10 100644
--- a/config.c
+++ b/config.c
@@ -314,6 +314,7 @@ struct config_item config_tab[] = {
GLOB_ITEM_STR("ts2phc.nmea_remote_host", ""),
GLOB_ITEM_STR("ts2phc.nmea_remote_port", ""),
GLOB_ITEM_STR("ts2phc.nmea_serialport", "/dev/ttyS0"),
+ PORT_ITEM_INT("ts2phc.perout_phase", -1, 0, 999999999),
PORT_ITEM_INT("ts2phc.pin_index", 0, 0, INT_MAX),
GLOB_ITEM_INT("ts2phc.pulsewidth", 500000000, 1000000, 999000000),
PORT_ITEM_ENU("tsproc_mode", TSPROC_FILTER, tsproc_enu),
diff --git a/missing.h b/missing.h
index 35eaf155fc51..e52915e8b621 100644
--- a/missing.h
+++ b/missing.h
@@ -97,6 +97,59 @@ struct compat_ptp_clock_caps {
#endif /*LINUX_VERSION_CODE < 5.8*/
+/*
+ * Bits of the ptp_perout_request.flags field:
+ */
+
+#ifndef PTP_PEROUT_ONE_SHOT
+#define PTP_PEROUT_ONE_SHOT (1<<0)
+#endif
+
+#ifndef PTP_PEROUT_DUTY_CYCLE
+#define PTP_PEROUT_DUTY_CYCLE (1<<1)
+#endif
+
+#ifndef PTP_PEROUT_PHASE
+#define PTP_PEROUT_PHASE (1<<2)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(5,9,0)
+
+/* from upcoming Linux kernel version 5.9 */
+struct compat_ptp_perout_request {
+ union {
+ /*
+ * Absolute start time.
+ * Valid only if (flags & PTP_PEROUT_PHASE) is unset.
+ */
+ struct ptp_clock_time start;
+ /*
+ * Phase offset. The signal should start toggling at an
+ * unspecified integer multiple of the period, plus this value.
+ * The start time should be "as soon as possible".
+ * Valid only if (flags & PTP_PEROUT_PHASE) is set.
+ */
+ struct ptp_clock_time phase;
+ };
+ struct ptp_clock_time period; /* Desired period, zero means disable. */
+ unsigned int index; /* Which channel to configure. */
+ unsigned int flags;
+ union {
+ /*
+ * The "on" time of the signal.
+ * Must be lower than the period.
+ * Valid only if (flags & PTP_PEROUT_DUTY_CYCLE) is set.
+ */
+ struct ptp_clock_time on;
+ /* Reserved for future use. */
+ unsigned int rsv[4];
+ };
+};
+
+#define ptp_perout_request compat_ptp_perout_request
+
+#endif /*LINUX_VERSION_CODE < 5.8*/
+
#ifndef PTP_MAX_SAMPLES
#define PTP_MAX_SAMPLES 25 /* Maximum allowed offset measurement samples. */
#endif /* PTP_MAX_SAMPLES */
diff --git a/ts2phc.8 b/ts2phc.8
index 07a402601c9e..f690e243864d 100644
--- a/ts2phc.8
+++ b/ts2phc.8
@@ -152,6 +152,11 @@ specified, then the given remote connection will be used in preference
to the configured serial port.
The default is "/dev/ttyS0".
.TP
+.B ts2phc.perout_phase
+Configures the offset between the beginning of the second and the PPS
+master's rising edge. Available only for a PHC master. The supported
+range is 0 to 999999999 nanoseconds. The default is 0 nanoseconds.
+.TP
.B ts2phc.pulsewidth
The expected pulse width of the external PPS signal in nanoseconds.
When 'ts2phc.extts_polarity' is "both", the given pulse width is used
diff --git a/ts2phc.c b/ts2phc.c
index 16cfe7cc101d..69cac305c791 100644
--- a/ts2phc.c
+++ b/ts2phc.c
@@ -382,6 +382,40 @@ static void ts2phc_reconfigure(struct ts2phc_private *priv)
pr_info("selecting %s as the source clock", src->name);
}
+static int ts2phc_approximate_master_tstamp(struct ts2phc_private *priv,
+ tmv_t *master_tmv)
+{
+ struct timespec master_ts;
+ tmv_t tmv;
+ int err;
+
+ err = ts2phc_master_getppstime(priv->master, &master_ts);
+ if (err < 0) {
+ pr_err("master ts not valid");
+ return err;
+ }
+
+ tmv = timespec_to_tmv(master_ts);
+ tmv = tmv_sub(tmv, priv->perout_phase);
+ master_ts = tmv_to_timespec(tmv);
+
+ /*
+ * As long as the kernel doesn't support a proper API for reporting
+ * a precise perout timestamp, we'll have to use this crude
+ * approximation.
+ */
+ if (master_ts.tv_nsec > NS_PER_SEC / 2)
+ master_ts.tv_sec++;
+ master_ts.tv_nsec = 0;
+
+ tmv = timespec_to_tmv(master_ts);
+ tmv = tmv_add(tmv, priv->perout_phase);
+
+ *master_tmv = tmv;
+
+ return 0;
+}
+
static void ts2phc_synchronize_clocks(struct ts2phc_private *priv, int autocfg)
{
tmv_t source_tmv;
@@ -400,18 +434,9 @@ static void ts2phc_synchronize_clocks(struct ts2phc_private *priv, int autocfg)
return;
}
} else {
- struct timespec source_ts;
-
- err = ts2phc_master_getppstime(priv->master, &source_ts);
- if (err < 0) {
- pr_err("source ts not valid");
+ err = ts2phc_approximate_master_tstamp(priv, &source_tmv);
+ if (err < 0)
return;
- }
- if (source_ts.tv_nsec > NS_PER_SEC / 2)
- source_ts.tv_sec++;
- source_ts.tv_nsec = 0;
-
- source_tmv = timespec_to_tmv(source_ts);
}
LIST_FOREACH(c, &priv->clocks, list) {
@@ -460,7 +485,7 @@ static void ts2phc_synchronize_clocks(struct ts2phc_private *priv, int autocfg)
static int ts2phc_collect_master_tstamp(struct ts2phc_private *priv)
{
struct clock *master_clock;
- struct timespec master_ts;
+ tmv_t master_tmv;
int err;
master_clock = ts2phc_master_get_clock(priv->master);
@@ -473,22 +498,11 @@ static int ts2phc_collect_master_tstamp(struct ts2phc_private *priv)
if (!master_clock)
return 0;
- err = ts2phc_master_getppstime(priv->master, &master_ts);
- if (err < 0) {
- pr_err("source ts not valid");
+ err = ts2phc_approximate_master_tstamp(priv, &master_tmv);
+ if (err < 0)
return err;
- }
-
- /*
- * As long as the kernel doesn't support a proper API for reporting
- * a precise perout timestamp, we'll have to use this crude
- * approximation.
- */
- if (master_ts.tv_nsec > NS_PER_SEC / 2)
- master_ts.tv_sec++;
- master_ts.tv_nsec = 0;
- clock_add_tstamp(master_clock, timespec_to_tmv(master_ts));
+ clock_add_tstamp(master_clock, master_tmv);
return 0;
}
@@ -636,13 +650,29 @@ int main(int argc, char *argv[])
}
STAILQ_FOREACH(iface, &cfg->interfaces, list) {
- if (1 == config_get_int(cfg, interface_name(iface), "ts2phc.master")) {
+ const char *dev = interface_name(iface);
+
+ if (1 == config_get_int(cfg, dev, "ts2phc.master")) {
+ int perout_phase;
+
if (pps_source) {
fprintf(stderr, "too many PPS sources\n");
ts2phc_cleanup(&priv);
return -1;
}
- pps_source = interface_name(iface);
+ pps_source = dev;
+ perout_phase = config_get_int(cfg, dev,
+ "ts2phc.perout_phase");
+ /*
+ * We use a default value of -1 to distinguish whether
+ * to use the PTP_PEROUT_PHASE API or not. But if we
+ * don't use that (and therefore we use absolute start
+ * time), the phase is still zero, by our application's
+ * convention.
+ */
+ if (perout_phase < 0)
+ perout_phase = 0;
+ priv.perout_phase = nanoseconds_to_tmv(perout_phase);
} else {
if (ts2phc_slave_add(&priv, interface_name(iface))) {
fprintf(stderr, "failed to add slave\n");
diff --git a/ts2phc.h b/ts2phc.h
index 4f656cc1c741..9b5df9e25e38 100644
--- a/ts2phc.h
+++ b/ts2phc.h
@@ -58,6 +58,7 @@ struct ts2phc_private {
STAILQ_HEAD(slave_ifaces_head, ts2phc_slave) slaves;
unsigned int n_slaves;
struct ts2phc_slave_array *polling_array;
+ tmv_t perout_phase;
struct config *cfg;
struct pmc_node node;
int state_changed;
diff --git a/ts2phc_phc_master.c b/ts2phc_phc_master.c
index 77b2452b5549..3feaacfbfb39 100644
--- a/ts2phc_phc_master.c
+++ b/ts2phc_phc_master.c
@@ -27,6 +27,8 @@ static int ts2phc_phc_master_activate(struct config *cfg, const char *dev,
{
struct ptp_perout_request perout_request;
struct ptp_pin_desc desc;
+ int32_t perout_phase;
+ int32_t pulsewidth;
struct timespec ts;
memset(&desc, 0, sizeof(desc));
@@ -44,12 +46,26 @@ static int ts2phc_phc_master_activate(struct config *cfg, const char *dev,
perror("clock_gettime");
return -1;
}
+ perout_phase = config_get_int(cfg, dev, "ts2phc.perout_phase");
memset(&perout_request, 0, sizeof(perout_request));
perout_request.index = master->channel;
- perout_request.start.sec = ts.tv_sec + 2;
- perout_request.start.nsec = 0;
perout_request.period.sec = 1;
perout_request.period.nsec = 0;
+ perout_request.flags = 0;
+ pulsewidth = config_get_int(cfg, dev, "ts2phc.pulsewidth");
+ if (pulsewidth) {
+ perout_request.flags |= PTP_PEROUT_DUTY_CYCLE;
+ perout_request.on.sec = pulsewidth / NS_PER_SEC;
+ perout_request.on.nsec = pulsewidth % NS_PER_SEC;
+ }
+ if (perout_phase != -1) {
+ perout_request.flags |= PTP_PEROUT_PHASE;
+ perout_request.phase.sec = perout_phase / NS_PER_SEC;
+ perout_request.phase.nsec = perout_phase % NS_PER_SEC;
+ } else {
+ perout_request.start.sec = ts.tv_sec + 2;
+ perout_request.start.nsec = 0;
+ }
if (ioctl(CLOCKID_TO_FD(master->clock->clkid), PTP_PEROUT_REQUEST2,
&perout_request)) {
diff --git a/ts2phc_slave.c b/ts2phc_slave.c
index e3bce3b7f051..68fe355bdca7 100644
--- a/ts2phc_slave.c
+++ b/ts2phc_slave.c
@@ -249,6 +249,19 @@ static void ts2phc_slave_destroy(struct ts2phc_slave *slave)
free(slave);
}
+static bool ts2phc_slave_ignore(struct ts2phc_private *priv,
+ struct ts2phc_slave *slave,
+ struct timespec source_ts)
+{
+ tmv_t source_tmv = timespec_to_tmv(source_ts);
+
+ source_tmv = tmv_sub(source_tmv, priv->perout_phase);
+ source_ts = tmv_to_timespec(source_tmv);
+
+ return source_ts.tv_nsec > slave->ignore_lower &&
+ source_ts.tv_nsec < slave->ignore_upper;
+}
+
static enum extts_result ts2phc_slave_event(struct ts2phc_private *priv,
struct ts2phc_slave *slave)
{
@@ -277,8 +290,7 @@ static enum extts_result ts2phc_slave_event(struct ts2phc_private *priv,
}
if (slave->polarity == (PTP_RISING_EDGE | PTP_FALLING_EDGE) &&
- source_ts.tv_nsec > slave->ignore_lower &&
- source_ts.tv_nsec < slave->ignore_upper) {
+ ts2phc_slave_ignore(priv, slave, source_ts)) {
pr_debug("%s SKIP extts index %u at %lld.%09u src %" PRIi64 ".%ld",
slave->name, event.index, event.t.sec, event.t.nsec,
--
2.25.1
|
|
From: Jacob K. <jac...@in...> - 2020-08-05 23:56:12
|
On 8/1/2020 10:46 AM, Vladimir Oltean wrote:
> This API was introduced for 2 reasons:
>
> 1. Some hardware can emit PPS signals but not starting from arbitrary
> absolute times, but rather phase-aligned to the beginning of a
> second. We _could_ patch ts2phc to always specify a start time of
> 0.000000000 to PTP_PEROUT_REQUEST, but in practice, we would never
> know whether that would actually work with all in-tree PHC drivers.
> So there was a need for a new flag that only specifies the phase of
> the periodic signal, and not the absolute start time.
>
> 2. Some hardware can, rather unfortunately, not distinguish between a
> rising and a falling extts edge. And, since whatever rises also has
> to fall before rising again, the strategy in ts2phc is to set a
> 'large' pulse width (half the period) and ignore the extts event
> corresponding to the mid-way between one second and another. This is
> all fine, but currently, ts2phc.pulsewidth is a read-only property in
> the config file. The kernel is not instructed in any way to use this
> value, it is simply that must be configured based on prior knowledge
> of the PHC's implementation. This API changes that.
>
> The introduction of a phase adjustment for the master PHC means we have
> to adjust our approximation of the precise perout timestamp. We put that
> code into a common function and convert all call sites to call that. We
> also need to do the same thing for the edge ignoring logic.
>
> Signed-off-by: Vladimir Oltean <ol...@gm...>
> ---
> config.c | 1 +
> missing.h | 53 ++++++++++++++++++++++++++++
> ts2phc.8 | 5 +++
> ts2phc.c | 86 ++++++++++++++++++++++++++++++---------------
> ts2phc.h | 1 +
> ts2phc_phc_master.c | 20 +++++++++--
> ts2phc_slave.c | 16 +++++++--
> 7 files changed, 150 insertions(+), 32 deletions(-)
>
> diff --git a/config.c b/config.c
> index d3446b4c8f27..a10f30998d10 100644
> --- a/config.c
> +++ b/config.c
> @@ -314,6 +314,7 @@ struct config_item config_tab[] = {
> GLOB_ITEM_STR("ts2phc.nmea_remote_host", ""),
> GLOB_ITEM_STR("ts2phc.nmea_remote_port", ""),
> GLOB_ITEM_STR("ts2phc.nmea_serialport", "/dev/ttyS0"),
> + PORT_ITEM_INT("ts2phc.perout_phase", -1, 0, 999999999),
> PORT_ITEM_INT("ts2phc.pin_index", 0, 0, INT_MAX),
> GLOB_ITEM_INT("ts2phc.pulsewidth", 500000000, 1000000, 999000000),
> PORT_ITEM_ENU("tsproc_mode", TSPROC_FILTER, tsproc_enu),
> diff --git a/missing.h b/missing.h
> index 35eaf155fc51..e52915e8b621 100644
> --- a/missing.h
> +++ b/missing.h
> @@ -97,6 +97,59 @@ struct compat_ptp_clock_caps {
>
> #endif /*LINUX_VERSION_CODE < 5.8*/
>
> +/*
> + * Bits of the ptp_perout_request.flags field:
> + */
> +
> +#ifndef PTP_PEROUT_ONE_SHOT
> +#define PTP_PEROUT_ONE_SHOT (1<<0)
> +#endif
> +
> +#ifndef PTP_PEROUT_DUTY_CYCLE
> +#define PTP_PEROUT_DUTY_CYCLE (1<<1)
> +#endif
> +
> +#ifndef PTP_PEROUT_PHASE
> +#define PTP_PEROUT_PHASE (1<<2)
> +#endif
> +
> +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,9,0)
> +
> +/* from upcoming Linux kernel version 5.9 */
> +struct compat_ptp_perout_request {
> + union {
> + /*
> + * Absolute start time.
> + * Valid only if (flags & PTP_PEROUT_PHASE) is unset.
> + */
> + struct ptp_clock_time start;
> + /*
> + * Phase offset. The signal should start toggling at an
> + * unspecified integer multiple of the period, plus this value.
> + * The start time should be "as soon as possible".
> + * Valid only if (flags & PTP_PEROUT_PHASE) is set.
> + */
> + struct ptp_clock_time phase;
> + };
> + struct ptp_clock_time period; /* Desired period, zero means disable. */
> + unsigned int index; /* Which channel to configure. */
> + unsigned int flags;
> + union {
> + /*
> + * The "on" time of the signal.
> + * Must be lower than the period.
> + * Valid only if (flags & PTP_PEROUT_DUTY_CYCLE) is set.
> + */
> + struct ptp_clock_time on;
> + /* Reserved for future use. */
> + unsigned int rsv[4];
> + };
> +};
> +
> +#define ptp_perout_request compat_ptp_perout_request
> +
> +#endif /*LINUX_VERSION_CODE < 5.8*/
> +
> #ifndef PTP_MAX_SAMPLES
> #define PTP_MAX_SAMPLES 25 /* Maximum allowed offset measurement samples. */
> #endif /* PTP_MAX_SAMPLES */
> diff --git a/ts2phc.8 b/ts2phc.8
> index 07a402601c9e..f690e243864d 100644
> --- a/ts2phc.8
> +++ b/ts2phc.8
> @@ -152,6 +152,11 @@ specified, then the given remote connection will be used in preference
> to the configured serial port.
> The default is "/dev/ttyS0".
> .TP
> +.B ts2phc.perout_phase
> +Configures the offset between the beginning of the second and the PPS
> +master's rising edge. Available only for a PHC master. The supported
> +range is 0 to 999999999 nanoseconds. The default is 0 nanoseconds.
> +.TP
> .B ts2phc.pulsewidth
> The expected pulse width of the external PPS signal in nanoseconds.
> When 'ts2phc.extts_polarity' is "both", the given pulse width is used
> diff --git a/ts2phc.c b/ts2phc.c
> index 16cfe7cc101d..69cac305c791 100644
> --- a/ts2phc.c
> +++ b/ts2phc.c
> @@ -382,6 +382,40 @@ static void ts2phc_reconfigure(struct ts2phc_private *priv)
> pr_info("selecting %s as the source clock", src->name);
> }
>
> +static int ts2phc_approximate_master_tstamp(struct ts2phc_private *priv,
> + tmv_t *master_tmv)
> +{
> + struct timespec master_ts;
> + tmv_t tmv;
> + int err;
> +
> + err = ts2phc_master_getppstime(priv->master, &master_ts);
> + if (err < 0) {
> + pr_err("master ts not valid");
> + return err;
> + }
> +
> + tmv = timespec_to_tmv(master_ts);
> + tmv = tmv_sub(tmv, priv->perout_phase);
> + master_ts = tmv_to_timespec(tmv);
> +
> + /*
> + * As long as the kernel doesn't support a proper API for reporting
> + * a precise perout timestamp, we'll have to use this crude
> + * approximation.
> + */
> + if (master_ts.tv_nsec > NS_PER_SEC / 2)
> + master_ts.tv_sec++;
> + master_ts.tv_nsec = 0;
> +
> + tmv = timespec_to_tmv(master_ts);
> + tmv = tmv_add(tmv, priv->perout_phase);
> +
The assumption here is that the timestamp must be on a full second,
which makes sense since we specified this to be the case when setting up
the signal. Ok. I think this approximation works well, and the more
accurate your given PPS signal is for that hardware, the better this
would be.
> + *master_tmv = tmv;
> +
> + return 0;
> +}
> +
> static void ts2phc_synchronize_clocks(struct ts2phc_private *priv, int autocfg)
> {
> tmv_t source_tmv;
> @@ -400,18 +434,9 @@ static void ts2phc_synchronize_clocks(struct ts2phc_private *priv, int autocfg)
> return;
> }
> } else {
> - struct timespec source_ts;
> -
> - err = ts2phc_master_getppstime(priv->master, &source_ts);
> - if (err < 0) {
> - pr_err("source ts not valid");
> + err = ts2phc_approximate_master_tstamp(priv, &source_tmv);
> + if (err < 0)
> return;
> - }
> - if (source_ts.tv_nsec > NS_PER_SEC / 2)
> - source_ts.tv_sec++;
> - source_ts.tv_nsec = 0;
> -
> - source_tmv = timespec_to_tmv(source_ts);
> }
>
> LIST_FOREACH(c, &priv->clocks, list) {
> @@ -460,7 +485,7 @@ static void ts2phc_synchronize_clocks(struct ts2phc_private *priv, int autocfg)
> static int ts2phc_collect_master_tstamp(struct ts2phc_private *priv)
> {
> struct clock *master_clock;
> - struct timespec master_ts;
> + tmv_t master_tmv;
> int err;
>
> master_clock = ts2phc_master_get_clock(priv->master);
> @@ -473,22 +498,11 @@ static int ts2phc_collect_master_tstamp(struct ts2phc_private *priv)
> if (!master_clock)
> return 0;
>
> - err = ts2phc_master_getppstime(priv->master, &master_ts);
> - if (err < 0) {
> - pr_err("source ts not valid");
> + err = ts2phc_approximate_master_tstamp(priv, &master_tmv);
> + if (err < 0)
> return err;
> - }
> -
> - /*
> - * As long as the kernel doesn't support a proper API for reporting
> - * a precise perout timestamp, we'll have to use this crude
> - * approximation.
> - */
> - if (master_ts.tv_nsec > NS_PER_SEC / 2)
> - master_ts.tv_sec++;
> - master_ts.tv_nsec = 0;
>
> - clock_add_tstamp(master_clock, timespec_to_tmv(master_ts));
> + clock_add_tstamp(master_clock, master_tmv);
>
> return 0;
> }
> @@ -636,13 +650,29 @@ int main(int argc, char *argv[])
> }
>
> STAILQ_FOREACH(iface, &cfg->interfaces, list) {
> - if (1 == config_get_int(cfg, interface_name(iface), "ts2phc.master")) {
> + const char *dev = interface_name(iface);
> +
> + if (1 == config_get_int(cfg, dev, "ts2phc.master")) {
> + int perout_phase;
> +
> if (pps_source) {
> fprintf(stderr, "too many PPS sources\n");
> ts2phc_cleanup(&priv);
> return -1;
> }
> - pps_source = interface_name(iface);
> + pps_source = dev;
> + perout_phase = config_get_int(cfg, dev,
> + "ts2phc.perout_phase");
> + /*
> + * We use a default value of -1 to distinguish whether
> + * to use the PTP_PEROUT_PHASE API or not. But if we
> + * don't use that (and therefore we use absolute start
> + * time), the phase is still zero, by our application's
> + * convention.
> + */
> + if (perout_phase < 0)
> + perout_phase = 0;
> + priv.perout_phase = nanoseconds_to_tmv(perout_phase);
> } else {
> if (ts2phc_slave_add(&priv, interface_name(iface))) {
> fprintf(stderr, "failed to add slave\n");
> diff --git a/ts2phc.h b/ts2phc.h
> index 4f656cc1c741..9b5df9e25e38 100644
> --- a/ts2phc.h
> +++ b/ts2phc.h
> @@ -58,6 +58,7 @@ struct ts2phc_private {
> STAILQ_HEAD(slave_ifaces_head, ts2phc_slave) slaves;
> unsigned int n_slaves;
> struct ts2phc_slave_array *polling_array;
> + tmv_t perout_phase;
> struct config *cfg;
> struct pmc_node node;
> int state_changed;
> diff --git a/ts2phc_phc_master.c b/ts2phc_phc_master.c
> index 77b2452b5549..3feaacfbfb39 100644
> --- a/ts2phc_phc_master.c
> +++ b/ts2phc_phc_master.c
> @@ -27,6 +27,8 @@ static int ts2phc_phc_master_activate(struct config *cfg, const char *dev,
> {
> struct ptp_perout_request perout_request;
> struct ptp_pin_desc desc;
> + int32_t perout_phase;
> + int32_t pulsewidth;
> struct timespec ts;
>
> memset(&desc, 0, sizeof(desc));
> @@ -44,12 +46,26 @@ static int ts2phc_phc_master_activate(struct config *cfg, const char *dev,
> perror("clock_gettime");
> return -1;
> }
> + perout_phase = config_get_int(cfg, dev, "ts2phc.perout_phase");
> memset(&perout_request, 0, sizeof(perout_request));
> perout_request.index = master->channel;
> - perout_request.start.sec = ts.tv_sec + 2;
> - perout_request.start.nsec = 0;
> perout_request.period.sec = 1;
> perout_request.period.nsec = 0;
> + perout_request.flags = 0;
> + pulsewidth = config_get_int(cfg, dev, "ts2phc.pulsewidth");
> + if (pulsewidth) {
> + perout_request.flags |= PTP_PEROUT_DUTY_CYCLE;
> + perout_request.on.sec = pulsewidth / NS_PER_SEC;
> + perout_request.on.nsec = pulsewidth % NS_PER_SEC;
> + }
> + if (perout_phase != -1) {
> + perout_request.flags |= PTP_PEROUT_PHASE;
> + perout_request.phase.sec = perout_phase / NS_PER_SEC;
> + perout_request.phase.nsec = perout_phase % NS_PER_SEC;
> + } else {
> + perout_request.start.sec = ts.tv_sec + 2;
> + perout_request.start.nsec = 0;
> + }
>
> if (ioctl(CLOCKID_TO_FD(master->clock->clkid), PTP_PEROUT_REQUEST2,
> &perout_request)) {
> diff --git a/ts2phc_slave.c b/ts2phc_slave.c
> index e3bce3b7f051..68fe355bdca7 100644
> --- a/ts2phc_slave.c
> +++ b/ts2phc_slave.c
> @@ -249,6 +249,19 @@ static void ts2phc_slave_destroy(struct ts2phc_slave *slave)
> free(slave);
> }
>
> +static bool ts2phc_slave_ignore(struct ts2phc_private *priv,
> + struct ts2phc_slave *slave,
> + struct timespec source_ts)
> +{
> + tmv_t source_tmv = timespec_to_tmv(source_ts);
> +
> + source_tmv = tmv_sub(source_tmv, priv->perout_phase);
> + source_ts = tmv_to_timespec(source_tmv);
> +
> + return source_ts.tv_nsec > slave->ignore_lower &&
> + source_ts.tv_nsec < slave->ignore_upper;
> +}
> +
> static enum extts_result ts2phc_slave_event(struct ts2phc_private *priv,
> struct ts2phc_slave *slave)
> {
> @@ -277,8 +290,7 @@ static enum extts_result ts2phc_slave_event(struct ts2phc_private *priv,
> }
>
> if (slave->polarity == (PTP_RISING_EDGE | PTP_FALLING_EDGE) &&
> - source_ts.tv_nsec > slave->ignore_lower &&
> - source_ts.tv_nsec < slave->ignore_upper) {
> + ts2phc_slave_ignore(priv, slave, source_ts)) {
>
> pr_debug("%s SKIP extts index %u at %lld.%09u src %" PRIi64 ".%ld",
> slave->name, event.index, event.t.sec, event.t.nsec,
>
|
|
From: Vladimir O. <ol...@gm...> - 2020-08-01 17:46:59
|
Now that we are registering a clock even for the PPS master when it
supports that (i.e. when it is a PHC), introduce a new API to retrieve
its clock in order to add timestamps to it.
The PHC master can be synchronized to the extts events of a PHC slave,
when in automatic mode.
Signed-off-by: Vladimir Oltean <ol...@gm...>
---
ts2phc.c | 45 ++++++++++++++++++++++++++++++++++++++++-
ts2phc_master.h | 2 ++
ts2phc_master_private.h | 1 +
ts2phc_phc_master.c | 17 ++++++++++++++++
4 files changed, 64 insertions(+), 1 deletion(-)
diff --git a/ts2phc.c b/ts2phc.c
index e3d42760dc45..16cfe7cc101d 100644
--- a/ts2phc.c
+++ b/ts2phc.c
@@ -457,6 +457,42 @@ static void ts2phc_synchronize_clocks(struct ts2phc_private *priv, int autocfg)
}
}
+static int ts2phc_collect_master_tstamp(struct ts2phc_private *priv)
+{
+ struct clock *master_clock;
+ struct timespec master_ts;
+ int err;
+
+ master_clock = ts2phc_master_get_clock(priv->master);
+ /*
+ * Master isn't a PHC (it may be a generic or a GPS master),
+ * don't error out, just don't do anything. If it doesn't have a PHC,
+ * there is nothing to synchronize, which is the only point of
+ * collecting its perout timestamp in the first place.
+ */
+ if (!master_clock)
+ return 0;
+
+ err = ts2phc_master_getppstime(priv->master, &master_ts);
+ if (err < 0) {
+ pr_err("source ts not valid");
+ return err;
+ }
+
+ /*
+ * As long as the kernel doesn't support a proper API for reporting
+ * a precise perout timestamp, we'll have to use this crude
+ * approximation.
+ */
+ if (master_ts.tv_nsec > NS_PER_SEC / 2)
+ master_ts.tv_sec++;
+ master_ts.tv_nsec = 0;
+
+ clock_add_tstamp(master_clock, timespec_to_tmv(master_ts));
+
+ return 0;
+}
+
static void usage(char *progname)
{
fprintf(stderr,
@@ -678,8 +714,15 @@ int main(int argc, char *argv[])
pr_err("poll failed");
break;
}
- if (err > 0)
+ if (err > 0) {
+ err = ts2phc_collect_master_tstamp(&priv);
+ if (err) {
+ pr_err("failed to collect master tstamp");
+ break;
+ }
+
ts2phc_synchronize_clocks(&priv, autocfg);
+ }
}
ts2phc_cleanup(&priv);
diff --git a/ts2phc_master.h b/ts2phc_master.h
index a7e7186f79a1..6edf8c013af9 100644
--- a/ts2phc_master.h
+++ b/ts2phc_master.h
@@ -51,4 +51,6 @@ void ts2phc_master_destroy(struct ts2phc_master *master);
*/
int ts2phc_master_getppstime(struct ts2phc_master *master, struct timespec *ts);
+struct clock *ts2phc_master_get_clock(struct ts2phc_master *m);
+
#endif
diff --git a/ts2phc_master_private.h b/ts2phc_master_private.h
index 463a1f003a21..deef1b520a3f 100644
--- a/ts2phc_master_private.h
+++ b/ts2phc_master_private.h
@@ -15,6 +15,7 @@
struct ts2phc_master {
void (*destroy)(struct ts2phc_master *ts2phc_master);
int (*getppstime)(struct ts2phc_master *master, struct timespec *ts);
+ struct clock *(*get_clock)(struct ts2phc_master *m);
};
#endif
diff --git a/ts2phc_phc_master.c b/ts2phc_phc_master.c
index 363085279ae3..77b2452b5549 100644
--- a/ts2phc_phc_master.c
+++ b/ts2phc_phc_master.c
@@ -83,6 +83,14 @@ static int ts2phc_phc_master_getppstime(struct ts2phc_master *m,
return clock_gettime(master->clock->clkid, ts);
}
+struct clock *ts2phc_phc_master_get_clock(struct ts2phc_master *m)
+{
+ struct ts2phc_phc_master *master =
+ container_of(m, struct ts2phc_phc_master, master);
+
+ return master->clock;
+}
+
struct ts2phc_master *ts2phc_phc_master_create(struct ts2phc_private *priv,
const char *dev)
{
@@ -94,6 +102,7 @@ struct ts2phc_master *ts2phc_phc_master_create(struct ts2phc_private *priv,
}
master->master.destroy = ts2phc_phc_master_destroy;
master->master.getppstime = ts2phc_phc_master_getppstime;
+ master->master.get_clock = ts2phc_phc_master_get_clock;
master->clock = clock_add(priv, dev);
if (!master->clock) {
@@ -112,3 +121,11 @@ struct ts2phc_master *ts2phc_phc_master_create(struct ts2phc_private *priv,
return &master->master;
}
+
+struct clock *ts2phc_master_get_clock(struct ts2phc_master *m)
+{
+ if (m->get_clock)
+ return m->get_clock(m);
+
+ return NULL;
+}
--
2.25.1
|
|
From: Richard C. <ric...@gm...> - 2020-08-04 01:50:46
|
On Sat, Aug 01, 2020 at 08:46:05PM +0300, Vladimir Oltean wrote: > At a high level, what I have done is: > - I moved the PMC related code from phc2sys into pmc_common.c, for > ts2phc reuse > - I created an extra abstraction in ts2phc as "struct clock" that would > represent what's synchronizable. The "master" and "slave" concepts > retain their meaning, which is: "master" == the device that emits PPS, > and "slave" == the device that timestamps PPS. > > The changes should be backwards-compatible with the non-automatic mode. > I have only tested non-automatic mode with a PHC master (that's all I > have) and it still appears to work as before. > 22 files changed, 1577 insertions(+), 750 deletions(-) This sounds interesting. It is a pretty big diff, and so I'll need time to go through it all. Right now, I'm rather over committed, and so please be patient! Thanks, Richard |
|
From: Vladimir O. <ol...@gm...> - 2020-08-04 11:40:30
|
On Mon, Aug 03, 2020 at 06:50:37PM -0700, Richard Cochran wrote: > On Sat, Aug 01, 2020 at 08:46:05PM +0300, Vladimir Oltean wrote: > > At a high level, what I have done is: > > - I moved the PMC related code from phc2sys into pmc_common.c, for > > ts2phc reuse > > - I created an extra abstraction in ts2phc as "struct clock" that would > > represent what's synchronizable. The "master" and "slave" concepts > > retain their meaning, which is: "master" == the device that emits PPS, > > and "slave" == the device that timestamps PPS. > > > > The changes should be backwards-compatible with the non-automatic mode. > > I have only tested non-automatic mode with a PHC master (that's all I > > have) and it still appears to work as before. > > > 22 files changed, 1577 insertions(+), 750 deletions(-) > > This sounds interesting. It is a pretty big diff, and so I'll need > time to go through it all. Right now, I'm rather over committed, and > so please be patient! Sure, there's no hurry. The diff is large, yes, even though I tried to avoid making unnecessary changes. I hope it isn't too difficult to review, it isn't as polished as I typically like, because the idea itself was uncertain, so I preferred not to spend that extra time at this point in the process. Anyways, I'm looking forward to your feedback whenever you have the time. Thanks, -Vladimir |