clock: Introduce a function to switch the PTP Hardware Clock.
When switching clock devices in JBOD mode, we need to be able to reset the servo. The existing servo_reset() function will not serve us well, because in this case we also need to seed the existing frequency offset and limit. This patch adds a new method that simply starts the servo from scratch. In the unlikely event of a resource allocation failure, the method will simply continue to use the previous device, which is better than nothing and certainly preferable to bailing out the program. Signed-off-by: Richard Cochran <richardcochran@gmail.com>master
parent
d70d38ade3
commit
a96797a7fc
37
clock.c
37
clock.c
|
@ -74,6 +74,7 @@ struct clock_subscriber {
|
||||||
struct clock {
|
struct clock {
|
||||||
clockid_t clkid;
|
clockid_t clkid;
|
||||||
struct servo *servo;
|
struct servo *servo;
|
||||||
|
enum servo_type servo_type;
|
||||||
struct defaultDS dds;
|
struct defaultDS dds;
|
||||||
struct dataset default_dataset;
|
struct dataset default_dataset;
|
||||||
struct currentDS cur;
|
struct currentDS cur;
|
||||||
|
@ -862,6 +863,7 @@ struct clock *clock_create(int phc_index, struct interfaces_head *ifaces,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
c->servo_state = SERVO_UNLOCKED;
|
c->servo_state = SERVO_UNLOCKED;
|
||||||
|
c->servo_type = servo;
|
||||||
c->delay_filter = filter_create(dds->delay_filter,
|
c->delay_filter = filter_create(dds->delay_filter,
|
||||||
dds->delay_filter_length);
|
dds->delay_filter_length);
|
||||||
if (!c->delay_filter) {
|
if (!c->delay_filter) {
|
||||||
|
@ -1358,6 +1360,41 @@ UInteger16 clock_steps_removed(struct clock *c)
|
||||||
return c->cur.stepsRemoved;
|
return c->cur.stepsRemoved;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int clock_switch_phc(struct clock *c, int phc_index)
|
||||||
|
{
|
||||||
|
struct servo *servo;
|
||||||
|
int fadj, max_adj;
|
||||||
|
clockid_t clkid;
|
||||||
|
char phc[32];
|
||||||
|
|
||||||
|
snprintf(phc, 31, "/dev/ptp%d", phc_index);
|
||||||
|
clkid = phc_open(phc);
|
||||||
|
if (clkid == CLOCK_INVALID) {
|
||||||
|
pr_err("Switching PHC, failed to open %s: %m", phc);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
max_adj = phc_max_adj(clkid);
|
||||||
|
if (!max_adj) {
|
||||||
|
pr_err("Switching PHC, clock is not adjustable");
|
||||||
|
phc_close(clkid);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
fadj = (int) clockadj_get_freq(clkid);
|
||||||
|
clockadj_set_freq(clkid, fadj);
|
||||||
|
servo = servo_create(c->servo_type, -fadj, max_adj, 0);
|
||||||
|
if (!servo) {
|
||||||
|
pr_err("Switching PHC, failed to create clock servo");
|
||||||
|
phc_close(clkid);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
phc_close(c->clkid);
|
||||||
|
servo_destroy(c->servo);
|
||||||
|
c->clkid = clkid;
|
||||||
|
c->servo = servo;
|
||||||
|
c->servo_state = SERVO_UNLOCKED;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
enum servo_state clock_synchronize(struct clock *c,
|
enum servo_state clock_synchronize(struct clock *c,
|
||||||
struct timespec ingress_ts,
|
struct timespec ingress_ts,
|
||||||
struct timestamp origin_ts,
|
struct timestamp origin_ts,
|
||||||
|
|
8
clock.h
8
clock.h
|
@ -204,6 +204,14 @@ int clock_slave_only(struct clock *c);
|
||||||
*/
|
*/
|
||||||
UInteger16 clock_steps_removed(struct clock *c);
|
UInteger16 clock_steps_removed(struct clock *c);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Switch to a new PTP Hardware Clock, for use with the "jbod" mode.
|
||||||
|
* @param c The clock instance.
|
||||||
|
* @param phc_index The index of the PHC device to use.
|
||||||
|
* @return Zero on success, non-zero otherwise.
|
||||||
|
*/
|
||||||
|
int clock_switch_phc(struct clock *c, int phc_index);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provide a data point to synchronize the clock.
|
* Provide a data point to synchronize the clock.
|
||||||
* @param c The clock instance to synchronize.
|
* @param c The clock instance to synchronize.
|
||||||
|
|
Loading…
Reference in New Issue