linux-arch.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Thomas Weißschuh" <thomas.weissschuh@linutronix.de>
To: Andy Lutomirski <luto@kernel.org>,
	Thomas Gleixner <tglx@linutronix.de>,
	 Vincenzo Frascino <vincenzo.frascino@arm.com>,
	 Shuah Khan <shuah@kernel.org>,
	 Anna-Maria Behnsen <anna-maria@linutronix.de>,
	 Frederic Weisbecker <frederic@kernel.org>,
	John Stultz <jstultz@google.com>,
	 Stephen Boyd <sboyd@kernel.org>,
	Catalin Marinas <catalin.marinas@arm.com>,
	 Will Deacon <will@kernel.org>, Arnd Bergmann <arnd@arndb.de>
Cc: linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, linux-arch@vger.kernel.org,
	"Richard Cochran" <richardcochran@gmail.com>,
	"Christopher Hall" <christopher.s.hall@intel.com>,
	"Frederic Weisbecker" <frederic@kernel.org>,
	"Anna-Maria Behnsen" <anna-maria@linutronix.de>,
	"Miroslav Lichvar" <mlichvar@redhat.com>,
	"Werner Abt" <werner.abt@meinberg-usa.com>,
	"David Woodhouse" <dwmw2@infradead.org>,
	"Stephen Boyd" <sboyd@kernel.org>,
	"Kurt Kanzenbach" <kurt@linutronix.de>,
	"Nam Cao" <namcao@linutronix.de>,
	"Antoine Tenart" <atenart@kernel.org>,
	"Thomas Weißschuh" <thomas.weissschuh@linutronix.de>
Subject: [PATCH 01/14] selftests/timers: Add testcase for auxiliary clocks
Date: Tue, 01 Jul 2025 10:57:55 +0200	[thread overview]
Message-ID: <20250701-vdso-auxclock-v1-1-df7d9f87b9b8@linutronix.de> (raw)
In-Reply-To: <20250701-vdso-auxclock-v1-0-df7d9f87b9b8@linutronix.de>

Auxiliary clocks behave differently from regular ones.
Add a testcase to validate their functionality.

Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
---
 tools/testing/selftests/timers/.gitignore |   1 +
 tools/testing/selftests/timers/Makefile   |   2 +-
 tools/testing/selftests/timers/auxclock.c | 319 ++++++++++++++++++++++++++++++
 3 files changed, 321 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/timers/.gitignore b/tools/testing/selftests/timers/.gitignore
index bb5326ff900b8edc3aa2d8d596599973593fbaf0..dcee43b3ecd9351c9bb0483088d712ccd7b57367 100644
--- a/tools/testing/selftests/timers/.gitignore
+++ b/tools/testing/selftests/timers/.gitignore
@@ -20,3 +20,4 @@ valid-adjtimex
 adjtick
 set-tz
 freq-step
+auxclock
diff --git a/tools/testing/selftests/timers/Makefile b/tools/testing/selftests/timers/Makefile
index 32203593c62e1e0cdfd3de6f567ea1e82913f2ef..3a8833b3fb7449495c66a92c4d82e35a6755b5e8 100644
--- a/tools/testing/selftests/timers/Makefile
+++ b/tools/testing/selftests/timers/Makefile
@@ -5,7 +5,7 @@ LDLIBS += -lrt -lpthread -lm
 # these are all "safe" tests that don't modify
 # system time or require escalated privileges
 TEST_GEN_PROGS = posix_timers nanosleep nsleep-lat set-timer-lat mqueue-lat \
-	     inconsistency-check raw_skew threadtest rtcpie
+	     inconsistency-check raw_skew threadtest rtcpie auxclock
 
 DESTRUCTIVE_TESTS = alarmtimer-suspend valid-adjtimex adjtick change_skew \
 		      skew_consistency clocksource-switch freq-step leap-a-day \
