[PATCH v4 net-next 3/7] selftests/ptp: Add testptp support for attributes ioctls
From: Arthur Kiyanovski <akiyano@amazon.com>
Date: 2026-07-14 02:04:19
Also in:
linux-doc, linux-kselftest
Subsystem:
kernel selftest framework, the rest · Maintainers:
Shuah Khan, Linus Torvalds
Add support for testing the new PTP_SYS_OFFSET_EXTENDED_ATTRS and
PTP_SYS_OFFSET_PRECISE_ATTRS ioctls in the testptp utility.
New command-line options:
-a: Get extended offset with attributes (error_bound, clock_status,
timescale)
-A: Get precise cross-timestamp with attributes
These options allow testing and validation of PHC devices that provide
clock quality information alongside timestamps.
Also display the new clock_attrs capability in the -c output, and
update print_system_timestamp to print unrecognized clock types instead
of silently dropping them.
Signed-off-by: Amit Bernstein <redacted>
Signed-off-by: Arthur Kiyanovski <akiyano@amazon.com>
---
tools/testing/selftests/ptp/testptp.c | 111 +++++++++++++++++++++++++-
1 file changed, 109 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/ptp/testptp.c b/tools/testing/selftests/ptp/testptp.c
index d3bcfd03fce4..99607da01b22 100644
--- a/tools/testing/selftests/ptp/testptp.c
+++ b/tools/testing/selftests/ptp/testptp.c@@ -147,10 +147,13 @@ static void usage(char *progname) " -t val shift the ptp clock time by 'val' seconds\n" " -T val set the ptp clock time to 'val' seconds\n" " -x val get an extended ptp clock time with the desired number of samples (up to %d)\n" + " -a val get extended timestamps with attributes (error_bound,\n" + " clock_status, timescale, counter), up to %d samples\n" " -X get a ptp clock cross timestamp\n" + " -A get a precise cross timestamp with attributes\n" " -y val pre/post tstamp timebase to use {realtime|monotonic|monotonic-raw}\n" " -z test combinations of rising/falling external time stamp flags\n", - progname, PTP_MAX_SAMPLES); + progname, PTP_MAX_SAMPLES, PTP_MAX_SAMPLES); } static void print_system_timestamp(int sample_num, __kernel_clockid_t clockid,
@@ -171,6 +174,8 @@ static void print_system_timestamp(int sample_num, __kernel_clockid_t clockid, sample_num, when, sec, nsec); break; default: + printf("sample #%2d: unknown clock %d %s: %lld.%09u\n", + sample_num, clockid, when, sec, nsec); break; } }
@@ -188,6 +193,7 @@ int main(int argc, char *argv[]) struct ptp_sys_offset *sysoff; struct ptp_sys_offset_extended *soe; struct ptp_sys_offset_precise *xts; + struct ptp_sys_offset_attrs *attrs_data; char *progname; unsigned int i;
@@ -208,7 +214,9 @@ int main(int argc, char *argv[]) int list_pins = 0; int pct_offset = 0; int getextended = 0; + int getextendedattrs = 0; int getcross = 0; + int getcrossattrs = 0; int n_samples = 0; int pin_index = -1, pin_func; int pps = -1;
@@ -226,7 +234,8 @@ int main(int argc, char *argv[]) progname = strrchr(argv[0], '/'); progname = progname ? 1+progname : argv[0]; - while (EOF != (c = getopt(argc, argv, "cd:e:E:f:F:ghH:i:k:lL:n:o:p:P:rsSt:T:w:x:Xy:z"))) { + while (EOF != (c = getopt(argc, argv, + "a:Acd:e:E:f:F:ghH:i:k:lL:n:o:p:P:rsSt:T:w:x:Xy:z"))) { switch (c) { case 'c': capabilities = 1;
@@ -311,9 +320,22 @@ int main(int argc, char *argv[]) return -1; } break; + case 'a': + getextendedattrs = atoi(optarg); + if (getextendedattrs < 1 || + getextendedattrs > PTP_MAX_SAMPLES) { + fprintf(stderr, + "number of extended attrs timestamp samples must be between 1 and %d; was asked for %d\n", + PTP_MAX_SAMPLES, getextendedattrs); + return -1; + } + break; case 'X': getcross = 1; break; + case 'A': + getcrossattrs = 1; + break; case 'y': if (!strcasecmp(optarg, "realtime")) ext_clockid = CLOCK_REALTIME;
@@ -367,6 +389,8 @@ int main(int argc, char *argv[]) " %d programmable pins\n" " %d cross timestamping\n" " %d adjust_phase\n" + " %d extended_attrs\n" + " %d precise_attrs\n" " %d maximum phase adjustment (ns)\n", caps.max_adj, caps.n_alarm,
@@ -376,6 +400,8 @@ int main(int argc, char *argv[]) caps.n_pins, caps.cross_timestamping, caps.adjust_phase, + caps.extended_attrs, + caps.precise_attrs, caps.max_phase_adj); } }
@@ -648,6 +674,49 @@ int main(int argc, char *argv[]) free(soe); } + if (getextendedattrs) { + attrs_data = calloc(1, sizeof(*attrs_data) + + getextendedattrs * sizeof(struct ptp_timestamp)); + if (!attrs_data) { + perror("calloc"); + return -1; + } + + attrs_data->request.num_samples = getextendedattrs; + attrs_data->request.clock_id = ext_clockid; + + if (ioctl(fd, PTP_SYS_OFFSET_EXTENDED_ATTRS, attrs_data)) { + perror("PTP_SYS_OFFSET_EXTENDED_ATTRS"); + } else { + printf("extended attrs timestamp request returned %d samples\n", + getextendedattrs); + + for (i = 0; i < getextendedattrs; i++) { + struct ptp_timestamp *ts = &attrs_data->timestamps[i]; + + printf(" sample #%u:\n", i); + printf(" sys before: %lld ns\n", + (long long)ts->pre_systime.sys_time); + printf(" phc time: %lld.%09u\n", + ts->devtime.device_time.sec, + ts->devtime.device_time.nsec); + if (ts->devtime.attrs.valid & PTP_ATTRS_VALID_ERROR_BOUND) + printf(" error_bound: %u ns\n", + ts->devtime.attrs.error_bound); + if (ts->devtime.attrs.valid & PTP_ATTRS_VALID_STATUS) + printf(" status: %u\n", + ts->devtime.attrs.status); + if (ts->devtime.attrs.valid & PTP_ATTRS_VALID_TIMESCALE) + printf(" timescale: %u\n", + ts->devtime.attrs.timescale); + printf(" sys after: %lld ns\n", + (long long)ts->post_systime.sys_time); + } + } + + free(attrs_data); + } + if (getcross) { xts = calloc(1, sizeof(*xts)); if (!xts) {
@@ -671,6 +740,44 @@ int main(int argc, char *argv[]) free(xts); } + if (getcrossattrs) { + attrs_data = calloc(1, sizeof(*attrs_data) + + sizeof(struct ptp_timestamp)); + if (!attrs_data) { + perror("calloc"); + return -1; + } + + attrs_data->request.num_samples = 1; + attrs_data->request.clock_id = ext_clockid; + + if (ioctl(fd, PTP_SYS_OFFSET_PRECISE_ATTRS, attrs_data)) { + perror("PTP_SYS_OFFSET_PRECISE_ATTRS"); + } else { + struct ptp_timestamp *ts = &attrs_data->timestamps[0]; + + puts("precise attrs crosstimestamp request okay"); + printf("device time: %lld.%09u\n", + ts->devtime.device_time.sec, + ts->devtime.device_time.nsec); + printf("system time: %lld ns\n", + (long long)ts->systime.sys_time); + printf("raw time: %lld ns\n", + (long long)ts->systime.sys_rawtime); + if (ts->devtime.attrs.valid & PTP_ATTRS_VALID_ERROR_BOUND) + printf("error_bound: %u ns\n", + ts->devtime.attrs.error_bound); + if (ts->devtime.attrs.valid & PTP_ATTRS_VALID_STATUS) + printf("status: %u\n", + ts->devtime.attrs.status); + if (ts->devtime.attrs.valid & PTP_ATTRS_VALID_TIMESCALE) + printf("timescale: %u\n", + ts->devtime.attrs.timescale); + } + + free(attrs_data); + } + if (channel >= 0) { if (ioctl(fd, PTP_MASK_CLEAR_ALL)) { perror("PTP_MASK_CLEAR_ALL");
--
2.47.3