The interface to the Linux kernel for adjusting clock frequencies is specified in scaled parts per million, where the frequency field is parts per million with a 16 bit binary fractional field. (Equivalently it is parts per ~65 billion).
The frequency adjustment is stored internally as a double, even though when displaying we always display only a whole number adjustment. Thus ptp4l and phc2sys already use the full range of frequency adjustments that can be specified using a double type. However, when initializing the servo we read the current clock frequency and cast it to an integer, discarding the fractional part below a part per billion. Refactor the servo_create API to take a double value instead of an integer value. Fix the clockadj_get_freq and clockadj_set_freq initialization to avoid casting to an integer and thus rounding the value. Signed-off-by: Jacob Keller <jacob.e.kel...@intel.com> --- Changes since v1: * rebased to fix conflicts since Miroslav's patch was applied clock.c | 10 ++++++---- linreg.c | 2 +- linreg.h | 2 +- pi.c | 2 +- pi.h | 2 +- servo.c | 2 +- servo.h | 2 +- ts2phc.c | 5 +++-- 8 files changed, 15 insertions(+), 12 deletions(-) diff --git a/clock.c b/clock.c index 8177e77bc1ec..518601021051 100644 --- a/clock.c +++ b/clock.c @@ -897,10 +897,11 @@ struct clock *clock_create(enum clock_type type, struct config *config, enum servo_type servo = config_get_int(config, NULL, "clock_servo"); char ts_label[IF_NAMESIZE], phc[32], *tmp; enum timestamp_type timestamping; - int fadj = 0, max_adj = 0, sw_ts; int phc_index, conf_phc_index, required_modes = 0; struct clock *c = &the_clock; + int max_adj = 0, sw_ts; const char *uds_ifname; + double fadj = 0.0; struct port *p; unsigned char oui[OUI_LEN]; struct interface *iface; @@ -1143,7 +1144,7 @@ struct clock *clock_create(enum clock_type type, struct config *config, c->time_flags = c->utc_timescale ? 0 : PTP_TIMESCALE; if (c->clkid != CLOCK_INVALID) { - fadj = (int) clockadj_get_freq(c->clkid); + fadj = clockadj_get_freq(c->clkid); /* Disable write phase mode if not implemented by driver */ if (c->write_phase_mode && !phc_has_writephase(c->clkid)) { pr_err("clock does not support write phase mode"); @@ -1732,9 +1733,10 @@ struct tsproc *clock_get_tsproc(struct clock *c) int clock_switch_phc(struct clock *c, int phc_index) { struct servo *servo; - int fadj, max_adj; clockid_t clkid; char phc[32]; + double fadj; + int max_adj; snprintf(phc, sizeof(phc), "/dev/ptp%d", phc_index); clkid = phc_open(phc); @@ -1748,7 +1750,7 @@ int clock_switch_phc(struct clock *c, int phc_index) phc_close(clkid); return -1; } - fadj = (int) clockadj_get_freq(clkid); + fadj = clockadj_get_freq(clkid); servo = servo_create(c->config, c->servo_type, -fadj, max_adj, 0); if (!servo) { pr_err("Switching PHC, failed to create clock servo"); diff --git a/linreg.c b/linreg.c index 8f354f4b0d0b..363636e16937 100644 --- a/linreg.c +++ b/linreg.c @@ -330,7 +330,7 @@ static void linreg_leap(struct servo *servo, int leap) s->leap = leap; } -struct servo *linreg_servo_create(int fadj) +struct servo *linreg_servo_create(double fadj) { struct linreg_servo *s; diff --git a/linreg.h b/linreg.h index 5c86ea76ebf2..3c48ce5d465a 100644 --- a/linreg.h +++ b/linreg.h @@ -21,6 +21,6 @@ #include "servo.h" -struct servo *linreg_servo_create(int fadj); +struct servo *linreg_servo_create(double fadj); #endif diff --git a/pi.c b/pi.c index bfe50223d96a..4a96a5b1913b 100644 --- a/pi.c +++ b/pi.c @@ -177,7 +177,7 @@ static void pi_reset(struct servo *servo) s->count = 0; } -struct servo *pi_servo_create(struct config *cfg, int fadj, int sw_ts) +struct servo *pi_servo_create(struct config *cfg, double fadj, int sw_ts) { struct pi_servo *s; diff --git a/pi.h b/pi.h index feb3ebeb25b9..1e7eb4f3fd51 100644 --- a/pi.h +++ b/pi.h @@ -21,6 +21,6 @@ #include "servo.h" -struct servo *pi_servo_create(struct config *cfg, int fadj, int sw_ts); +struct servo *pi_servo_create(struct config *cfg, double fadj, int sw_ts); #endif diff --git a/servo.c b/servo.c index 46042aa176d9..6ba7cb42c71e 100644 --- a/servo.c +++ b/servo.c @@ -31,7 +31,7 @@ #define NSEC_PER_SEC 1000000000 struct servo *servo_create(struct config *cfg, enum servo_type type, - int fadj, int max_ppb, int sw_ts) + double fadj, int max_ppb, int sw_ts) { double servo_first_step_threshold; double servo_step_threshold; diff --git a/servo.h b/servo.h index 6c30d3341fa6..6cedb66ada03 100644 --- a/servo.h +++ b/servo.h @@ -77,7 +77,7 @@ enum servo_state { * @return A pointer to a new servo on success, NULL otherwise. */ struct servo *servo_create(struct config *cfg, enum servo_type type, - int fadj, int max_ppb, int sw_ts); + double fadj, int max_ppb, int sw_ts); /** * Destroy an instance of a clock servo. diff --git a/ts2phc.c b/ts2phc.c index ff917ace31a5..f7542347b2f5 100644 --- a/ts2phc.c +++ b/ts2phc.c @@ -126,9 +126,10 @@ static struct servo *ts2phc_servo_create(struct ts2phc_private *priv, { enum servo_type type = config_get_int(priv->cfg, NULL, "clock_servo"); struct servo *servo; - int fadj, max_adj; + double fadj; + int max_adj; - fadj = (int) clockadj_get_freq(clock->clkid); + fadj = clockadj_get_freq(clock->clkid); max_adj = phc_max_adj(clock->clkid); -- 2.38.1.420.g319605f8f00e _______________________________________________ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel