[PATCH 03/13] cobalt/clock: pipeline: abstract access to host (real)time

Philippe Gerum rpm at xenomai.org
Sun Jan 31 15:45:30 CET 2021


From: Philippe Gerum <rpm at xenomai.org>

Dovetail enables applications to get timestamps from the
CLOCK_MONOTONIC and CLOCK_REALTIME clocks via the regular vDSO by
calling clock_gettime(), including from the out-of-band stage
(i.e. primary mode).

Legacy support involving IPIPE_HOSTRT can move to the I-pipe specific
section.

No functional change is introduced.

Signed-off-by: Philippe Gerum <rpm at xenomai.org>
---
 include/cobalt/kernel/ipipe/pipeline/clock.h |  4 ++
 include/cobalt/uapi/kernel/vdso.h            |  5 ++
 kernel/cobalt/ipipe/Makefile                 |  2 +-
 kernel/cobalt/ipipe/clock.c                  | 62 ++++++++++++++++++++
 kernel/cobalt/posix/clock.c                  | 57 +-----------------
 5 files changed, 73 insertions(+), 57 deletions(-)
 create mode 100644 kernel/cobalt/ipipe/clock.c

diff --git a/include/cobalt/kernel/ipipe/pipeline/clock.h b/include/cobalt/kernel/ipipe/pipeline/clock.h
index c607d9585..eeeae6602 100644
--- a/include/cobalt/kernel/ipipe/pipeline/clock.h
+++ b/include/cobalt/kernel/ipipe/pipeline/clock.h
@@ -7,6 +7,8 @@
 
 #include <linux/ipipe_tickdev.h>
 
+struct timespec;
+
 static inline u64 pipeline_read_cycle_counter(void)
 {
 	u64 t;
@@ -29,4 +31,6 @@ static inline const char *pipeline_clock_name(void)
 	return ipipe_clock_name();
 }
 
+int pipeline_get_host_time(struct timespec *tp);
+
 #endif /* !_COBALT_KERNEL_IPIPE_CLOCK_H */
diff --git a/include/cobalt/uapi/kernel/vdso.h b/include/cobalt/uapi/kernel/vdso.h
index 396594bb0..5b9b1b66b 100644
--- a/include/cobalt/uapi/kernel/vdso.h
+++ b/include/cobalt/uapi/kernel/vdso.h
@@ -20,6 +20,11 @@
 
 #include <cobalt/uapi/kernel/urw.h>
 
