sys: add sync status setting to generic and Linux driver

Set the adjtimex status, esterror and maxerror fields to the values
provided by the reference module.
This commit is contained in:
Miroslav Lichvar 2014-12-09 17:31:10 +01:00
parent 2645e632a8
commit 02cbe5e1ad
5 changed files with 54 additions and 17 deletions

View file

@ -38,6 +38,7 @@ struct timex {
#define ADJ_OFFSET 0x0001 /* time offset */
#define ADJ_FREQUENCY 0x0002 /* frequency offset */
#define ADJ_MAXERROR 0x0004 /* maximum time error */
#define ADJ_ESTERROR 0x0008 /* estimated time error */
#define ADJ_STATUS 0x0010 /* clock status */
#define ADJ_TIMECONST 0x0020 /* pll time constant */
#define ADJ_SETOFFSET 0x0100 /* add 'time' to current time */

View file

@ -39,9 +39,10 @@
/* ================================================== */
/* System clock frequency drivers */
/* System clock drivers */
static lcl_ReadFrequencyDriver drv_read_freq;
static lcl_SetFrequencyDriver drv_set_freq;
static lcl_SetSyncStatusDriver drv_set_sync_status;
/* Current frequency as requested by the local module (in ppm) */
static double base_freq;
@ -270,6 +271,22 @@ apply_step_offset(double offset)
/* ================================================== */
static void
set_sync_status(int synchronised, double est_error, double max_error)
{
double offset;
offset = fabs(offset_register);
if (est_error < offset)
est_error = offset;
max_error += offset;
if (drv_set_sync_status)
drv_set_sync_status(synchronised, est_error, max_error);
}
/* ================================================== */
void
SYS_Generic_CompleteFreqDriver(double max_set_freq_ppm, double max_set_freq_delay,
lcl_ReadFrequencyDriver sys_read_freq,
@ -282,6 +299,7 @@ SYS_Generic_CompleteFreqDriver(double max_set_freq_ppm, double max_set_freq_dela
max_freq_change_delay = max_set_freq_delay * (1.0 + max_freq / 1.0e6);
drv_read_freq = sys_read_freq;
drv_set_freq = sys_set_freq;
drv_set_sync_status = sys_set_sync_status;
base_freq = (*drv_read_freq)();
slew_freq = 0.0;
@ -292,7 +310,7 @@ SYS_Generic_CompleteFreqDriver(double max_set_freq_ppm, double max_set_freq_dela
lcl_RegisterSystemDrivers(read_frequency, set_frequency,
accrue_offset, sys_apply_step_offset ?
sys_apply_step_offset : apply_step_offset,
offset_convert, sys_set_leap, NULL);
offset_convert, sys_set_leap, set_sync_status);
LCL_AddParameterChangeHandler(handle_step, NULL);
}

View file

@ -58,6 +58,9 @@ int LockAll = 0;
#include "logging.h"
#include "wrap_adjtimex.h"
/* The threshold for adjtimex maxerror when the kernel sets the UNSYNC flag */
#define UNSYNC_MAXERROR 16.0
/* This is the uncompensated system tick value */
static int nominal_tick;
@ -181,6 +184,29 @@ set_leap(int leap)
/* ================================================== */
static void
set_sync_status(int synchronised, double est_error, double max_error)
{
if (synchronised) {
if (est_error > UNSYNC_MAXERROR)
est_error = UNSYNC_MAXERROR;
if (max_error >= UNSYNC_MAXERROR) {
max_error = UNSYNC_MAXERROR;
synchronised = 0;
}
} else {
est_error = max_error = UNSYNC_MAXERROR;
}
/* Clear the UNSYNC flag only if rtcsync is enabled */
if (!CNF_GetRtcSync())
synchronised = 0;
TMX_SetSync(synchronised, est_error, max_error);
}
/* ================================================== */
/* Estimate the value of USER_HZ given the value of txc.tick that chronyd finds when
* it starts. The only credible values are 100 (Linux/x86) or powers of 2.
* Also, the bounds checking inside the kernel's adjtimex system call enforces
@ -334,13 +360,11 @@ SYS_Linux_Initialise(void)
have_setoffset = 0;
}
TMX_SetSync(CNF_GetRtcSync());
SYS_Generic_CompleteFreqDriver(1.0e6 * max_tick_bias / nominal_tick,
1.0 / tick_update_hz,
read_frequency, set_frequency,
have_setoffset ? apply_step_offset : NULL,
set_leap, NULL);
set_leap, set_sync_status);
}
/* ================================================== */

View file

@ -68,19 +68,11 @@ TMX_SetFrequency(double *freq, long tick)
{
struct timex txc;
txc.modes = ADJ_TICK | ADJ_FREQUENCY | ADJ_STATUS;
txc.modes = ADJ_TICK | ADJ_FREQUENCY;
txc.freq = (long)(*freq * (double)(1 << SHIFT_USEC));
*freq = txc.freq / (double)(1 << SHIFT_USEC);
txc.tick = tick;
txc.status = status;
if (!(status & STA_UNSYNC)) {
/* maxerror has to be reset periodically to prevent kernel
from enabling UNSYNC flag */
txc.modes |= ADJ_MAXERROR;
txc.maxerror = 0;
}
return adjtimex(&txc);
}
@ -161,7 +153,7 @@ TMX_SetLeap(int leap)
return adjtimex(&txc);
}
int TMX_SetSync(int sync)
int TMX_SetSync(int sync, double est_error, double max_error)
{
struct timex txc;
@ -171,8 +163,10 @@ int TMX_SetSync(int sync)
status |= STA_UNSYNC;
}
txc.modes = ADJ_STATUS;
txc.modes = ADJ_STATUS | ADJ_ESTERROR | ADJ_MAXERROR;
txc.status = status;
txc.esterror = est_error * 1.0e6;
txc.maxerror = max_error * 1.0e6;
return adjtimex(&txc);
}

View file

@ -69,7 +69,7 @@ int TMX_SetFrequency(double *freq, long tick);
int TMX_GetFrequency(double *freq, long *tick);
int TMX_ReadCurrentParams(struct tmx_params *params);
int TMX_SetLeap(int leap);
int TMX_SetSync(int sync);
int TMX_SetSync(int sync, double est_error, double max_error);
int TMX_TestStepOffset(void);
int TMX_ApplyStepOffset(double offset);