Discussion:
[Linuxptp-devel] [PATCH 1/4] Add leap function to servo.
Miroslav Lichvar
2014-06-20 14:32:48 UTC
Permalink
Introduce a new function to inform the servo about upcoming leap second.
This is used when the kernel leap is disabled to allow the servo to
handle better the sudden 1 second step in the offset when the leap
second is inserted or deleted.

Signed-off-by: Miroslav Lichvar <***@redhat.com>
---
clock.c | 2 ++
phc2sys.c | 2 ++
servo.c | 6 ++++++
servo.h | 8 ++++++++
servo_private.h | 2 ++
5 files changed, 20 insertions(+)

diff --git a/clock.c b/clock.c
index 14e20ad..ddea72f 100644
--- a/clock.c
+++ b/clock.c
@@ -697,6 +697,8 @@ static int clock_utc_correct(struct clock *c, tmv_t ingress)
if (c->leap_set != clock_leap) {
if (c->kernel_leap)
sysclk_set_leap(clock_leap);
+ else
+ servo_leap(c->servo, clock_leap);
c->leap_set = clock_leap;
}
}
diff --git a/phc2sys.c b/phc2sys.c
index e063372..4b8051e 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -1114,6 +1114,8 @@ static int clock_handle_leap(struct node *node, struct clock *clock,
if (clock->clkid == CLOCK_REALTIME &&
node->kernel_leap)
sysclk_set_leap(clock_leap);
+ else
+ servo_leap(clock->servo, clock_leap);
clock->leap_set = clock_leap;
}
}
diff --git a/servo.c b/servo.c
index 58bd4eb..f200f75 100644
--- a/servo.c
+++ b/servo.c
@@ -107,3 +107,9 @@ double servo_rate_ratio(struct servo *servo)

return 1.0;
}
+
+void servo_leap(struct servo *servo, int leap)
+{
+ if (servo->leap)
+ servo->leap(servo, leap);
+}
diff --git a/servo.h b/servo.h
index 9cec6f4..e054501 100644
--- a/servo.h
+++ b/servo.h
@@ -132,4 +132,12 @@ void servo_reset(struct servo *servo);
*/
double servo_rate_ratio(struct servo *servo);

+/**
+ * Inform a clock servo about upcoming leap second.
+ * @param servo Pointer to a servo obtained via @ref servo_create().
+ * @param leap +1 when leap second will be inserted, -1 when leap second
+ * will be deleted, 0 when it passed.
+ */
+void servo_leap(struct servo *servo, int leap);
+
#endif
diff --git a/servo_private.h b/servo_private.h
index ebb7e3b..9a1a459 100644
--- a/servo_private.h
+++ b/servo_private.h
@@ -38,6 +38,8 @@ struct servo {
void (*reset)(struct servo *servo);

double (*rate_ratio)(struct servo *servo);
+
+ void (*leap)(struct servo *servo, int leap);
};

#endif
--
1.9.3
Miroslav Lichvar
2014-06-20 14:32:51 UTC
Permalink
Always disable the clock sanity check when the ntpshm servo is used,
because it doesn't know when or how is the clock adjusted. Disable also
the kernel leap option as the process controlling the clock is
responsible for setting the kernel flag.

Signed-off-by: Miroslav Lichvar <***@redhat.com>
---
phc2sys.c | 5 +++++
ptp4l.c | 4 ++++
2 files changed, 9 insertions(+)

diff --git a/phc2sys.c b/phc2sys.c
index 4b8051e..87c1749 100644
--- a/phc2sys.c
+++ b/phc2sys.c
@@ -1324,6 +1324,11 @@ int main(int argc, char *argv[])
goto bad_usage;
}

+ if (node.servo_type == CLOCK_SERVO_NTPSHM) {
+ node.kernel_leap = 0;
+ node.sanity_freq_limit = 0;
+ }
+
print_set_progname(progname);
print_set_verbose(verbose);
print_set_syslog(use_syslog);
diff --git a/ptp4l.c b/ptp4l.c
index a33900f..25270c6 100644
--- a/ptp4l.c
+++ b/ptp4l.c
@@ -300,6 +300,10 @@ int main(int argc, char *argv[])
ds->flags & DDS_SLAVE_ONLY) {
ds->clockQuality.clockClass = 255;
}
+ if (cfg_settings.clock_servo == CLOCK_SERVO_NTPSHM) {
+ cfg_settings.dds.kernel_leap = 0;
+ cfg_settings.dds.sanity_freq_limit = 0;
+ }

