Set TAI offset of system clock.
When synchronizing the system clock and the PTP UTC offset is valid and traceable, set the TAI offset of the clock to have correct CLOCK_TAI (which is implemented in the kernel as CLOCK_REALTIME + TAI offset). Signed-off-by: Miroslav Lichvar <mlichvar@redhat.com>master
parent
a3c32b8c65
commit
fefd5b4b05
9
clock.c
9
clock.c
|
@ -88,6 +88,7 @@ struct clock {
|
|||
int freq_est_interval;
|
||||
int grand_master_capable; /* for 802.1AS only */
|
||||
int utc_timescale;
|
||||
int utc_offset_set;
|
||||
int leap_set;
|
||||
int kernel_leap;
|
||||
int utc_offset; /* grand master role */
|
||||
|
@ -700,6 +701,13 @@ static int clock_utc_correct(struct clock *c, tmv_t ingress)
|
|||
}
|
||||
}
|
||||
|
||||
/* Update TAI-UTC offset of the system clock if valid and traceable. */
|
||||
if (c->tds.flags & UTC_OFF_VALID && c->tds.flags & TIME_TRACEABLE &&
|
||||
c->utc_offset_set != utc_offset && c->clkid == CLOCK_REALTIME) {
|
||||
sysclk_set_tai_offset(utc_offset);
|
||||
c->utc_offset_set = utc_offset;
|
||||
}
|
||||
|
||||
if (!(c->tds.flags & PTP_TIMESCALE))
|
||||
return 0;
|
||||
|
||||
|
@ -789,6 +797,7 @@ struct clock *clock_create(int phc_index, struct interface *iface, int count,
|
|||
max_adj = sysclk_max_freq();
|
||||
sysclk_set_leap(0);
|
||||
}
|
||||
c->utc_offset_set = 0;
|
||||
c->leap_set = 0;
|
||||
c->time_flags = c->utc_timescale ? 0 : PTP_TIMESCALE;
|
||||
|
||||
|
|
11
clockadj.c
11
clockadj.c
|
@ -129,6 +129,17 @@ void sysclk_set_leap(int leap)
|
|||
realtime_leap_bit = tx.status;
|
||||
}
|
||||
|
||||
void sysclk_set_tai_offset(int offset)
|
||||
{
|
||||
clockid_t clkid = CLOCK_REALTIME;
|
||||
struct timex tx;
|
||||
memset(&tx, 0, sizeof(tx));
|
||||
tx.modes = ADJ_TAI;
|
||||
tx.constant = offset;
|
||||
if (clock_adjtime(clkid, &tx) < 0)
|
||||
pr_err("failed to set TAI offset: %m");
|
||||
}
|
||||
|
||||
int sysclk_max_freq(void)
|
||||
{
|
||||
clockid_t clkid = CLOCK_REALTIME;
|
||||
|
|
|
@ -57,6 +57,12 @@ void clockadj_step(clockid_t clkid, int64_t step);
|
|||
*/
|
||||
void sysclk_set_leap(int leap);
|
||||
|
||||
/**
|
||||
* Set the TAI offset of the system clock to have correct CLOCK_TAI.
|
||||
* @param offset The TAI-UTC offset in seconds.
|
||||
*/
|
||||
void sysclk_set_tai_offset(int offset);
|
||||
|
||||
/**
|
||||
* Read maximum frequency adjustment of the system clock (CLOCK_REALTIME).
|
||||
* @return The maximum frequency adjustment in parts per billion (ppb).
|
||||
|
|
33
phc2sys.c
33
phc2sys.c
|
@ -78,6 +78,7 @@ struct clock {
|
|||
int new_state;
|
||||
int sync_offset;
|
||||
int leap_set;
|
||||
int utc_offset_set;
|
||||
struct servo *servo;
|
||||
enum servo_state servo_state;
|
||||
char *device;
|
||||
|
@ -103,6 +104,7 @@ struct node {
|
|||
double phc_interval;
|
||||
int sync_offset;
|
||||
int forced_sync_offset;
|
||||
int utc_offset_traceable;
|
||||
int leap;
|
||||
int kernel_leap;
|
||||
struct pmc *pmc;
|
||||
|
@ -864,9 +866,12 @@ static int run_pmc_get_utc_offset(struct node *node, int timeout)
|
|||
node->leap = -1;
|
||||
else
|
||||
node->leap = 0;
|
||||
node->utc_offset_traceable = tds->flags & UTC_OFF_VALID &&
|
||||
tds->flags & TIME_TRACEABLE;
|
||||
} else {
|
||||
node->sync_offset = 0;
|
||||
node->leap = 0;
|
||||
node->utc_offset_traceable = 0;
|
||||
}
|
||||
msg_put(msg);
|
||||
return 1;
|
||||
|
@ -1076,14 +1081,10 @@ static int clock_handle_leap(struct node *node, struct clock *clock,
|
|||
|
||||
clock->sync_offset = node->sync_offset;
|
||||
|
||||
if (!node_leap && !clock->leap_set)
|
||||
return 0;
|
||||
|
||||
if (clock->is_utc == node->master->is_utc)
|
||||
return 0;
|
||||
|
||||
/* If the system clock is the master clock, get a time stamp from
|
||||
it, as it is the clock which will include the leap second. */
|
||||
if ((node_leap || clock->leap_set) &&
|
||||
clock->is_utc != node->master->is_utc) {
|
||||
/* If the master clock is in UTC, get a time stamp from it, as
|
||||
it is the clock which will include the leap second. */
|
||||
if (node->master->is_utc) {
|
||||
struct timespec tp;
|
||||
if (clock_gettime(node->master->clkid, &tp)) {
|
||||
|
@ -1094,7 +1095,7 @@ static int clock_handle_leap(struct node *node, struct clock *clock,
|
|||
}
|
||||
|
||||
/* If the clock will be stepped, the time stamp has to be the
|
||||
target time. Ignore possible 1 second error in UTC offset. */
|
||||
new time. Ignore possible 1 second error in UTC offset. */
|
||||
if (clock->is_utc && clock->servo_state == SERVO_UNLOCKED)
|
||||
ts -= offset + get_sync_offset(node, clock);
|
||||
|
||||
|
@ -1105,14 +1106,24 @@ static int clock_handle_leap(struct node *node, struct clock *clock,
|
|||
}
|
||||
|
||||
clock_leap = leap_second_status(ts, clock->leap_set,
|
||||
&node_leap, &clock->sync_offset);
|
||||
&node_leap,
|
||||
&clock->sync_offset);
|
||||
|
||||
if (clock->leap_set != clock_leap) {
|
||||
/* Only the system clock can leap. */
|
||||
if (clock->clkid == CLOCK_REALTIME && node->kernel_leap)
|
||||
if (clock->clkid == CLOCK_REALTIME &&
|
||||
node->kernel_leap)
|
||||
sysclk_set_leap(clock_leap);
|
||||
clock->leap_set = clock_leap;
|
||||
}
|
||||
}
|
||||
|
||||
if (node->utc_offset_traceable &&
|
||||
clock->utc_offset_set != clock->sync_offset) {
|
||||
if (clock->clkid == CLOCK_REALTIME)
|
||||
sysclk_set_tai_offset(clock->sync_offset);
|
||||
clock->utc_offset_set = clock->sync_offset;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue