Current code only prints a message in case the kernel returns an error
for a clock adjustment. Failing to adjust clock leads to an inconsistent
state in which a servo continues to report "locked" state while the
underlying PHC's state is essentially undetermined.

This change resets the servo in case of failure to adjust the clock.

Signed-off-by: Wojciech Wasko <wwa...@nvidia.com>
---
 clock.c    | 26 +++++++++++++++++++-------
 clockadj.c | 18 +++++++++++++-----
 clockadj.h |  9 ++++++---
 phc2sys.c  | 11 +++++++++--
 ts2phc.c   | 14 +++++++++++---
 5 files changed, 58 insertions(+), 20 deletions(-)

diff --git a/clock.c b/clock.c
index 134c7c3..ff1abbf 100644
--- a/clock.c
+++ b/clock.c
@@ -1778,18 +1778,20 @@ static void clock_step_window(struct clock *c)
        c->step_window_counter = c->step_window;
 }
 
-static void clock_synchronize_locked(struct clock *c, double adj)
+static int clock_synchronize_locked(struct clock *c, double adj)
 {
        if (c->sanity_check) {
                clockcheck_freq(c->sanity_check, clockadj_get_freq(c->clkid));
        }
-       clockadj_set_freq(c->clkid, -adj);
+       if (clockadj_set_freq(c->clkid, -adj) < 0)
+               return -1;
        if (c->clkid == CLOCK_REALTIME) {
                sysclk_set_sync();
        }
        if (c->sanity_check) {
                clockcheck_set_freq(c->sanity_check, -adj);
        }
+       return 0;
 }
 
 enum servo_state clock_synchronize(struct clock *c, tmv_t ingress, tmv_t 
origin)
@@ -1841,8 +1843,10 @@ enum servo_state clock_synchronize(struct clock *c, 
tmv_t ingress, tmv_t origin)
        case SERVO_UNLOCKED:
                break;
        case SERVO_JUMP:
-               clockadj_set_freq(c->clkid, -adj);
-               clockadj_step(c->clkid, -tmv_to_nanoseconds(c->master_offset));
+               if (clockadj_set_freq(c->clkid, -adj) < 0)
+                       goto servo_unlock;
+               if (clockadj_step(c->clkid, 
-tmv_to_nanoseconds(c->master_offset)) < 0)
+                       goto servo_unlock;
                c->ingress_ts = tmv_zero();
                if (c->sanity_check) {
                        clockcheck_set_freq(c->sanity_check, -adj);
@@ -1853,14 +1857,17 @@ enum servo_state clock_synchronize(struct clock *c, 
tmv_t ingress, tmv_t origin)
                clock_step_window(c);
                break;
        case SERVO_LOCKED:
-               clock_synchronize_locked(c, adj);
+               if (clock_synchronize_locked(c, adj) < 0)
+                       goto servo_unlock;
                break;
        case SERVO_LOCKED_STABLE:
                if (c->write_phase_mode) {
-                       clockadj_set_phase(c->clkid, -offset);
+                       if (clockadj_set_phase(c->clkid, -offset) < 0)
+                               goto servo_unlock;
                        adj = 0;
                } else {
-                       clock_synchronize_locked(c, adj);
+                       if (clock_synchronize_locked(c, adj) < 0)
+                               goto servo_unlock;
                }
                break;
        }
@@ -1877,6 +1884,11 @@ enum servo_state clock_synchronize(struct clock *c, 
tmv_t ingress, tmv_t origin)
        clock_notify_event(c, NOTIFY_TIME_SYNC);
 
        return state;
+
+servo_unlock:
+       servo_reset(c->servo);
+       c->servo_state = SERVO_UNLOCKED;
+       return SERVO_UNLOCKED;
 }
 
 void clock_sync_interval(struct clock *c, int n)
diff --git a/clockadj.c b/clockadj.c
index 4c920b9..1437ec0 100644
--- a/clockadj.c
+++ b/clockadj.c
@@ -48,7 +48,7 @@ void clockadj_init(clockid_t clkid)
 #endif
 }
 
-void clockadj_set_freq(clockid_t clkid, double freq)
+int clockadj_set_freq(clockid_t clkid, double freq)
 {
        struct timex tx;
        memset(&tx, 0, sizeof(tx));
@@ -62,8 +62,11 @@ void clockadj_set_freq(clockid_t clkid, double freq)
 
        tx.modes |= ADJ_FREQUENCY;
        tx.freq = (long) (freq * 65.536);
-       if (clock_adjtime(clkid, &tx) < 0)
+       if (clock_adjtime(clkid, &tx) < 0) {
                pr_err("failed to adjust the clock: %m");
+               return -1;
+       }
+       return 0;
 }
 
 double clockadj_get_freq(clockid_t clkid)
@@ -82,7 +85,7 @@ double clockadj_get_freq(clockid_t clkid)
        return f;
 }
 
