lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250610171905.4042496-1-cjubran@nvidia.com>
Date: Tue, 10 Jun 2025 20:19:05 +0300
From: Carolina Jubran <cjubran@...dia.com>
To: Richard Cochran <richardcochran@...il.com>, Andrew Lunn
	<andrew+netdev@...n.ch>, "David S. Miller" <davem@...emloft.net>, "Eric
 Dumazet" <edumazet@...gle.com>, Jakub Kicinski <kuba@...nel.org>, Paolo Abeni
	<pabeni@...hat.com>
CC: Gal Pressman <gal@...dia.com>, Tariq Toukan <tariqt@...dia.com>, "Bar
 Shapira" <bshapira@...dia.com>, Maciek Machnikowski <maciejm@...dia.com>,
	Wojtek Wasko <wwasko@...dia.com>, Vinicius Costa Gomes
	<vinicius.gomes@...el.com>, Vadim Fedorenko <vadim.fedorenko@...ux.dev>,
	Mahesh Bandewar <maheshb@...gle.com>, <netdev@...r.kernel.org>,
	<linux-kernel@...r.kernel.org>, Carolina Jubran <cjubran@...dia.com>
Subject: [RFC PATCH] ptp: extend offset ioctls to expose raw free-running cycles

Some telemetry and low-level event logging applications use hardware
timestamps reported in raw cycle counter units. There is currently no
generic way in user space to correlate such raw cycle values with
system time.

This patch adds support for returning the raw free-running counter
value from the device, alongside system timestamps. It introduces a new
flag, PTP_OFFSET_CYCLES, which can be set in PTP_SYS_OFFSET_EXTENDED2
or PTP_SYS_OFFSET_PRECISE2 ioctl calls.

When this flag is set, the driver is expected to return a raw cycle counter
value rather than a nanosecond timestamp. This is useful for offline
correlation and debugging.

This can also be useful in XDP. Some drivers already insert timestamps
into XDP metadata. If we allow them to insert the raw cycle counter
instead of converting it to nanoseconds, this could reduce overhead in
the fast path. The raw value can then be translated in user space using
this ioctl when needed.

While reviewing the current usage of getcyclesx64(), I noticed that
ptp_vclock expects it to return a timestamp as a timespec64 that
represents a nanosecond-based value. This is then passed through
timespec64_to_ns() before being used with timecounter_cyc2time().
However, in the Intel igc driver (igc_ptp_getcyclesx64()), the
timestamp is read directly from hardware registers into tv_sec and
tv_nsec.

Is this value already formatted as a proper nanosecond-based timestamp,
or is it a raw hardware format? Just wondering if this is expected
behavior, or if it might be a bug?

We’ll appreciate any feedback.

Signed-off-by: Carolina Jubran <cjubran@...dia.com>
---
 drivers/ptp/ptp_chardev.c      | 41 +++++++++++++++++++++++++++++-----
 include/uapi/linux/ptp_clock.h | 41 +++++++++++++++++++++++++++++-----
 2 files changed, 72 insertions(+), 10 deletions(-)

diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c
index 4bf421765d03..c810b694de11 100644
--- a/drivers/ptp/ptp_chardev.c
+++ b/drivers/ptp/ptp_chardev.c
@@ -176,6 +176,7 @@ long ptp_ioctl(struct posix_clock_context *pccontext, unsigned int cmd,
 	struct ptp_pin_desc pd;
 	struct timespec64 ts;
 	int enable, err = 0;
+	bool cycles;
 
 	if (in_compat_syscall() && cmd != PTP_ENABLE_PPS && cmd != PTP_ENABLE_PPS2)
 		arg = (unsigned long)compat_ptr(arg);
@@ -354,11 +355,30 @@ long ptp_ioctl(struct posix_clock_context *pccontext, unsigned int cmd,
 
 	case PTP_SYS_OFFSET_PRECISE:
 	case PTP_SYS_OFFSET_PRECISE2:
-		if (!ptp->info->getcrosststamp) {
+		if (!ptp->info->getcrosststamp || !ptp->info->getcrosscycles) {
 			err = -EOPNOTSUPP;
 			break;
 		}
-		err = ptp->info->getcrosststamp(ptp->info, &xtstamp);
+		if (copy_from_user(&precise_offset, (void __user *)arg,
+				   sizeof(precise_offset))) {
+			err = -EFAULT;
+			break;
+		}
+
+		if ((cmd == PTP_SYS_OFFSET_PRECISE2 &&
+		    (precise_offset.rsv[0] & ~PTP_OFFSET_PRECISE_VALID_FLAGS)) ||
+		    (cmd == PTP_SYS_OFFSET_PRECISE &&
+		    (precise_offset.rsv[0] & ~PTP_OFFSET_PRECISE_V1_VALID_FLAGS)) ||
+		    precise_offset.rsv[1]) {
+			err = -EINVAL;
+			break;
+		}
+
+		cycles = !!(precise_offset.rsv[0] & PTP_OFFSET_CYCLES);
+		if (cycles)
+			err = ptp->info->getcrosscycles(ptp->info, &xtstamp);
+		else
+			err = ptp->info->getcrosststamp(ptp->info, &xtstamp);
 		if (err)
 			break;
 
@@ -379,7 +399,7 @@ long ptp_ioctl(struct posix_clock_context *pccontext, unsigned int cmd,
 
 	case PTP_SYS_OFFSET_EXTENDED:
 	case PTP_SYS_OFFSET_EXTENDED2:
-		if (!ptp->info->gettimex64) {
+		if (!ptp->info->gettimex64 || !ptp->info->getcyclesx64) {
 			err = -EOPNOTSUPP;
 			break;
 		}
@@ -389,8 +409,13 @@ long ptp_ioctl(struct posix_clock_context *pccontext, unsigned int cmd,
 			extoff = NULL;
 			break;
 		}
+
 		if (extoff->n_samples > PTP_MAX_SAMPLES ||
-		    extoff->rsv[0] || extoff->rsv[1] ||
+		    (cmd == PTP_SYS_OFFSET_EXTENDED2 &&
+		     (extoff->rsv[0] & ~PTP_OFFSET_EXTENDED_VALID_FLAGS)) ||
+		    (cmd == PTP_SYS_OFFSET_EXTENDED &&
+		     (extoff->rsv[0] & ~PTP_OFFSET_EXTENDED_V1_VALID_FLAGS)) ||
+		    extoff->rsv[1] ||
 		    (extoff->clockid != CLOCK_REALTIME &&
 		     extoff->clockid != CLOCK_MONOTONIC &&
 		     extoff->clockid != CLOCK_MONOTONIC_RAW)) {
@@ -398,8 +423,14 @@ long ptp_ioctl(struct posix_clock_context *pccontext, unsigned int cmd,
 			break;
 		}
 		sts.clockid = extoff->clockid;
+		cycles = !!(extoff->rsv[0] & PTP_OFFSET_CYCLES);
 		for (i = 0; i < extoff->n_samples; i++) {
-			err = ptp->info->gettimex64(ptp->info, &ts, &sts);
+			if (cycles)
+				err = ptp->info->getcyclesx64(ptp->info, &ts,
+							      &sts);
+			else
+				err = ptp->info->gettimex64(ptp->info, &ts,
+							    &sts);
 			if (err)
 				goto out;
 			extoff->ts[i][0].sec = sts.pre_ts.tv_sec;
diff --git a/include/uapi/linux/ptp_clock.h b/include/uapi/linux/ptp_clock.h
index 18eefa6d93d6..eaf58e17fdb4 100644
--- a/include/uapi/linux/ptp_clock.h
+++ b/include/uapi/linux/ptp_clock.h
@@ -25,6 +25,31 @@
 #include <linux/ioctl.h>
 #include <linux/types.h>
 
+/*
+ * Bits of the ptp_sys_offset.flags field:
+ */
+#define PTP_OFFSET_CYCLES  (1<<0)  /* Use cycles instead of timestamps */
+
+/*
+ * flag fields valid for the PTP_SYS_OFFSET_EXTENDED2 ioctl.
+ */
+#define PTP_OFFSET_EXTENDED_VALID_FLAGS	(PTP_OFFSET_CYCLES)
+
+/*
+ * No flags are valid for the original PTP_SYS_OFFSET_EXTENDED ioctl
+ */
+#define PTP_OFFSET_EXTENDED_V1_VALID_FLAGS	(0)
+
+/*
+ * flag fields valid for the PTP_SYS_OFFSET_PRECISE2 ioctl.
+ */
+#define PTP_OFFSET_PRECISE_VALID_FLAGS	(PTP_OFFSET_CYCLES)
+
+/*
+ * No flags are valid for the original PTP_SYS_OFFSET_PRECISE ioctl
+ */
+#define PTP_OFFSET_PRECISE_V1_VALID_FLAGS	(0)
+
 /*
  * Bits of the ptp_extts_request.flags field:
  */
@@ -86,9 +111,15 @@
  *
  */
 struct ptp_clock_time {
-	__s64 sec;  /* seconds */
-	__u32 nsec; /* nanoseconds */
-	__u32 reserved;
+	union {
+		struct {
+			__s64 sec;  /* seconds */
+			__u32 nsec; /* nanoseconds */
+			__u32 reserved;
+		};
+		__u64 cycles;
+	};
+
 };
 
 struct ptp_clock_caps {
@@ -173,7 +204,7 @@ struct ptp_sys_offset {
 struct ptp_sys_offset_extended {
 	unsigned int n_samples;
 	__kernel_clockid_t clockid;
-	unsigned int rsv[2];
+	unsigned int rsv[2];    /* rsv[0] is used for PTP_OFFSET_FLAG_CYCLES */
 	struct ptp_clock_time ts[PTP_MAX_SAMPLES][3];
 };
 
@@ -181,7 +212,7 @@ struct ptp_sys_offset_precise {
 	struct ptp_clock_time device;
 	struct ptp_clock_time sys_realtime;
 	struct ptp_clock_time sys_monoraw;
-	unsigned int rsv[4];    /* Reserved for future use. */
+	unsigned int rsv[4];    /* rsv[0] is used for PTP_OFFSET_FLAG_CYCLES */
 };
 
 enum ptp_pin_function {
-- 
2.38.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