aboutsummaryrefslogtreecommitdiffstats
path: root/tools/testing
diff options
context:
space:
mode:
authorShuah Khan <shuahkh@osg.samsung.com>2016-09-13 13:30:03 -0400
committerShuah Khan <shuahkh@osg.samsung.com>2016-09-20 11:54:38 -0400
commit8dbbf854202610a033a0788c33d8feb1548d3eeb (patch)
tree798c50901e2d723c2d1f4a788c93f91d2a2e0232 /tools/testing
parent92dd8dd4d07f170db0638a20a8db691262da4e5e (diff)
selftests: move ptp tests from Documentation/ptp
Remove ptp from Makefile to move the test to selftests. Update ptp Makefile to work under selftests. ptp will not be run as part of selftests suite and will not be included in install targets. They can be built separately for now. Acked-by: Jonathan Corbet <corbet@lwn.net> Signed-off-by: Shuah Khan <shuahkh@osg.samsung.com>
Diffstat (limited to 'tools/testing')
-rw-r--r--tools/testing/selftests/ptp/.gitignore1
-rw-r--r--tools/testing/selftests/ptp/Makefile8
-rw-r--r--tools/testing/selftests/ptp/testptp.c523
-rw-r--r--tools/testing/selftests/ptp/testptp.mk33
4 files changed, 565 insertions, 0 deletions
diff --git a/tools/testing/selftests/ptp/.gitignore b/tools/testing/selftests/ptp/.gitignore
new file mode 100644
index 000000000000..f562e49d6917
--- /dev/null
+++ b/tools/testing/selftests/ptp/.gitignore
@@ -0,0 +1 @@
testptp
diff --git a/tools/testing/selftests/ptp/Makefile b/tools/testing/selftests/ptp/Makefile
new file mode 100644
index 000000000000..83dd42b2129e
--- /dev/null
+++ b/tools/testing/selftests/ptp/Makefile
@@ -0,0 +1,8 @@
1TEST_PROGS := testptp
2LDLIBS += -lrt
3all: $(TEST_PROGS)
4
5include ../lib.mk
6
7clean:
8 rm -fr $(TEST_PROGS)
diff --git a/tools/testing/selftests/ptp/testptp.c b/tools/testing/selftests/ptp/testptp.c
new file mode 100644
index 000000000000..5d2eae16f7ee
--- /dev/null
+++ b/tools/testing/selftests/ptp/testptp.c
@@ -0,0 +1,523 @@
1/*
2 * PTP 1588 clock support - User space test program
3 *
4 * Copyright (C) 2010 OMICRON electronics GmbH
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20#define _GNU_SOURCE
21#define __SANE_USERSPACE_TYPES__ /* For PPC64, to get LL64 types */
22#include <errno.h>
23#include <fcntl.h>
24#include <inttypes.h>
25#include <math.h>
26#include <signal.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <sys/ioctl.h>
31#include <sys/mman.h>
32#include <sys/stat.h>
33#include <sys/time.h>
34#include <sys/timex.h>
35#include <sys/types.h>
36#include <time.h>
37#include <unistd.h>
38
39#include <linux/ptp_clock.h>
40
41#define DEVICE "/dev/ptp0"
42
43#ifndef ADJ_SETOFFSET
44#define ADJ_SETOFFSET 0x0100
45#endif
46
47#ifndef CLOCK_INVALID
48#define CLOCK_INVALID -1
49#endif
50
51/* clock_adjtime is not available in GLIBC < 2.14 */
52#if !__GLIBC_PREREQ(2, 14)
53#include <sys/syscall.h>
54static int clock_adjtime(clockid_t id, struct timex *tx)
55{
56 return syscall(__NR_clock_adjtime, id, tx);
57}
58#endif
59
60static clockid_t get_clockid(int fd)
61{
62#define CLOCKFD 3
63#define FD_TO_CLOCKID(fd) ((~(clockid_t) (fd) << 3) | CLOCKFD)
64
65 return FD_TO_CLOCKID(fd);
66}
67
68static void handle_alarm(int s)
69{
70 printf("received signal %d\n", s);
71}
72
73static int install_handler(int signum, void (*handler)(int))
74{
75 struct sigaction action;
76 sigset_t mask;
77
78 /* Unblock the signal. */
79 sigemptyset(&mask);
80 sigaddset(&mask, signum);
81 sigprocmask(SIG_UNBLOCK, &mask, NULL);
82
83 /* Install the signal handler. */
84 action.sa_handler = handler;
85 action.sa_flags = 0;
86 sigemptyset(&action.sa_mask);
87 sigaction(signum, &action, NULL);
88
89 return 0;
90}
91
92static long ppb_to_scaled_ppm(int ppb)
93{
94 /*
95 * The 'freq' field in the 'struct timex' is in parts per
96 * million, but with a 16 bit binary fractional field.
97 * Instead of calculating either one of
98 *
99 * scaled_ppm = (ppb / 1000) << 16 [1]
100 * scaled_ppm = (ppb << 16) / 1000 [2]
101 *
102 * we simply use double precision math, in order to avoid the
103 * truncation in [1] and the possible overflow in [2].
104 */
105 return (long) (ppb * 65.536);
106}
107
108static int64_t pctns(struct ptp_clock_time *t)
109{
110 return t->sec * 1000000000LL + t->nsec;
111}
112
113static void usage(char *progname)
114{
115 fprintf(stderr,
116 "usage: %s [options]\n"
117 " -a val request a one-shot alarm after 'val' seconds\n"
118 " -A val request a periodic alarm every 'val' seconds\n"
119 " -c query the ptp clock's capabilities\n"
120 " -d name device to open\n"
121 " -e val read 'val' external time stamp events\n"
122 " -f val adjust the ptp clock frequency by 'val' ppb\n"
123 " -g get the ptp clock time\n"
124 " -h prints this message\n"
125 " -i val index for event/trigger\n"
126 " -k val measure the time offset between system and phc clock\n"
127 " for 'val' times (Maximum 25)\n"
128 " -l list the current pin configuration\n"
129 " -L pin,val configure pin index 'pin' with function 'val'\n"
130 " the channel index is taken from the '-i' option\n"
131 " 'val' specifies the auxiliary function:\n"
132 " 0 - none\n"
133 " 1 - external time stamp\n"
134 " 2 - periodic output\n"
135 " -p val enable output with a period of 'val' nanoseconds\n"
136 " -P val enable or disable (val=1|0) the system clock PPS\n"
137 " -s set the ptp clock time from the system time\n"
138 " -S set the system time from the ptp clock time\n"
139 " -t val shift the ptp clock time by 'val' seconds\n"
140 " -T val set the ptp clock time to 'val' seconds\n",
141 progname);
142}
143
144int main(int argc, char *argv[])
145{
146 struct ptp_clock_caps caps;
147 struct ptp_extts_event event;
148 struct ptp_extts_request extts_request;
149 struct ptp_perout_request perout_request;
150 struct ptp_pin_desc desc;
151 struct timespec ts;
152 struct timex tx;
153
154 static timer_t timerid;
155 struct itimerspec timeout;
156 struct sigevent sigevent;
157
158 struct ptp_clock_time *pct;
159 struct ptp_sys_offset *sysoff;
160
161
162 char *progname;
163 unsigned int i;
164 int c, cnt, fd;
165
166 char *device = DEVICE;
167 clockid_t clkid;
168 int adjfreq = 0x7fffffff;
169 int adjtime = 0;
170 int capabilities = 0;
171 int extts = 0;
172 int gettime = 0;
173 int index = 0;
174 int list_pins = 0;
175 int oneshot = 0;
176 int pct_offset = 0;
177 int n_samples = 0;
178 int periodic = 0;
179 int perout = -1;
180 int pin_index = -1, pin_func;
181 int pps = -1;
182 int seconds = 0;
183 int settime = 0;
184
185 int64_t t1, t2, tp;
186 int64_t interval, offset;
187
188 progname = strrchr(argv[0], '/');
189 progname = progname ? 1+progname : argv[0];
190 while (EOF != (c = getopt(argc, argv, "a:A:cd:e:f:ghi:k:lL:p:P:sSt:T:v"))) {
191 switch (c) {
192 case 'a':
193 oneshot = atoi(optarg);
194 break;
195 case 'A':
196 periodic = atoi(optarg);
197 break;
198 case 'c':
199 capabilities = 1;
200 break;
201 case 'd':
202 device = optarg;
203 break;
204 case 'e':
205 extts = atoi(optarg);
206 break;
207 case 'f':
208 adjfreq = atoi(optarg);
209 break;
210 case 'g':
211 gettime = 1;
212 break;
213 case 'i':
214 index = atoi(optarg);
215 break;
216 case 'k':
217 pct_offset = 1;
218 n_samples = atoi(optarg);
219 break;
220 case 'l':
221 list_pins = 1;
222 break;
223 case 'L':
224 cnt = sscanf(optarg, "%d,%d", &pin_index, &pin_func);
225 if (cnt != 2) {
226 usage(progname);
227 return -1;
228 }
229 break;
230 case 'p':
231 perout = atoi(optarg);
232 break;
233 case 'P':
234 pps = atoi(optarg);
235 break;
236 case 's':
237 settime = 1;
238 break;
239 case 'S':
240 settime = 2;
241 break;
242 case 't':
243 adjtime = atoi(optarg);
244 break;
245 case 'T':
246 settime = 3;
247 seconds = atoi(optarg);
248 break;
249 case 'h':
250 usage(progname);
251 return 0;
252 case '?':
253 default:
254 usage(progname);
255 return -1;
256 }
257 }
258
259 fd = open(device, O_RDWR);
260 if (fd < 0) {
261 fprintf(stderr, "opening %s: %s\n", device, strerror(errno));
262 return -1;
263 }
264
265 clkid = get_clockid(fd);
266 if (CLOCK_INVALID == clkid) {
267 fprintf(stderr, "failed to read clock id\n");
268 return -1;
269 }
270
271 if (capabilities) {
272 if (ioctl(fd, PTP_CLOCK_GETCAPS, &caps)) {
273 perror("PTP_CLOCK_GETCAPS");
274 } else {
275 printf("capabilities:\n"
276 " %d maximum frequency adjustment (ppb)\n"
277 " %d programmable alarms\n"
278 " %d external time stamp channels\n"
279 " %d programmable periodic signals\n"
280 " %d pulse per second\n"
281 " %d programmable pins\n"
282 " %d cross timestamping\n",
283 caps.max_adj,
284 caps.n_alarm,
285 caps.n_ext_ts,
286 caps.n_per_out,
287 caps.pps,
288 caps.n_pins,
289 caps.cross_timestamping);
290 }
291 }
292
293 if (0x7fffffff != adjfreq) {
294 memset(&tx, 0, sizeof(tx));
295 tx.modes = ADJ_FREQUENCY;
296 tx.freq = ppb_to_scaled_ppm(adjfreq);
297 if (clock_adjtime(clkid, &tx)) {
298 perror("clock_adjtime");
299 } else {
300 puts("frequency adjustment okay");
301 }
302 }
303
304 if (adjtime) {
305 memset(&tx, 0, sizeof(tx));
306 tx.modes = ADJ_SETOFFSET;
307 tx.time.tv_sec = adjtime;
308 tx.time.tv_usec = 0;
309 if (clock_adjtime(clkid, &tx) < 0) {
310 perror("clock_adjtime");
311 } else {
312 puts("time shift okay");
313 }
314 }
315
316 if (gettime) {
317 if (clock_gettime(clkid, &ts)) {
318 perror("clock_gettime");
319 } else {
320 printf("clock time: %ld.%09ld or %s",
321 ts.tv_sec, ts.tv_nsec, ctime(&ts.tv_sec));
322 }
323 }
324
325 if (settime == 1) {
326 clock_gettime(CLOCK_REALTIME, &ts);
327 if (clock_settime(clkid, &ts)) {
328 perror("clock_settime");
329 } else {
330 puts("set time okay");
331 }
332 }
333
334 if (settime == 2) {
335 clock_gettime(clkid, &ts);
336 if (clock_settime(CLOCK_REALTIME, &ts)) {
337 perror("clock_settime");
338 } else {
339 puts("set time okay");
340 }
341 }
342
343 if (settime == 3) {
344 ts.tv_sec = seconds;
345 ts.tv_nsec = 0;
346 if (clock_settime(clkid, &ts)) {
347 perror("clock_settime");
348 } else {
349 puts("set time okay");
350 }
351 }
352
353 if (extts) {
354 memset(&extts_request, 0, sizeof(extts_request));
355 extts_request.index = index;
356 extts_request.flags = PTP_ENABLE_FEATURE;
357 if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_request)) {
358 perror("PTP_EXTTS_REQUEST");
359 extts = 0;
360 } else {
361 puts("external time stamp request okay");
362 }
363 for (; extts; extts--) {
364 cnt = read(fd, &event, sizeof(event));
365 if (cnt != sizeof(event)) {
366 perror("read");
367 break;
368 }
369 printf("event index %u at %lld.%09u\n", event.index,
370 event.t.sec, event.t.nsec);
371 fflush(stdout);
372 }
373 /* Disable the feature again. */
374 extts_request.flags = 0;
375 if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_request)) {
376 perror("PTP_EXTTS_REQUEST");
377 }
378 }
379
380 if (list_pins) {
381 int n_pins = 0;
382 if (ioctl(fd, PTP_CLOCK_GETCAPS, &caps)) {
383 perror("PTP_CLOCK_GETCAPS");
384 } else {
385 n_pins = caps.n_pins;
386 }
387 for (i = 0; i < n_pins; i++) {
388 desc.index = i;
389 if (ioctl(fd, PTP_PIN_GETFUNC, &desc)) {
390 perror("PTP_PIN_GETFUNC");
391 break;
392 }
393 printf("name %s index %u func %u chan %u\n",
394 desc.name, desc.index, desc.func, desc.chan);
395 }
396 }
397
398 if (oneshot) {
399 install_handler(SIGALRM, handle_alarm);
400 /* Create a timer. */
401 sigevent.sigev_notify = SIGEV_SIGNAL;
402 sigevent.sigev_signo = SIGALRM;
403 if (timer_create(clkid, &sigevent, &timerid)) {
404 perror("timer_create");
405 return -1;
406 }
407 /* Start the timer. */
408 memset(&timeout, 0, sizeof(timeout));
409 timeout.it_value.tv_sec = oneshot;
410 if (timer_settime(timerid, 0, &timeout, NULL)) {
411 perror("timer_settime");
412 return -1;
413 }
414 pause();
415 timer_delete(timerid);
416 }
417
418 if (periodic) {
419 install_handler(SIGALRM, handle_alarm);
420 /* Create a timer. */
421 sigevent.sigev_notify = SIGEV_SIGNAL;
422 sigevent.sigev_signo = SIGALRM;
423 if (timer_create(clkid, &sigevent, &timerid)) {
424 perror("timer_create");
425 return -1;
426 }
427 /* Start the timer. */
428 memset(&timeout, 0, sizeof(timeout));
429 timeout.it_interval.tv_sec = periodic;
430 timeout.it_value.tv_sec = periodic;
431 if (timer_settime(timerid, 0, &timeout, NULL)) {
432 perror("timer_settime");
433 return -1;
434 }
435 while (1) {
436 pause();
437 }
438 timer_delete(timerid);
439 }
440
441 if (perout >= 0) {
442 if (clock_gettime(clkid, &ts)) {
443 perror("clock_gettime");
444 return -1;
445 }
446 memset(&perout_request, 0, sizeof(perout_request));
447 perout_request.index = index;
448 perout_request.start.sec = ts.tv_sec + 2;
449 perout_request.start.nsec = 0;
450 perout_request.period.sec = 0;
451 perout_request.period.nsec = perout;
452 if (ioctl(fd, PTP_PEROUT_REQUEST, &perout_request)) {
453 perror("PTP_PEROUT_REQUEST");
454 } else {
455 puts("periodic output request okay");
456 }
457 }
458
459 if (pin_index >= 0) {
460 memset(&desc, 0, sizeof(desc));
461 desc.index = pin_index;
462 desc.func = pin_func;
463 desc.chan = index;
464 if (ioctl(fd, PTP_PIN_SETFUNC, &desc)) {
465 perror("PTP_PIN_SETFUNC");
466 } else {
467 puts("set pin function okay");
468 }
469 }
470
471 if (pps != -1) {
472 int enable = pps ? 1 : 0;
473 if (ioctl(fd, PTP_ENABLE_PPS, enable)) {
474 perror("PTP_ENABLE_PPS");
475 } else {
476 puts("pps for system time request okay");
477 }
478 }
479
480 if (pct_offset) {
481 if (n_samples <= 0 || n_samples > 25) {
482 puts("n_samples should be between 1 and 25");
483 usage(progname);
484 return -1;
485 }
486
487 sysoff = calloc(1, sizeof(*sysoff));
488 if (!sysoff) {
489 perror("calloc");
490 return -1;
491 }
492 sysoff->n_samples = n_samples;
493
494 if (ioctl(fd, PTP_SYS_OFFSET, sysoff))
495 perror("PTP_SYS_OFFSET");
496 else
497 puts("system and phc clock time offset request okay");
498
499 pct = &sysoff->ts[0];
500 for (i = 0; i < sysoff->n_samples; i++) {
501 t1 = pctns(pct+2*i);
502 tp = pctns(pct+2*i+1);
503 t2 = pctns(pct+2*i+2);
504 interval = t2 - t1;
505 offset = (t2 + t1) / 2 - tp;
506
507 printf("system time: %lld.%u\n",
508 (pct+2*i)->sec, (pct+2*i)->nsec);
509 printf("phc time: %lld.%u\n",
510 (pct+2*i+1)->sec, (pct+2*i+1)->nsec);
511 printf("system time: %lld.%u\n",
512 (pct+2*i+2)->sec, (pct+2*i+2)->nsec);
513 printf("system/phc clock time offset is %" PRId64 " ns\n"
514 "system clock time delay is %" PRId64 " ns\n",
515 offset, interval);
516 }
517
518 free(sysoff);
519 }
520
521 close(fd);
522 return 0;
523}
diff --git a/tools/testing/selftests/ptp/testptp.mk b/tools/testing/selftests/ptp/testptp.mk
new file mode 100644
index 000000000000..4ef2d9755421
--- /dev/null
+++ b/tools/testing/selftests/ptp/testptp.mk
@@ -0,0 +1,33 @@
1# PTP 1588 clock support - User space test program
2#
3# Copyright (C) 2010 OMICRON electronics GmbH
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19CC = $(CROSS_COMPILE)gcc
20INC = -I$(KBUILD_OUTPUT)/usr/include
21CFLAGS = -Wall $(INC)
22LDLIBS = -lrt
23PROGS = testptp
24
25all: $(PROGS)
26
27testptp: testptp.o
28
29clean:
30 rm -f testptp.o
31
32distclean: clean
33 rm -f $(PROGS)