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