Commit d3d5592b authored by Philippe Gerum's avatar Philippe Gerum Committed by Jan Kiszka

cobalt/clock: pipeline: abstract access to host (real)time

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's avatarPhilippe Gerum <rpm@xenomai.org>
Signed-off-by: Jan Kiszka's avatarJan Kiszka <jan.kiszka@siemens.com>
parent d0f63400
......@@ -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 */
......@@ -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;
......
......@@ -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
/*
* SPDX-License-Identifier: GPL-2.0
*
* Written by Gilles Chanteperdrix <gilles.chanteperdrix@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
}
......@@ -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:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment