Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ptp/ioctl: support MONOTONIC{,_RAW} timestamps for PTP_SYS_OFFSET_EXTENDED

The ability to read the PHC (Physical Hardware Clock) alongside
multiple system clocks is currently dependent on the specific
hardware architecture. This limitation restricts the use of
PTP_SYS_OFFSET_PRECISE to certain hardware configurations.

The generic soultion which would work across all architectures
is to read the PHC along with the latency to perform PHC-read as
offered by PTP_SYS_OFFSET_EXTENDED which provides pre and post
timestamps. However, these timestamps are currently limited
to the CLOCK_REALTIME timebase. Since CLOCK_REALTIME is affected
by NTP (or similar time synchronization services), it can
experience significant jumps forward or backward. This hinders
the precise latency measurements that PTP_SYS_OFFSET_EXTENDED
is designed to provide.

This problem could be addressed by supporting MONOTONIC_RAW
timestamps within PTP_SYS_OFFSET_EXTENDED. Unlike CLOCK_REALTIME
or CLOCK_MONOTONIC, the MONOTONIC_RAW timebase is unaffected
by NTP adjustments.

This enhancement can be implemented by utilizing one of the three
reserved words within the PTP_SYS_OFFSET_EXTENDED struct to pass
the clock-id for timestamps. The current behavior aligns with
clock-id for CLOCK_REALTIME timebase (value of 0), ensuring
backward compatibility of the UAPI.

Signed-off-by: Mahesh Bandewar <maheshb@google.com>
Signed-off-by: Vadim Fedorenko <vadfed@meta.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Mahesh Bandewar and committed by
David S. Miller
c259acab d5c45460

+56 -12
+6 -2
drivers/ptp/ptp_chardev.c
··· 359 359 extoff = NULL; 360 360 break; 361 361 } 362 - if (extoff->n_samples > PTP_MAX_SAMPLES 363 - || extoff->rsv[0] || extoff->rsv[1] || extoff->rsv[2]) { 362 + if (extoff->n_samples > PTP_MAX_SAMPLES || 363 + extoff->rsv[0] || extoff->rsv[1] || 364 + (extoff->clockid != CLOCK_REALTIME && 365 + extoff->clockid != CLOCK_MONOTONIC && 366 + extoff->clockid != CLOCK_MONOTONIC_RAW)) { 364 367 err = -EINVAL; 365 368 break; 366 369 } 370 + sts.clockid = extoff->clockid; 367 371 for (i = 0; i < extoff->n_samples; i++) { 368 372 err = ptp->info->gettimex64(ptp->info, &ts, &sts); 369 373 if (err)
+32 -4
include/linux/ptp_clock_kernel.h
··· 47 47 * struct ptp_system_timestamp - system time corresponding to a PHC timestamp 48 48 * @pre_ts: system timestamp before capturing PHC 49 49 * @post_ts: system timestamp after capturing PHC 50 + * @clockid: clock-base used for capturing the system timestamps 50 51 */ 51 52 struct ptp_system_timestamp { 52 53 struct timespec64 pre_ts; 53 54 struct timespec64 post_ts; 55 + clockid_t clockid; 54 56 }; 55 57 56 58 /** ··· 459 457 460 458 static inline void ptp_read_system_prets(struct ptp_system_timestamp *sts) 461 459 { 462 - if (sts) 463 - ktime_get_real_ts64(&sts->pre_ts); 460 + if (sts) { 461 + switch (sts->clockid) { 462 + case CLOCK_REALTIME: 463 + ktime_get_real_ts64(&sts->pre_ts); 464 + break; 465 + case CLOCK_MONOTONIC: 466 + ktime_get_ts64(&sts->pre_ts); 467 + break; 468 + case CLOCK_MONOTONIC_RAW: 469 + ktime_get_raw_ts64(&sts->pre_ts); 470 + break; 471 + default: 472 + break; 473 + } 474 + } 464 475 } 465 476 466 477 static inline void ptp_read_system_postts(struct ptp_system_timestamp *sts) 467 478 { 468 - if (sts) 469 - ktime_get_real_ts64(&sts->post_ts); 479 + if (sts) { 480 + switch (sts->clockid) { 481 + case CLOCK_REALTIME: 482 + ktime_get_real_ts64(&sts->post_ts); 483 + break; 484 + case CLOCK_MONOTONIC: 485 + ktime_get_ts64(&sts->post_ts); 486 + break; 487 + case CLOCK_MONOTONIC_RAW: 488 + ktime_get_raw_ts64(&sts->post_ts); 489 + break; 490 + default: 491 + break; 492 + } 493 + } 470 494 } 471 495 472 496 #endif
+18 -6
include/uapi/linux/ptp_clock.h
··· 155 155 struct ptp_clock_time ts[2 * PTP_MAX_SAMPLES + 1]; 156 156 }; 157 157 158 + /* 159 + * ptp_sys_offset_extended - data structure for IOCTL operation 160 + * PTP_SYS_OFFSET_EXTENDED 161 + * 162 + * @n_samples: Desired number of measurements. 163 + * @clockid: clockid of a clock-base used for pre/post timestamps. 164 + * @rsv: Reserved for future use. 165 + * @ts: Array of samples in the form [pre-TS, PHC, post-TS]. The 166 + * kernel provides @n_samples. 167 + * 168 + * Starting from kernel 6.12 and onwards, the first word of the reserved-field 169 + * is used for @clockid. That's backward compatible since previous kernel 170 + * expect all three reserved words (@rsv[3]) to be 0 while the clockid (first 171 + * word in the new structure) for CLOCK_REALTIME is '0'. 172 + */ 158 173 struct ptp_sys_offset_extended { 159 - unsigned int n_samples; /* Desired number of measurements. */ 160 - unsigned int rsv[3]; /* Reserved for future use. */ 161 - /* 162 - * Array of [system, phc, system] time stamps. The kernel will provide 163 - * 3*n_samples time stamps. 164 - */ 174 + unsigned int n_samples; 175 + __kernel_clockid_t clockid; 176 + unsigned int rsv[2]; 165 177 struct ptp_clock_time ts[PTP_MAX_SAMPLES][3]; 166 178 }; 167 179