-void clockadj_set_phase(clockid_t clkid, long offset)
+int clockadj_set_phase(clockid_t clkid, long offset)
 {
        struct timex tx;
        memset(&tx, 0, sizeof(tx));
@@ -91,10 +94,12 @@ void clockadj_set_phase(clockid_t clkid, long offset)
        tx.offset = offset;
        if (clock_adjtime(clkid, &tx) < 0) {
                pr_err("failed to set the clock offset: %m");
+               return -1;
        }
+       return 0;
 }
 
-void clockadj_step(clockid_t clkid, int64_t step)
+int clockadj_step(clockid_t clkid, int64_t step)
 {
        struct timex tx;
        int sign = 1;
@@ -114,8 +119,11 @@ void clockadj_step(clockid_t clkid, int64_t step)
                tx.time.tv_sec  -= 1;
                tx.time.tv_usec += 1000000000;
        }
-       if (clock_adjtime(clkid, &tx) < 0)
+       if (clock_adjtime(clkid, &tx) < 0) {
                pr_err("failed to step clock: %m");
+               return -1;
+       }
+       return 0;
 }
 
 int clockadj_max_freq(clockid_t clkid)
diff --git a/clockadj.h b/clockadj.h
index 6db1d79..ff5e3d5 100644
--- a/clockadj.h
+++ b/clockadj.h
@@ -33,8 +33,9 @@ void clockadj_init(clockid_t clkid);
  * Set clock's frequency offset.
  * @param clkid A clock ID obtained using phc_open() or CLOCK_REALTIME.
  * @param freq  The frequency offset in parts per billion (ppb).
+ * @return      0 on success, -1 on failure
  */
-void clockadj_set_freq(clockid_t clkid, double freq);
+int clockadj_set_freq(clockid_t clkid, double freq);
 
 /**
  * Read clock's frequency offset.
@@ -47,15 +48,17 @@ double clockadj_get_freq(clockid_t clkid);
  * Set clock's phase offset.
  * @param clkid  A clock ID obtained using phc_open() or CLOCK_REALTIME.
  * @param offset The phase offset in nanoseconds.
+ * @return       0 on success, -1 on failure
  */
-void clockadj_set_phase(clockid_t clkid, long offset);
+int clockadj_set_phase(clockid_t clkid, long offset);
 
 /**
  * Step clock's time.
  * @param clkid A clock ID obtained using phc_open() or CLOCK_REALTIME.
  * @param step  The time step in nanoseconds.
+ * @return      0 on success, -1 on failure
  */
-void clockadj_step(clockid_t clkid, int64_t step);
+int clockadj_step(clockid_t clkid, int64_t step);
 
 /**
  * Read maximum frequency adjustment of the target clock.
diff --git a/phc2sys.c b/phc2sys.c
index 88ed00c..40236b9 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -555,7 +555,8 @@ static void update_clock(struct phc2sys_private *priv, 
struct clock *clock,
        case SERVO_UNLOCKED:
                break;
        case SERVO_JUMP:
-               clockadj_step(clock->clkid, -offset);
+               if (clockadj_step(clock->clkid, -offset) < 0)
+                       goto servo_unlock;
                if (clock->sanity_check)
                        clockcheck_step(clock->sanity_check, -offset);
                /* Fall through. */
@@ -564,7 +565,8 @@ static void update_clock(struct phc2sys_private *priv, 
struct clock *clock,
                if (clock->sanity_check)
                        clockcheck_freq(clock->sanity_check,
                                        clockadj_get_freq(clock->clkid));
-               clockadj_set_freq(clock->clkid, -ppb);
+               if (clockadj_set_freq(clock->clkid, -ppb) < 0)
+                       goto servo_unlock;
                if (clock->clkid == CLOCK_REALTIME)
                        sysclk_set_sync();
                if (clock->sanity_check)
@@ -587,6 +589,11 @@ report:
                                offset, state, ppb);
                }
        }
+       return;
+
+servo_unlock:
+       servo_reset(clock->servo);
+       clock->servo_state = SERVO_UNLOCKED;
 }
 
 static void enable_pps_output(clockid_t src)
diff --git a/ts2phc.c b/ts2phc.c
index f754234..9eaa9b9 100644
--- a/ts2phc.c
+++ b/ts2phc.c
@@ -485,14 +485,22 @@ static void ts2phc_synchronize_clocks(struct 
ts2phc_private *priv, int autocfg)
                case SERVO_UNLOCKED:
                        break;
                case SERVO_JUMP:
-                       clockadj_set_freq(c->clkid, -adj);
-                       clockadj_step(c->clkid, -offset);
+                       if (clockadj_set_freq(c->clkid, -adj) < 0)
+                               goto servo_unlock;
+                       if (clockadj_step(c->clkid, -offset) < 0)
+                               goto servo_unlock;
                        break;
                case SERVO_LOCKED:
                case SERVO_LOCKED_STABLE:
-                       clockadj_set_freq(c->clkid, -adj);
+                       if (clockadj_set_freq(c->clkid, -adj) < 0)
+                               goto servo_unlock;
                        break;
                }
+               continue;
+
+servo_unlock:
+               servo_reset(c->servo);
+               c->servo_state = SERVO_UNLOCKED;
        }
 }
 
-- 
2.25.1



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

Reply via email to