+/*
+ * I-pipe only. Dovetail enables the common vDSO for getting
+ * CLOCK_REALTIME timestamps from the out-of-band stage
+ * (XNVDSO_FEAT_HOST_REALTIME is cleared in this case).
+ */
 struct xnvdso_hostrt_data {
 	__u64 wall_sec;
 	__u64 wtom_sec;
diff --git a/kernel/cobalt/ipipe/Makefile b/kernel/cobalt/ipipe/Makefile
index eae6a4a7c..f2b877d45 100644
--- a/kernel/cobalt/ipipe/Makefile
+++ b/kernel/cobalt/ipipe/Makefile
@@ -2,4 +2,4 @@ ccflags-y += -I$(srctree)/kernel
 
 obj-y +=	pipeline.o
 
-pipeline-y :=	init.o intr.o kevents.o tick.o syscall.o sched.o
+pipeline-y :=	init.o intr.o kevents.o tick.o syscall.o sched.o clock.o
diff --git a/kernel/cobalt/ipipe/clock.c b/kernel/cobalt/ipipe/clock.c
new file mode 100644
index 000000000..d0135dc7a
--- /dev/null
+++ b/kernel/cobalt/ipipe/clock.c
@@ -0,0 +1,62 @@
+/*
+ * SPDX-License-Identifier: GPL-2.0
+ *
+ * Written by Gilles Chanteperdrix <gilles.chanteperdrix at xenomai.org>.
+ */
+
+#include <cobalt/kernel/clock.h>
+#include <cobalt/kernel/vdso.h>
+
+int pipeline_get_host_time(struct timespec *tp)
+{
+#ifdef CONFIG_IPIPE_HAVE_HOSTRT
+	struct xnvdso_hostrt_data *hostrt_data;
+	u64 now, base, mask, cycle_delta;
+	__u32 mult, shift;
+	unsigned long rem;
+	urwstate_t tmp;
+	__u64 nsec;
+
+	hostrt_data = get_hostrt_data();
+	BUG_ON(!hostrt_data);
+
+	if (unlikely(!hostrt_data->live))
+		return -1;
+
+	/*
+	 * Note: Disabling HW interrupts around writes to hostrt_data
+	 * ensures that a reader (on the Xenomai side) cannot
+	 * interrupt a writer (on the Linux kernel side) on the same
+	 * CPU.  The urw block is required when a reader is
+	 * interleaved by a writer on a different CPU. This follows
+	 * the approach from userland, where taking the spinlock is
+	 * not possible.
+	 */
+	unsynced_read_block(&tmp, &hostrt_data->lock) {
+		now = xnclock_read_raw(&nkclock);
+		base = hostrt_data->cycle_last;
+		mask = hostrt_data->mask;
+		mult = hostrt_data->mult;
+		shift = hostrt_data->shift;
+		tp->tv_sec = hostrt_data->wall_sec;
+		nsec = hostrt_data->wall_nsec;
+	}
+
+	/*
+	 * At this point, we have a consistent copy of the fundamental
+	 * data structure - calculate the interval between the current
+	 * and base time stamp cycles, and convert the difference
+	 * to nanoseconds.
+	 */
+	cycle_delta = (now - base) & mask;
+	nsec += (cycle_delta * mult) >> shift;
+
+	/* Convert to the desired sec, usec representation */
+	tp->tv_sec += xnclock_divrem_billion(nsec, &rem);
+	tp->tv_nsec = rem;
+
+	return 0;
+#else
+	return -EINVAL;
+#endif
+}
diff --git a/kernel/cobalt/posix/clock.c b/kernel/cobalt/posix/clock.c
index 40271f3ed..e957dd956 100644
--- a/kernel/cobalt/posix/clock.c
+++ b/kernel/cobalt/posix/clock.c
@@ -18,7 +18,6 @@
 
 #include <linux/clocksource.h>
 #include <linux/bitmap.h>
-#include <cobalt/kernel/vdso.h>
 #include <cobalt/kernel/clock.h>
 #include "internal.h"
 #include "thread.h"
@@ -29,60 +28,6 @@ static struct xnclock *external_clocks[COBALT_MAX_EXTCLOCKS];
 
 DECLARE_BITMAP(cobalt_clock_extids, COBALT_MAX_EXTCLOCKS);
 
-static int do_clock_host_realtime(struct timespec *tp)
-{
-#ifdef CONFIG_IPIPE_HAVE_HOSTRT
-	struct xnvdso_hostrt_data *hostrt_data;
-	u64 now, base, mask, cycle_delta;
-	__u32 mult, shift;
-	unsigned long rem;
-	urwstate_t tmp;
-	__u64 nsec;
-
-	hostrt_data = get_hostrt_data();
-	BUG_ON(!hostrt_data);
-
-	if (unlikely(!hostrt_data->live))
-		return -1;
-
-	/*
-	 * Note: Disabling HW interrupts around writes to hostrt_data
-	 * ensures that a reader (on the Xenomai side) cannot
-	 * interrupt a writer (on the Linux kernel side) on the same
-	 * CPU.  The urw block is required when a reader is
-	 * interleaved by a writer on a different CPU. This follows
-	 * the approach from userland, where taking the spinlock is
-	 * not possible.
-	 */
-	unsynced_read_block(&tmp, &hostrt_data->lock) {
-		now = xnclock_read_raw(&nkclock);
-		base = hostrt_data->cycle_last;
-		mask = hostrt_data->mask;
-		mult = hostrt_data->mult;
-		shift = hostrt_data->shift;
-		tp->tv_sec = hostrt_data->wall_sec;
-		nsec = hostrt_data->wall_nsec;
-	}
-
-	/*
-	 * At this point, we have a consistent copy of the fundamental
-	 * data structure - calculate the interval between the current
-	 * and base time stamp cycles, and convert the difference
-	 * to nanoseconds.
-	 */
-	cycle_delta = (now - base) & mask;
-	nsec += (cycle_delta * mult) >> shift;
-
-	/* Convert to the desired sec, usec representation */
-	tp->tv_sec += xnclock_divrem_billion(nsec, &rem);
-	tp->tv_nsec = rem;
-
-	return 0;
-#else
-	return -EINVAL;
-#endif
-}
-
 #define do_ext_clock(__clock_id, __handler, __ret, __args...)	\
 ({								\
 	struct xnclock *__clock;				\
@@ -161,7 +106,7 @@ int __cobalt_clock_gettime(clockid_t clock_id, struct timespec *ts)
 		ns2ts(ts, xnclock_read_monotonic(&nkclock));
 		break;
 	case CLOCK_HOST_REALTIME:
-		if (do_clock_host_realtime(ts) != 0)
+		if (pipeline_get_host_time(ts) != 0)
 			return -EINVAL;
 		break;
 	default:
-- 
2.26.2




More information about the Xenomai mailing list