• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: LGPL-2.1
2 /*
3  * Copyright (C) 2019, VMware, Tzvetomir Stoyanov tz.stoyanov@gmail.com>
4  *
5  */
6 
7 #include <fcntl.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <arpa/inet.h>
11 #include <sys/types.h>
12 #include <linux/types.h>
13 #include <time.h>
14 #include <sched.h>
15 #include <limits.h>
16 
17 #include "trace-cmd.h"
18 #include "trace-cmd-private.h"
19 #include "tracefs.h"
20 #include "trace-tsync-local.h"
21 #include "trace-msg.h"
22 #include "trace-cmd-local.h"
23 
24 typedef __be32 be32;
25 typedef __u64 u64;
26 typedef __s64 s64;
27 
28 #define PTP_SYNC_LOOP	339
29 
30 #define PTP_SYNC_PKT_START	1
31 #define PTP_SYNC_PKT_PROBE	2
32 #define PTP_SYNC_PKT_PROBES	3
33 #define PTP_SYNC_PKT_OFFSET	4
34 #define PTP_SYNC_PKT_END	5
35 
36 /* print time sync debug messages */
37 /* #define TSYNC_DEBUG */
38 
39 struct ptp_clock_sync {
40 	struct tep_handle	*tep;
41 	struct tep_format_field	*id;
42 	int			raw_id;
43 	int			marker_fd;
44 	int			series_id;
45 	int			flags;
46 	int			debug_fd;
47 };
48 
49 enum {
50 /*
51  * Consider only the probe with fastest response time,
52  * otherwise make a histogram from all probes.
53  */
54 	PTP_FLAG_FASTEST_RESPONSE		= (1 << 0),
55 /*
56  * Use trace marker to get the clock,
57  * otherwise use the system clock directly.
58  */
59 	PTP_FLAG_USE_MARKER			= (1 << 1),
60 };
61 static int ptp_flags = PTP_FLAG_FASTEST_RESPONSE | PTP_FLAG_USE_MARKER;
62 
63 /*
64  * Calculated using formula [CPU rate]*[calculated offset deviation]
65  * tested on 3GHz CPU, with x86-tsc trace clock and compare the calculated
66  * offset with /sys/kernel/debug/kvm/<VM ID>/vcpu0/tsc-offset
67  * measured 2000ns deviation
68  * using PTP flags PTP_FLAG_FASTEST_RESPONSE | PTP_FLAG_USE_MARKER
69  */
70 #define PTP_ACCURACY	6000
71 #define PTP_NAME	"ptp"
72 
73 struct ptp_clock_start_msg {
74 	be32	series_id;
75 	be32	flags;
76 } __packed;
77 
78 struct ptp_clock_sample {
79 	s64		ts;
80 	be32		id;
81 } __packed;
82 
83 struct ptp_clock_result_msg {
84 	be32			series_id;
85 	be32			count;
86 	struct ptp_clock_sample	samples[2*PTP_SYNC_LOOP];
87 } __packed;
88 
89 struct ptp_clock_offset_msg {
90 	s64	ts;
91 	s64	offset;
92 };
93 
94 struct ptp_markers_context {
95 	struct clock_sync_context	*clock;
96 	struct ptp_clock_sync		*ptp;
97 	struct ptp_clock_result_msg	msg;
98 	int				size;
99 };
100 
101 struct ptp_marker_buf {
102 	int local_id;
103 	int remote_id;
104 	int count;
105 	int packet_id;
106 } __packed;
107 
108 struct ptp_marker {
109 	int series_id;
110 	struct ptp_marker_buf data;
111 } __packed;
112 
ptp_clock_sync_init(struct tracecmd_time_sync * tsync)113 static int ptp_clock_sync_init(struct tracecmd_time_sync *tsync)
114 {
115 	const char *systems[] = {"ftrace", NULL};
116 	struct clock_sync_context *clock_context;
117 	struct ptp_clock_sync *ptp;
118 	struct tep_event *raw;
119 	char *path;
120 
121 	if (!tsync || !tsync->context)
122 		return -1;
123 	clock_context = (struct clock_sync_context *)tsync->context;
124 	if (clock_context->proto_data)
125 		return 0;
126 
127 	ptp = calloc(1, sizeof(struct ptp_clock_sync));
128 	if (!ptp)
129 		return -1;
130 
131 	ptp->marker_fd = -1;
132 	ptp->debug_fd = -1;
133 
134 	path = tracefs_instance_get_dir(clock_context->instance);
135 	if (!path)
136 		goto error;
137 	ptp->tep = tracefs_local_events_system(path, systems);
138 	tracefs_put_tracing_file(path);
139 	if (!ptp->tep)
140 		goto error;
141 	raw = tep_find_event_by_name(ptp->tep, "ftrace", "raw_data");
142 	if (!raw)
143 		goto error;
144 	ptp->id = tep_find_field(raw, "id");
145 	if (!ptp->id)
146 		goto error;
147 	ptp->raw_id = raw->id;
148 
149 	tep_set_file_bigendian(ptp->tep, tracecmd_host_bigendian());
150 	tep_set_local_bigendian(ptp->tep, tracecmd_host_bigendian());
151 
152 	path = tracefs_instance_get_file(clock_context->instance, "trace_marker_raw");
153 	if (!path)
154 		goto error;
155 	ptp->marker_fd = open(path, O_WRONLY);
156 	tracefs_put_tracing_file(path);
157 
158 	clock_context->proto_data = ptp;
159 
160 #ifdef TSYNC_DEBUG
161 	if (clock_context->is_server) {
162 		char buff[256];
163 		int res_fd;
164 
165 		sprintf(buff, "res-id%d.txt", clock_context->remote_id);
166 
167 		res_fd = open(buff, O_CREAT|O_WRONLY|O_TRUNC, 0644);
168 		if (res_fd > 0)
169 			close(res_fd);
170 	}
171 #endif
172 
173 	return 0;
174 
175 error:
176 	if (ptp) {
177 		tep_free(ptp->tep);
178 		if (ptp->marker_fd >= 0)
179 			close(ptp->marker_fd);
180 	}
181 	free(ptp);
182 	return -1;
183 }
184 
ptp_clock_sync_free(struct tracecmd_time_sync * tsync)185 static int ptp_clock_sync_free(struct tracecmd_time_sync *tsync)
186 {
187 	struct clock_sync_context *clock_context;
188 	struct ptp_clock_sync *ptp;
189 
190 	if (!tsync || !tsync->context)
191 		return -1;
192 	clock_context = (struct clock_sync_context *)tsync->context;
193 
194 	if (clock_context && clock_context->proto_data) {
195 		ptp = (struct ptp_clock_sync *)clock_context->proto_data;
196 		tep_free(ptp->tep);
197 		if (ptp->marker_fd >= 0)
198 			close(ptp->marker_fd);
199 		if (ptp->debug_fd >= 0)
200 			close(ptp->debug_fd);
201 		free(clock_context->proto_data);
202 		clock_context->proto_data = NULL;
203 	}
204 	return 0;
205 }
206 
207 /* Save the timestamps of sent ('s') and returned ('r') probes in the
208  * ctx->msg.samples[] array. Depending of the context (server or client), there
209  * may be only returned probes, or both sent and returned probes. The returned
210  * probes are saved first in the array, after them are the sent probes.
211  * Depending of the context, the array can be with size:
212  *  [0 .. max data.count] - holds only returned probes
213  *  [0 .. 2 * max data.count] - holds both returned and sent probes
214  */
ptp_probe_store(struct ptp_markers_context * ctx,struct ptp_marker * marker,unsigned long long ts)215 static void ptp_probe_store(struct ptp_markers_context *ctx,
216 			    struct ptp_marker *marker,
217 			    unsigned long long ts)
218 {
219 	int index = -1;
220 
221 	if (marker->data.packet_id == 'r' &&
222 	    marker->data.count <= ctx->size) {
223 		index = marker->data.count - 1;
224 	} else if (marker->data.packet_id == 's' &&
225 		  marker->data.count * 2 <= ctx->size){
226 		index = ctx->size / 2 + marker->data.count - 1;
227 	}
228 
229 	if (index >= 0) {
230 		ctx->msg.samples[index].id = marker->data.count;
231 		ctx->msg.samples[index].ts = ts;
232 		ctx->msg.count++;
233 	}
234 }
235 
ptp_marker_find(struct tep_event * event,struct tep_record * record,int cpu,void * context)236 static int ptp_marker_find(struct tep_event *event, struct tep_record *record,
237 			   int cpu, void *context)
238 {
239 	struct ptp_markers_context *ctx;
240 	struct ptp_marker *marker;
241 
242 	ctx = (struct ptp_markers_context *)context;
243 
244 	/* Make sure this is our event */
245 	if (event->id != ctx->ptp->raw_id || !ctx->ptp->id)
246 		return 0;
247 	if (record->size >= (ctx->ptp->id->offset + sizeof(struct ptp_marker))) {
248 		marker = (struct ptp_marker *)(record->data + ctx->ptp->id->offset);
249 		if (marker->data.local_id == ctx->clock->local_id &&
250 		    marker->data.remote_id == ctx->clock->remote_id &&
251 		    marker->series_id == ctx->ptp->series_id &&
252 		    marker->data.count)
253 			ptp_probe_store(ctx, marker, record->ts);
254 	}
255 
256 	return 0;
257 }
258 
good_probe(struct ptp_clock_sample * server_sample,struct ptp_clock_sample * send_sample,struct ptp_clock_sample * client_sample,int * bad_probes)259 static inline bool good_probe(struct ptp_clock_sample *server_sample,
260 			      struct ptp_clock_sample *send_sample,
261 			      struct ptp_clock_sample *client_sample,
262 			      int *bad_probes)
263 {
264 	if (server_sample->ts && send_sample->ts && client_sample->ts &&
265 	    server_sample->id == send_sample->id &&
266 	    server_sample->id == client_sample->id)
267 		return true;
268 	(*bad_probes)++;
269 	return false;
270 }
271 
ptp_calc_offset_fastest(struct clock_sync_context * clock,struct ptp_clock_result_msg * server,struct ptp_clock_result_msg * client,long long * offset_ret,long long * ts_ret,int * bad_probes)272 static int ptp_calc_offset_fastest(struct clock_sync_context *clock,
273 			   struct ptp_clock_result_msg *server,
274 			   struct ptp_clock_result_msg *client,
275 			   long long *offset_ret, long long *ts_ret,
276 			   int *bad_probes)
277 {
278 	struct ptp_clock_sample *sample_send;
279 	long long delta_min = LLONG_MAX;
280 	long long offset = 0;
281 	long long delta = 0;
282 	long long ts = 0;
283 	int max_i;
284 	int i;
285 
286 	*bad_probes = 0;
287 	sample_send = server->samples + (server->count / 2);
288 	max_i = server->count / 2 < client->count ?
289 		server->count / 2 : client->count;
290 	for (i = 0; i < max_i; i++) {
291 		if (!good_probe(&server->samples[i], &sample_send[i],
292 		    &client->samples[i], bad_probes))
293 			continue;
294 		ts = (sample_send[i].ts + server->samples[i].ts) / 2;
295 		offset = client->samples[i].ts - ts;
296 
297 		delta = server->samples[i].ts - sample_send[i].ts;
298 		if (delta_min > delta) {
299 			delta_min = delta;
300 			*offset_ret = offset;
301 			*ts_ret = ts;
302 		}
303 #ifdef TSYNC_DEBUG
304 		{
305 			struct ptp_clock_sync *ptp;
306 
307 			ptp = (struct ptp_clock_sync *)clock->proto_data;
308 			if (ptp && ptp->debug_fd > 0) {
309 				char buff[256];
310 
311 				sprintf(buff, "%lld %lld %lld\n",
312 					ts, client->samples[i].ts, offset);
313 				write(ptp->debug_fd, buff, strlen(buff));
314 			}
315 		}
316 #endif
317 	}
318 
319 	return 0;
320 }
321 
ptp_calc_offset_hist(struct clock_sync_context * clock,struct ptp_clock_result_msg * server,struct ptp_clock_result_msg * client,long long * offset_ret,long long * ts_ret,int * bad_probes)322 static int ptp_calc_offset_hist(struct clock_sync_context *clock,
323 			   struct ptp_clock_result_msg *server,
324 			   struct ptp_clock_result_msg *client,
325 			   long long *offset_ret, long long *ts_ret,
326 			   int *bad_probes)
327 {
328 	struct ptp_clock_sample *sample_send;
329 	long long timestamps[PTP_SYNC_LOOP];
330 	long long offsets[PTP_SYNC_LOOP];
331 	long long offset_min = LLONG_MAX;
332 	long long offset_max = 0;
333 	int hist[PTP_SYNC_LOOP];
334 	int ind, max = 0;
335 	long long bin;
336 	int i, k = 0;
337 
338 	*bad_probes = 0;
339 	memset(hist, 0, sizeof(int) * PTP_SYNC_LOOP);
340 	sample_send = server->samples + (server->count / 2);
341 	for (i = 0; i * 2 < server->count && i < client->count; i++) {
342 		if (!good_probe(&server->samples[i], &sample_send[i],
343 		    &client->samples[i], bad_probes))
344 			continue;
345 		timestamps[k] = (sample_send[i].ts + server->samples[i].ts) / 2;
346 		offsets[k] = client->samples[i].ts - timestamps[k];
347 		if (offset_max < llabs(offsets[k]))
348 			offset_max = llabs(offsets[k]);
349 		if (offset_min > llabs(offsets[k]))
350 			offset_min = llabs(offsets[k]);
351 #ifdef TSYNC_DEBUG
352 		{
353 			struct ptp_clock_sync *ptp;
354 
355 			ptp = (struct ptp_clock_sync *)clock->proto_data;
356 
357 			if (ptp && ptp->debug_fd > 0) {
358 				char buff[256];
359 
360 				sprintf(buff, "%lld %lld %lld\n",
361 					timestamps[k],
362 					client->samples[i].ts, offsets[k]);
363 				write(ptp->debug_fd, buff, strlen(buff));
364 			}
365 		}
366 #endif
367 		k++;
368 	}
369 
370 	bin = (offset_max - offset_min) / PTP_SYNC_LOOP;
371 	for (i = 0; i < k; i++) {
372 		ind = (llabs(offsets[i]) - offset_min) / bin;
373 		if (ind < PTP_SYNC_LOOP) {
374 			hist[ind]++;
375 			if (max < hist[ind]) {
376 				max = hist[ind];
377 				*offset_ret = offsets[i];
378 				*ts_ret = timestamps[i];
379 			}
380 		}
381 	}
382 
383 	return 0;
384 }
385 
ntoh_ptp_results(struct ptp_clock_result_msg * msg)386 static void ntoh_ptp_results(struct ptp_clock_result_msg *msg)
387 {
388 	int i;
389 
390 	msg->count = ntohl(msg->count);
391 	for (i = 0; i < msg->count; i++) {
392 		msg->samples[i].id = ntohl(msg->samples[i].id);
393 		msg->samples[i].ts = ntohll(msg->samples[i].ts);
394 	}
395 	msg->series_id = ntohl(msg->series_id);
396 }
397 
398 
hton_ptp_results(struct ptp_clock_result_msg * msg)399 static void hton_ptp_results(struct ptp_clock_result_msg *msg)
400 {
401 	int i;
402 
403 	for (i = 0; i < msg->count; i++) {
404 		msg->samples[i].id = htonl(msg->samples[i].id);
405 		msg->samples[i].ts = htonll(msg->samples[i].ts);
406 	}
407 	msg->series_id = htonl(msg->series_id);
408 	msg->count = htonl(msg->count);
409 }
410 
ptp_track_clock(struct ptp_markers_context * ctx,struct ptp_marker * marker)411 static inline void ptp_track_clock(struct ptp_markers_context *ctx,
412 				   struct ptp_marker *marker)
413 {
414 	if (ctx->ptp->flags & PTP_FLAG_USE_MARKER) {
415 		write(ctx->ptp->marker_fd, marker, sizeof(struct ptp_marker));
416 	} else {
417 		struct timespec clock;
418 		unsigned long long ts;
419 
420 		clock_gettime(CLOCK_MONOTONIC_RAW, &clock);
421 		ts = clock.tv_sec * 1000000000LL;
422 		ts += clock.tv_nsec;
423 		ptp_probe_store(ctx, marker, ts);
424 	}
425 }
426 
ptp_clock_client(struct tracecmd_time_sync * tsync,long long * offset,long long * timestamp)427 static int ptp_clock_client(struct tracecmd_time_sync *tsync,
428 			    long long *offset, long long *timestamp)
429 {
430 	char sync_proto[TRACECMD_TSYNC_PNAME_LENGTH];
431 	struct clock_sync_context *clock_context;
432 	struct ptp_clock_offset_msg res_offset;
433 	struct ptp_clock_start_msg start;
434 	struct ptp_markers_context ctx;
435 	struct ptp_clock_sync *ptp;
436 	struct ptp_marker marker;
437 	unsigned int sync_msg;
438 	unsigned int size;
439 	char *msg;
440 	int count;
441 	int ret;
442 
443 	if (!tsync || !tsync->context || !tsync->msg_handle)
444 		return -1;
445 
446 	clock_context = (struct clock_sync_context *)tsync->context;
447 	if (clock_context->proto_data == NULL)
448 		return -1;
449 
450 	ptp = (struct ptp_clock_sync *)clock_context->proto_data;
451 	size = sizeof(start);
452 	msg = (char *)&start;
453 	ret = tracecmd_msg_recv_time_sync(tsync->msg_handle,
454 					  sync_proto, &sync_msg,
455 					  &size, &msg);
456 	if (ret || strncmp(sync_proto, PTP_NAME, TRACECMD_TSYNC_PNAME_LENGTH) ||
457 	    sync_msg != PTP_SYNC_PKT_START)
458 		return -1;
459 	ret = tracecmd_msg_send_time_sync(tsync->msg_handle, PTP_NAME,
460 					  PTP_SYNC_PKT_START, sizeof(start),
461 					  (char *)&start);
462 	marker.data.local_id = clock_context->local_id;
463 	marker.data.remote_id = clock_context->remote_id;
464 	marker.series_id = ntohl(start.series_id);
465 	marker.data.packet_id = 'r';
466 	ptp->series_id = marker.series_id;
467 	ptp->flags = ntohl(start.flags);
468 	msg = (char *)&count;
469 	size = sizeof(count);
470 	ctx.msg.count = 0;
471 	ctx.size = PTP_SYNC_LOOP;
472 	ctx.ptp = ptp;
473 	ctx.clock = clock_context;
474 	ctx.msg.series_id = ptp->series_id;
475 	while (true) {
476 		count = 0;
477 		ret = tracecmd_msg_recv_time_sync(tsync->msg_handle,
478 						  sync_proto, &sync_msg,
479 						  &size, &msg);
480 		if (ret || strncmp(sync_proto, PTP_NAME, TRACECMD_TSYNC_PNAME_LENGTH) ||
481 		    sync_msg != PTP_SYNC_PKT_PROBE || !ntohl(count))
482 			break;
483 		marker.data.count = ntohl(count);
484 		ptp_track_clock(&ctx, &marker);
485 		ret = tracecmd_msg_send_time_sync(tsync->msg_handle, PTP_NAME,
486 						  PTP_SYNC_PKT_PROBE,
487 						  sizeof(count), (char *)&count);
488 		if (ret)
489 			break;
490 	}
491 
492 	if (strncmp(sync_proto, PTP_NAME, TRACECMD_TSYNC_PNAME_LENGTH) ||
493 	    sync_msg != PTP_SYNC_PKT_END)
494 		return -1;
495 
496 	if (ptp->flags & PTP_FLAG_USE_MARKER)
497 		tracefs_iterate_raw_events(ptp->tep, clock_context->instance,
498 					   NULL, 0, ptp_marker_find, &ctx);
499 
500 	hton_ptp_results(&ctx.msg);
501 	ret = tracecmd_msg_send_time_sync(tsync->msg_handle, PTP_NAME,
502 					  PTP_SYNC_PKT_PROBES,
503 					  sizeof(ctx.msg), (char *)&ctx.msg);
504 
505 	msg = (char *)&res_offset;
506 	size = sizeof(res_offset);
507 	ret = tracecmd_msg_recv_time_sync(tsync->msg_handle,
508 					  sync_proto, &sync_msg,
509 					  &size, (char **)&msg);
510 	if (ret || strncmp(sync_proto, PTP_NAME, TRACECMD_TSYNC_PNAME_LENGTH) ||
511 	    sync_msg != PTP_SYNC_PKT_OFFSET)
512 		return -1;
513 
514 	*offset = ntohll(res_offset.offset);
515 	*timestamp = ntohll(res_offset.ts);
516 
517 	return 0;
518 }
519 
520 
ptp_clock_server(struct tracecmd_time_sync * tsync,long long * offset,long long * timestamp)521 static int ptp_clock_server(struct tracecmd_time_sync *tsync,
522 			    long long *offset, long long *timestamp)
523 {
524 	char sync_proto[TRACECMD_TSYNC_PNAME_LENGTH];
525 	struct ptp_clock_result_msg *results = NULL;
526 	struct clock_sync_context *clock_context;
527 	struct ptp_clock_offset_msg res_offset;
528 	struct ptp_clock_start_msg start;
529 	struct ptp_markers_context ctx;
530 	int sync_loop = PTP_SYNC_LOOP;
531 	struct ptp_clock_sync *ptp;
532 	struct ptp_marker marker;
533 	unsigned int sync_msg;
534 	unsigned int size;
535 	int bad_probes;
536 	int count = 1;
537 	int msg_count;
538 	int msg_ret;
539 	char *msg;
540 	int ret;
541 
542 	if (!tsync || !tsync->context || !tsync->msg_handle)
543 		return -1;
544 
545 	clock_context = (struct clock_sync_context *)tsync->context;
546 	if (clock_context->proto_data == NULL)
547 		return -1;
548 
549 	ptp = (struct ptp_clock_sync *)clock_context->proto_data;
550 	ptp->flags = ptp_flags;
551 	memset(&start, 0, sizeof(start));
552 	start.series_id = htonl(ptp->series_id + 1);
553 	start.flags = htonl(ptp->flags);
554 	ret = tracecmd_msg_send_time_sync(tsync->msg_handle, PTP_NAME,
555 					 PTP_SYNC_PKT_START, sizeof(start),
556 					 (char *)&start);
557 	if (!ret)
558 		ret = tracecmd_msg_recv_time_sync(tsync->msg_handle,
559 						  sync_proto, &sync_msg,
560 						  NULL, NULL);
561 	if (ret || strncmp(sync_proto, PTP_NAME, TRACECMD_TSYNC_PNAME_LENGTH) ||
562 	    sync_msg != PTP_SYNC_PKT_START)
563 		return -1;
564 
565 	tracefs_instance_file_write(clock_context->instance, "trace", "\0");
566 
567 	ptp->series_id++;
568 	marker.data.local_id = clock_context->local_id;
569 	marker.data.remote_id = clock_context->remote_id;
570 	marker.series_id = ptp->series_id;
571 	msg = (char *)&msg_ret;
572 	size = sizeof(msg_ret);
573 	ctx.size = 2*PTP_SYNC_LOOP;
574 	ctx.ptp = ptp;
575 	ctx.clock = clock_context;
576 	ctx.msg.count = 0;
577 	ctx.msg.series_id = ptp->series_id;
578 	do {
579 		marker.data.count = count++;
580 		marker.data.packet_id = 's';
581 		msg_count = htonl(marker.data.count);
582 		ptp_track_clock(&ctx, &marker);
583 		ret = tracecmd_msg_send_time_sync(tsync->msg_handle, PTP_NAME,
584 						 PTP_SYNC_PKT_PROBE,
585 						 sizeof(msg_count),
586 						 (char *)&msg_count);
587 		if (!ret)
588 			ret = tracecmd_msg_recv_time_sync(tsync->msg_handle,
589 							  sync_proto, &sync_msg,
590 							  &size, &msg);
591 
592 		marker.data.packet_id = 'r';
593 		ptp_track_clock(&ctx, &marker);
594 		if (ret || strncmp(sync_proto, PTP_NAME, TRACECMD_TSYNC_PNAME_LENGTH) ||
595 		    sync_msg != PTP_SYNC_PKT_PROBE ||
596 		    ntohl(msg_ret) != marker.data.count)
597 			break;
598 	} while (--sync_loop);
599 
600 	if (sync_loop)
601 		return -1;
602 
603 	ret = tracecmd_msg_send_time_sync(tsync->msg_handle, PTP_NAME,
604 					  PTP_SYNC_PKT_END, 0, NULL);
605 
606 	size = 0;
607 	ret = tracecmd_msg_recv_time_sync(tsync->msg_handle,
608 					  sync_proto, &sync_msg,
609 					  &size, (char **)&results);
610 	if (ret || strncmp(sync_proto, PTP_NAME, TRACECMD_TSYNC_PNAME_LENGTH) ||
611 	    sync_msg != PTP_SYNC_PKT_PROBES || size == 0 || results == NULL)
612 		return -1;
613 
614 	ntoh_ptp_results(results);
615 	if (ptp->flags & PTP_FLAG_USE_MARKER)
616 		tracefs_iterate_raw_events(ptp->tep, clock_context->instance,
617 					   NULL, 0, ptp_marker_find, &ctx);
618 	if (ptp->flags & PTP_FLAG_FASTEST_RESPONSE)
619 		ptp_calc_offset_fastest(clock_context, &ctx.msg, results, offset,
620 					timestamp, &bad_probes);
621 	else
622 		ptp_calc_offset_hist(clock_context, &ctx.msg, results, offset,
623 				     timestamp, &bad_probes);
624 #ifdef TSYNC_DEBUG
625 	{
626 		char buff[256];
627 		int res_fd;
628 
629 		sprintf(buff, "res-id%d.txt", clock_context->remote_id);
630 
631 		res_fd = open(buff, O_WRONLY|O_APPEND, 0644);
632 		if (res_fd > 0) {
633 			if (*offset && *timestamp) {
634 				sprintf(buff, "%d %lld %lld\n",
635 					ptp->series_id, *offset, *timestamp);
636 				write(res_fd, buff, strlen(buff));
637 			}
638 			close(res_fd);
639 		}
640 
641 		printf("\n calculated offset %d: %lld, %d probes, filtered out %d, PTP flags 0x%X\n\r",
642 			ptp->series_id, *offset, results->count, bad_probes, ptp->flags);
643 		if (ptp && ptp->debug_fd > 0) {
644 			sprintf(buff, "%lld %lld 0\n", *offset, *timestamp);
645 			write(ptp->debug_fd, buff, strlen(buff));
646 			close(ptp->debug_fd);
647 			ptp->debug_fd = -1;
648 		}
649 
650 	}
651 #endif
652 
653 	res_offset.offset = htonll(*offset);
654 	res_offset.ts = htonll(*timestamp);
655 	ret = tracecmd_msg_send_time_sync(tsync->msg_handle, PTP_NAME,
656 					  PTP_SYNC_PKT_OFFSET,
657 					  sizeof(res_offset),
658 					  (char *)&res_offset);
659 
660 	free(results);
661 	return 0;
662 }
663 
ptp_clock_sync_calc(struct tracecmd_time_sync * tsync,long long * offset,long long * scaling,long long * frac,long long * timestamp,unsigned int cpu)664 static int ptp_clock_sync_calc(struct tracecmd_time_sync *tsync,
665 			       long long *offset, long long *scaling, long long *frac,
666 			       long long *timestamp, unsigned int cpu)
667 {
668 	struct clock_sync_context *clock_context;
669 	int ret;
670 
671 	if (!tsync || !tsync->context)
672 		return -1;
673 	clock_context = (struct clock_sync_context *)tsync->context;
674 
675 #ifdef TSYNC_DEBUG
676 	if (clock_context->is_server) {
677 		struct ptp_clock_sync *ptp;
678 		char buff[256];
679 
680 		ptp = (struct ptp_clock_sync *)clock_context->proto_data;
681 		if (ptp->debug_fd > 0)
682 			close(ptp->debug_fd);
683 		sprintf(buff, "s-id%d_%d.txt",
684 				clock_context->remote_id, ptp->series_id+1);
685 		ptp->debug_fd = open(buff, O_CREAT|O_WRONLY|O_TRUNC, 0644);
686 	}
687 #endif
688 
689 	if (scaling)
690 		*scaling = 1;
691 	if (frac)
692 		*frac = 0;
693 	if (clock_context->is_server)
694 		ret = ptp_clock_server(tsync, offset, timestamp);
695 	else
696 		ret = ptp_clock_client(tsync, offset, timestamp);
697 
698 	return ret;
699 }
700 
ptp_clock_sync_register(void)701 int ptp_clock_sync_register(void)
702 {
703 	return tracecmd_tsync_proto_register(PTP_NAME, PTP_ACCURACY,
704 					     TRACECMD_TIME_SYNC_ROLE_GUEST |
705 					     TRACECMD_TIME_SYNC_ROLE_HOST |
706 					     TRACECMD_TIME_SYNC_ROLE_CLIENT |
707 					     TRACECMD_TIME_SYNC_ROLE_SERVER,
708 					     0, TRACECMD_TSYNC_FLAG_INTERPOLATE,
709 					     ptp_clock_sync_init,
710 					     ptp_clock_sync_free,
711 					     ptp_clock_sync_calc);
712 
713 }
714 
ptp_clock_sync_unregister(void)715 int ptp_clock_sync_unregister(void)
716 {
717 	return tracecmd_tsync_proto_unregister(PTP_NAME);
718 }
719