diff --git a/tools/testing/selftests/timers/auxclock.c b/tools/testing/selftests/timers/auxclock.c
new file mode 100644
index 0000000000000000000000000000000000000000..0ba2f9996114ade3147f0f3aec49904556a23cd4
--- /dev/null
+++ b/tools/testing/selftests/timers/auxclock.c
@@ -0,0 +1,319 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/* Work around type conflicts between libc and the UAPI headers */
+#define _SYS_TIME_H
+#define __timeval_defined
+#define _GNU_SOURCE
+
+#include <fcntl.h>
+#include <linux/types.h>
+#include <linux/timex.h>
+#include <sched.h>
+#include <stdio.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#include "../kselftest_harness.h"
+
+#ifndef CLOCK_AUX
+#define	CLOCK_AUX	16
+#endif
+
+#ifndef NSEC_PER_SEC
+#define NSEC_PER_SEC 1000000000ULL
+#endif
+
+#define AUXCLOCK_SELFTEST_TIMENS_OFFSET 10000
+
+static int configure_auxclock(__kernel_clockid_t clockid, bool enable)
+{
+	char path[100];
+	int fd, ret;
+
+	ret = snprintf(path, sizeof(path),
+		       "/sys/kernel/time/aux_clocks/%d/aux_clock_enable",
+		       (int)clockid - CLOCK_AUX);
+	if (ret >= sizeof(path))
+		return -ENOSPC;
+
+	fd = open(path, O_WRONLY);
+	if (fd == -1)
+		return -errno;
+
+	/* Always disable to reset */
+	ret = dprintf(fd, "0\n");
+	if (enable)
+		ret = dprintf(fd, "1\n");
+	close(fd);
+
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+/* Everything is done in terms of 64bit time values to keep the code readable */
+
+static inline void timespec_to_kernel_timespec(const struct timespec *ts,
+					       struct __kernel_timespec *kts)
+{
+	if (!kts)
+		return;
+
+	kts->tv_sec = ts->tv_sec;
+	kts->tv_nsec = ts->tv_nsec;
+}
+
+static inline void kernel_timespec_to_timespec(const struct __kernel_timespec *kts,
+					       struct timespec *ts)
+{
+	if (!kts)
+		return;
+
+	ts->tv_sec = kts->tv_sec;
+	ts->tv_nsec = kts->tv_nsec;
+}
+
+static int sys_clock_getres_time64(__kernel_clockid_t clockid, struct __kernel_timespec *ts)
+{
+#if defined(__NR_clock_getres_time64)
+	return syscall(__NR_clock_getres_time64, clockid, ts);
+#elif defined(__NR_clock_getres)
+	struct timespec _ts;
+	int ret;
+
+	ret = syscall(__NR_clock_getres, clockid, &_ts);
+	if (!ret)
+		timespec_to_kernel_timespec(&_ts, ts);
+	return ret;
+#else
+#error "No clock_getres() support"
+#endif
+}
+
+static int sys_clock_gettime64(__kernel_clockid_t clockid, struct __kernel_timespec *ts)
+{
+#if defined(__NR_clock_gettime64)
+	return syscall(__NR_clock_gettime64, clockid, ts);
+#elif defined(__NR_clock_gettime)
+	struct timespec _ts;
+	int ret;
+
+	ret = syscall(__NR_clock_gettime, clockid, &_ts);
+	if (!ret)
+		timespec_to_kernel_timespec(&_ts, ts);
+	return ret;
+#else
+#error "No clock_gettime() support"
+#endif
+}
+
+static int sys_clock_settime64(__kernel_clockid_t clockid, const struct __kernel_timespec *ts)
+{
+#if defined(__NR_clock_settime64)
+	return syscall(__NR_clock_settime64, clockid, ts);
+#elif defined(__NR_clock_settime)
+	struct timespec _ts;
+
+	kernel_timespec_to_timespec(ts, &_ts);
+	return syscall(__NR_clock_settime, clockid, &_ts);
+#else
+#error "No clock_settime() support"
+#endif
+}
+
+static int sys_clock_adjtime64(__kernel_clockid_t clockid, struct __kernel_timex *tx)
+{
+#if defined(__NR_clock_adjtime64)
+	return syscall(__NR_clock_adjtime64, clockid, tx);
+#elif __LONG_WIDTH__ == 64 && defined(__NR_clock_adjtime)
+	return syscall(__NR_clock_adjtime, clockid, tx);
+#else
+#error "No clock_adjtime() support"
+#endif
+}
+
+FIXTURE(auxclock) {};
+
+FIXTURE_VARIANT(auxclock) {
+	__kernel_clockid_t clock;
+	bool clock_enabled;
+	bool use_timens;
+};
+
+FIXTURE_VARIANT_ADD(auxclock, default) {
+	.clock		= CLOCK_AUX,
+	.clock_enabled	= true,
+	.use_timens	= false,
+};
+
+FIXTURE_VARIANT_ADD(auxclock, timens) {
+	.clock		= CLOCK_AUX,
+	.clock_enabled	= true,
+	.use_timens	= true,
+};
+
+FIXTURE_VARIANT_ADD(auxclock, disabled) {
+	.clock		= CLOCK_AUX,
+	.clock_enabled	= false,
+	.use_timens	= false,
+};
+
+/* No timens_disabled to keep the testmatrix smaller. */
+
+static void enter_timens(struct __test_metadata *_metadata)
+{
+	int ret, fd;
+	char buf[100];
+
+	ret = unshare(CLONE_NEWTIME);
+	if (ret != 0 && errno == EPERM)
+		SKIP(return, "no permissions for unshare(CLONE_NEWTIME)");
+	if (ret != 0 && errno == EINVAL)
+		SKIP(return, "time namespaces not available");
+	ASSERT_EQ(0, ret) TH_LOG("unshare(CLONE_NEWTIME) failed: %s", strerror(errno));
+	fd = open("/proc/self/timens_offsets", O_WRONLY);
+	if (fd == -1 && errno == ENOENT)
+		SKIP(return, "no support for time namespaces");
+	ASSERT_NE(-1, fd);
+	/* Fiddle with the namespace to make the tests more meaningful */
+	ret = snprintf(buf, sizeof(buf), "monotonic %d 0\nboottime %d 0\n",
+		       AUXCLOCK_SELFTEST_TIMENS_OFFSET, AUXCLOCK_SELFTEST_TIMENS_OFFSET);
+	ASSERT_TRUE(ret > 0 && ret < sizeof(buf));
+	ret = write(fd, buf, ret);
+	ASSERT_NE(-1, ret);
+	close(fd);
+	fd = open("/proc/self/ns/time_for_children", O_RDONLY);
+	ASSERT_NE(-1, fd);
+	ret = setns(fd, CLONE_NEWTIME);
+	close(fd);
+	ASSERT_EQ(0, ret);
+}
+
+FIXTURE_SETUP(auxclock) {
+	int ret;
+
+	ret = configure_auxclock(variant->clock, variant->clock_enabled);
+	if (ret == -ENOENT)
+		SKIP(return, "auxclocks not enabled");
+	ASSERT_EQ(0, ret);
+
+	if (variant->use_timens)
+		enter_timens(_metadata);
+}
+
+FIXTURE_TEARDOWN(auxclock) {
+	int ret;
+
+	ret = configure_auxclock(variant->clock, false);
+	ASSERT_EQ(0, ret);
+}
+
+TEST_F(auxclock, sys_clock_getres) {
+	struct __kernel_timespec ts;
+	int ret;
+
+	/* clock_getres() is always expected to work */
+	ret = sys_clock_getres_time64(variant->clock, &ts);
+	ASSERT_EQ(0, ret);
+	ASSERT_EQ(0, ts.tv_sec);
+	ASSERT_EQ(1, ts.tv_nsec);
+}
+
+TEST_F(auxclock, sys_clock_gettime) {
+	struct __kernel_timespec ts;
+	int ret;
+
+	ret = sys_clock_gettime64(variant->clock, &ts);
+	if (variant->clock_enabled) {
+		ASSERT_EQ(0, ret);
+	} else {
+		ASSERT_EQ(-1, ret);
+		ASSERT_EQ(ENODEV, errno);
+	}
+}
+
+static void auxclock_validate_progression(struct __test_metadata *_metadata,
+					  const struct __kernel_timespec *a,
+					  const struct __kernel_timespec *b)
+{
+	int64_t diff;
+
+	diff = (b->tv_sec - a->tv_sec) * NSEC_PER_SEC;
+	diff += b->tv_nsec - a->tv_nsec;
+
+	/* Arbitrary values */
+	ASSERT_LT(1, diff);
+	ASSERT_GT(1 * NSEC_PER_SEC, diff);
+}
+
+TEST_F(auxclock, sys_clock_settime) {
+	struct __kernel_timespec a, b = {};
+	int ret;
+
+	a.tv_sec = 1234;
+	a.tv_nsec = 5678;
+
+	ret = sys_clock_settime64(variant->clock, &a);
+	if (!variant->clock_enabled) {
+		ASSERT_EQ(-1, ret);
+		ASSERT_EQ(ENODEV, errno);
+		return;
+	}
+
+	ASSERT_EQ(0, ret);
+
+	ret = sys_clock_gettime64(variant->clock, &b);
+	ASSERT_EQ(0, ret);
+
+	auxclock_validate_progression(_metadata, &a, &b);
+}
+
+TEST_F(auxclock, sys_clock_adjtime) {
+	struct __kernel_timex tx;
+	int ret, realtime_freq;
+
+	memset(&tx, 0, sizeof(tx));
+	tx.modes = ADJ_FREQUENCY;
+	ret = sys_clock_adjtime64(CLOCK_REALTIME, &tx);
+	ASSERT_NE(-1, ret);
+	ASSERT_TRUE(tx.modes & ADJ_FREQUENCY);
+	realtime_freq = tx.freq;
+
+	ret = sys_clock_adjtime64(variant->clock, &tx);
+	if (variant->clock_enabled) {
+		ASSERT_NE(-1, ret);
+		ASSERT_EQ(realtime_freq, tx.freq);
+	} else {
+		ASSERT_EQ(-1, ret);
+		ASSERT_EQ(ENODEV, errno);
+	}
+}
+
+TEST_F(auxclock, progression) {
+	struct __kernel_timespec a, b;
+	int ret;
+
+	if (!variant->clock_enabled) {
+		TH_LOG("no progression on disabled clocks");
+		return;
+	}
+
+	/* set up reference */
+	ret = sys_clock_gettime64(variant->clock, &a);
+	ASSERT_EQ(0, ret);
+
+	for (int i = 0; i < 100; i++) {
+		memset(&b, 0, sizeof(b));
+		ret = sys_clock_gettime64(variant->clock, &b);
+		ASSERT_EQ(0, ret);
+		auxclock_validate_progression(_metadata, &a, &b);
+
+		memset(&a, 0, sizeof(a));
+		ret = sys_clock_gettime64(variant->clock, &a);
+		ASSERT_EQ(0, ret);
+		auxclock_validate_progression(_metadata, &b, &a);
+	}
+}
+
+TEST_HARNESS_MAIN

-- 
2.50.0


  reply	other threads:[~2025-07-01  8:58 UTC|newest]

Thread overview: 39+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-07-01  8:57 [PATCH 00/14] vdso: Add support for auxiliary clocks Thomas Weißschuh
2025-07-01  8:57 ` Thomas Weißschuh [this message]
2025-07-01  8:57 ` [PATCH 02/14] vdso/vsyscall: Introduce a helper to fill clock configurations Thomas Weißschuh
2025-07-01  8:57 ` [PATCH 03/14] vdso/vsyscall: Split up __arch_update_vsyscall() into __arch_update_vdso_clock() Thomas Weißschuh
2025-07-01  8:57 ` [PATCH 04/14] vdso/helpers: Add helpers for seqlocks of single vdso_clock Thomas Weißschuh
2025-07-01  8:57 ` [PATCH 05/14] vdso/gettimeofday: Return bool from clock_getres() helpers Thomas Weißschuh
2025-07-01  8:58 ` [PATCH 06/14] vdso/gettimeofday: Return bool from clock_gettime() helpers Thomas Weißschuh
     [not found]   ` <CGME20250708151720eucas1p260f984fd95d3460d3e9f6c9b48e0e25c@eucas1p2.samsung.com>
2025-07-08 15:17     ` Marek Szyprowski
     [not found]       ` <CGME20250708154921eucas1p1fd8fa4374610a991ca5c67bd612ca0c2@eucas1p1.samsung.com>
2025-07-08 15:49         ` Marek Szyprowski
2025-07-09  7:34           ` Thomas Weißschuh
2025-07-09  8:04             ` Marek Szyprowski
2025-07-16 12:25               ` Mark Brown
2025-07-16 12:34                 ` Thomas Weißschuh
2025-07-16 12:50                   ` Mark Brown
2025-07-16 13:23                     ` Thomas Weißschuh
2025-07-16 14:35                       ` Mark Brown
2025-07-18 12:02                         ` Thomas Weißschuh
2025-07-19 11:16                         ` David Laight
2025-07-09  8:29   ` Mark Brown
2025-07-01  8:58 ` [PATCH 07/14] vdso/gettimeofday: Introduce vdso_clockid_valid() Thomas Weißschuh
2025-07-01  8:58 ` [PATCH 08/14] vdso/gettimeofday: Introduce vdso_set_timespec() Thomas Weißschuh
2025-07-01  8:58 ` [PATCH 09/14] vdso/gettimeofday: Introduce vdso_get_timestamp() Thomas Weißschuh
2025-07-01  8:58 ` [PATCH 10/14] vdso: Introduce aux_clock_resolution_ns() Thomas Weißschuh
2025-07-01  8:58 ` [PATCH 11/14] vdso/vsyscall: Update auxiliary clock data in the datapage Thomas Weißschuh
2025-07-07  6:57   ` Thomas Gleixner
2025-07-07 11:34     ` Arnd Bergmann
2025-07-07 13:16       ` Thomas Gleixner
2025-07-07 14:48         ` Arnd Bergmann
2025-07-01  8:58 ` [PATCH 12/14] vdso/gettimeofday: Add support for auxiliary clocks Thomas Weißschuh
2025-07-06 19:31   ` Thomas Gleixner
2025-08-20  8:03   ` John Stultz
2025-08-20 10:15     ` Thomas Weißschuh
2025-07-01  8:58 ` [PATCH 13/14] Revert "selftests: vDSO: parse_vdso: Use UAPI headers instead of libc headers" Thomas Weißschuh
2025-07-06 20:43   ` Thomas Gleixner
2025-07-07  6:21     ` Thomas Weißschuh
2025-07-01  8:58 ` [PATCH 14/14] selftests/timers/auxclock: Test vDSO functionality Thomas Weißschuh
2025-07-06 20:26   ` Thomas Gleixner
2025-07-07  7:17     ` Thomas Weißschuh
2025-07-07 13:18       ` Thomas Gleixner

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250701-vdso-auxclock-v1-1-df7d9f87b9b8@linutronix.de \
    --to=thomas.weissschuh@linutronix.de \
    --cc=anna-maria@linutronix.de \
    --cc=arnd@arndb.de \
    --cc=atenart@kernel.org \
    --cc=catalin.marinas@arm.com \
    --cc=christopher.s.hall@intel.com \
    --cc=dwmw2@infradead.org \
    --cc=frederic@kernel.org \
    --cc=jstultz@google.com \
    --cc=kurt@linutronix.de \
    --cc=linux-arch@vger.kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=luto@kernel.org \
    --cc=mlichvar@redhat.com \
    --cc=namcao@linutronix.de \
    --cc=richardcochran@gmail.com \
    --cc=sboyd@kernel.org \
    --cc=shuah@kernel.org \
    --cc=tglx@linutronix.de \
    --cc=vincenzo.frascino@arm.com \
    --cc=werner.abt@meinberg-usa.com \
    --cc=will@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).