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 timestamps are a mere approximation. We configure the kernel to emit
periodic output and then never hear back from that PHC again. We just
assume that it emits periodic output as promised, and that each pulse is
emitted at the beginning of each second. We rely on the slaves to report
an extts event first, and we know who generated that - the master, of
course. So then we proceed to read the master's PHC time, and round that
to what is the most plausible integer second in its time base. We
believe that to be the 'timestamp'. This is fed into the servo algorithm.

The PHC master can be synchronized to the extts events of a PHC slave,
when in automatic mode.

Signed-off-by: Vladimir Oltean <olte...@gmail.com>
---
Changes in v4:
Add one more paragraph to commit message.

Changes in v3:
Implement ts2phc_master_get_clock() as part of ts2phc_master.c instead
of ts2phc_phc_master.c.

 ts2phc.c                | 45 ++++++++++++++++++++++++++++++++++++++++-
 ts2phc_master.c         |  8 ++++++++
 ts2phc_master.h         |  2 ++
 ts2phc_master_private.h |  1 +
 ts2phc_phc_master.c     |  9 +++++++++
 5 files changed, 64 insertions(+), 1 deletion(-)

diff --git a/ts2phc.c b/ts2phc.c
index dbe7bf954943..ce2ceb97888a 100644
--- a/ts2phc.c
+++ b/ts2phc.c
@@ -482,6 +482,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,
@@ -702,8 +738,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.c b/ts2phc_master.c
index 4617c4aecbe5..0dc02a103859 100644
--- a/ts2phc_master.c
+++ b/ts2phc_master.c
@@ -38,3 +38,11 @@ int ts2phc_master_getppstime(struct ts2phc_master *master, 
struct timespec *ts)
 {
        return master->getppstime(master, ts);
 }
+
+struct clock *ts2phc_master_get_clock(struct ts2phc_master *m)
+{
+       if (m->get_clock)
+               return m->get_clock(m);
+
+       return NULL;
+}
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 1a944a960f18..233c95f5c181 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) {
-- 
2.25.1



_______________________________________________
Linuxptp-devel mailing list
Linuxptp-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxptp-devel

Reply via email to