print_set_progname(progname);
print_set_verbose(cfg_settings.verbose);
--
1.9.3
Miroslav Lichvar
2014-06-20 14:32:50 UTC
Permalink
When leap second is inserted/deleted to the reference time, adjust the
reference point as if the clock was stepped in the opposite direction to
keep the slope and error statistics valid and correct the offset
gracefully.

Signed-off-by: Miroslav Lichvar <***@redhat.com>
---
linreg.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)

diff --git a/linreg.c b/linreg.c
index 4513dd1..b94c44e 100644
--- a/linreg.c
+++ b/linreg.c
@@ -76,6 +76,8 @@ struct linreg_servo {
double update_interval;
/* Current ratio between remote and local frequency */
double frequency_ratio;
+ /* Upcoming leap second */
+ int leap;
};

static void linreg_destroy(struct servo *servo)
@@ -305,6 +307,20 @@ static double linreg_rate_ratio(struct servo *servo)
return s->frequency_ratio;
}

+static void linreg_leap(struct servo *servo, int leap)
+{
+ struct linreg_servo *s = container_of(servo, struct linreg_servo, servo);
+
+ /*
+ * Move reference when leap second is applied to the reference
+ * time as if the clock was stepped in the opposite direction
+ */
+ if (s->leap && !leap)
+ move_reference(s, 0, s->leap * 1000000000);
+
+ s->leap = leap;
+}
+
struct servo *linreg_servo_create(int fadj)
{
struct linreg_servo *s;
@@ -318,6 +334,7 @@ struct servo *linreg_servo_create(int fadj)
s->servo.sync_interval = linreg_sync_interval;
s->servo.reset = linreg_reset;
s->servo.rate_ratio = linreg_rate_ratio;
+ s->servo.leap = linreg_leap;

s->clock_freq = -fadj;
s->frequency_ratio = 1.0;
--
1.9.3
Miroslav Lichvar
2014-06-20 14:32:49 UTC
Permalink
Signed-off-by: Miroslav Lichvar <***@redhat.com>
---
ntpshm.c | 27 ++++++++++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/ntpshm.c b/ntpshm.c
index b6280a5..21a11cf 100644
--- a/ntpshm.c
+++ b/ntpshm.c
@@ -28,6 +28,11 @@

#define NS_PER_SEC 1000000000

+/* NTP leap values */
+#define LEAP_NORMAL 0x0
+#define LEAP_INSERT 0x1
+#define LEAP_DELETE 0x2
+
/* Key of the first SHM segment */
#define SHMKEY 0x4e545030

@@ -61,6 +66,7 @@ struct shmTime {
struct ntpshm_servo {
struct servo servo;
struct shmTime *shm;
+ int leap;
};

static void ntpshm_destroy(struct servo *servo)
@@ -91,7 +97,18 @@ static double ntpshm_sample(struct servo *servo,
s->shm->receiveTimeStampNSec = local_ts % NS_PER_SEC;
s->shm->receiveTimeStampUSec = s->shm->receiveTimeStampNSec / 1000;
s->shm->precision = -30; /* 1 nanosecond */
- s->shm->leap = 0;
+
+ switch (s->leap) {
+ case -1:
+ s->shm->leap = LEAP_DELETE;
+ break;
+ case 1:
+ s->shm->leap = LEAP_INSERT;
+ break;
+ default:
+ s->shm->leap = LEAP_NORMAL;
+ }
+
/* TODO: write memory barrier */

s->shm->count++;
@@ -109,6 +126,13 @@ static void ntpshm_reset(struct servo *servo)
{
}

+static void ntpshm_leap(struct servo *servo, int leap)
+{
+ struct ntpshm_servo *s = container_of(servo, struct ntpshm_servo, servo);
+
+ s->leap = leap;
+}
+
struct servo *ntpshm_servo_create(void)
{
struct ntpshm_servo *s;
@@ -122,6 +146,7 @@ struct servo *ntpshm_servo_create(void)
s->servo.sample = ntpshm_sample;
s->servo.sync_interval = ntpshm_sync_interval;
s->servo.reset = ntpshm_reset;
+ s->servo.leap = ntpshm_leap;

shmid = shmget(SHMKEY + ntpshm_segment, sizeof (struct shmTime),
IPC_CREAT | 0600);
--
1.9.3
Richard Cochran
2014-06-22 08:00:18 UTC
Permalink
This set adds support for leap seconds to the ntpshm servo and the
linreg servo when the kernel leap option is disabled.
Add leap function to servo.
ntpshm: Pass upcoming leap second.
linreg: Handle leap second gracefully.
Disable clockcheck and kernel leap with ntpshm servo.
Series applied.

Thanks,
Richard

Loading...