phc2sys: re-create clock clkid and servo when phc index changed

When the clock device or phc index changed, the new phc device may have
different maximum adjustment. So we need to create a new clkid and servo
in clock_reinit().

At the same time, we should not only do clock_reinit() when the new state
is PS_MASTER. We also need to reinit clock after a failover in slave mode(
the new state is PS_SLAVE). We can do clock_reinit() even in PS_FAULTY so
we can finish adjust offset before come back to PS_LISTENING. So I removed
the check and let's do clock_reinit() whenever there is a new state.

And for servo reset, as Miroslav suggested, we will do it in these cases:
- the system clock is the new destination (master state)
- a PHC is the new destination (master state)
- a PHC is switched (in any state)

Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
master
Hangbin Liu 2017-10-09 22:31:49 +08:00 committed by Richard Cochran
parent cb53238d5d
commit 8a349e557c
1 changed files with 61 additions and 11 deletions

View File

@ -128,6 +128,11 @@ static int clock_handle_leap(struct node *node, struct clock *clock,
static int run_pmc_get_utc_offset(struct node *node, int timeout);
static void run_pmc_events(struct node *node);
static int normalize_state(int state);
static int run_pmc_port_properties(struct node *node, int timeout,
unsigned int port,
int *state, int *tstamping, char *iface);
static clockid_t clock_open(char *device, int *phc_index)
{
struct sk_ts_info ts_info;
@ -309,15 +314,62 @@ static struct port *port_add(struct node *node, unsigned int number,
return p;
}
static void clock_reinit(struct clock *clock)
static void clock_reinit(struct node *node, struct clock *clock, int new_state)
{
servo_reset(clock->servo);
clock->servo_state = SERVO_UNLOCKED;
int phc_index = -1, phc_switched = 0;
int state, timestamping, ret = -1;
struct port *p;
struct servo *servo;
struct sk_ts_info ts_info;
char iface[IFNAMSIZ];
clockid_t clkid = CLOCK_INVALID;
if (clock->offset_stats) {
stats_reset(clock->offset_stats);
stats_reset(clock->freq_stats);
stats_reset(clock->delay_stats);
LIST_FOREACH(p, &node->ports, list) {
if (p->clock == clock) {
ret = run_pmc_port_properties(node, 1000, p->number,
&state, &timestamping,
iface);
if (ret > 0)
p->state = normalize_state(state);
}
}
if (ret > 0 && timestamping != TS_SOFTWARE) {
/* Check if device changed */
if (strcmp(clock->device, iface)) {
free(clock->device);
clock->device = strdup(iface);
}
/* Check if phc index changed */
if (!sk_get_ts_info(clock->device, &ts_info) &&
clock->phc_index != ts_info.phc_index) {
clkid = clock_open(clock->device, &phc_index);
if (clkid == CLOCK_INVALID)
return;
phc_close(clock->clkid);
clock->clkid = clkid;
clock->phc_index = phc_index;
servo = servo_add(node, clock);
if (servo) {
servo_destroy(clock->servo);
clock->servo = servo;
}
phc_switched = 1;
}
}
if (new_state == PS_MASTER || phc_switched) {
servo_reset(clock->servo);
clock->servo_state = SERVO_UNLOCKED;
if (clock->offset_stats) {
stats_reset(clock->offset_stats);
stats_reset(clock->freq_stats);
stats_reset(clock->delay_stats);
}
}
}
@ -336,9 +388,7 @@ static void reconfigure(struct node *node)
}
if (c->new_state) {
if (c->new_state == PS_MASTER)
clock_reinit(c);
clock_reinit(node, c, c->new_state);
c->state = c->new_state;
c->new_state = 0;
}
@ -403,7 +453,7 @@ static void reconfigure(struct node *node)
} else if (rt) {
if (rt->state != PS_MASTER) {
rt->state = PS_MASTER;
clock_reinit(rt);
clock_reinit(node, rt, rt->state);
}
pr_info("selecting %s for synchronization", rt->device);
}