1 /*
2 * Copyright (c) 2024 BayLibre SAS
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_REGISTER(ptp_clock, CONFIG_PTP_LOG_LEVEL);
9
10 #include <stdbool.h>
11 #include <stdlib.h>
12 #include <string.h>
13
14 #include <zephyr/zvfs/eventfd.h>
15
16 #include <zephyr/kernel.h>
17 #include <zephyr/drivers/ptp_clock.h>
18 #include <zephyr/net/ethernet.h>
19 #include <zephyr/net/net_if.h>
20 #include <zephyr/net/socket.h>
21 #include <zephyr/sys/slist.h>
22
23 #include "btca.h"
24 #include "clock.h"
25 #include "ddt.h"
26 #include "msg.h"
27 #include "port.h"
28 #include "tlv.h"
29 #include "transport.h"
30
31 #define MIN_NSEC_TO_TIMEINTERVAL (0xFFFF800000000000ULL)
32 #define MAX_NSEC_TO_TIMEINTERVAL (0x00007FFFFFFFFFFFULL)
33
34 /**
35 * @brief PTP Clock structure.
36 */
37 struct ptp_clock {
38 const struct device *phc;
39 struct ptp_default_ds default_ds;
40 struct ptp_current_ds current_ds;
41 struct ptp_parent_ds parent_ds;
42 struct ptp_time_prop_ds time_prop_ds;
43 struct ptp_dataset dataset;
44 struct ptp_foreign_tt_clock *best;
45 sys_slist_t ports_list;
46 struct zsock_pollfd pollfd[1 + 2 * CONFIG_PTP_NUM_PORTS];
47 bool pollfd_valid;
48 bool state_decision_event;
49 uint8_t time_src;
50 struct {
51 uint64_t t1;
52 uint64_t t2;
53 uint64_t t3;
54 uint64_t t4;
55 } timestamp; /* latest timestamps in nanoseconds */
56 double pi_drift;
57 };
58
59 __maybe_unused static struct ptp_clock ptp_clk = { 0 };
60 char str_clock_id[] = "FF:FF:FF:FF:FF:FF:FF:FF";
61
clock_generate_id(ptp_clk_id * clock_id,struct net_if * iface)62 static int clock_generate_id(ptp_clk_id *clock_id, struct net_if *iface)
63 {
64 struct net_linkaddr *addr = net_if_get_link_addr(iface);
65
66 if (addr) {
67 clock_id->id[0] = addr->addr[0];
68 clock_id->id[1] = addr->addr[1];
69 clock_id->id[2] = addr->addr[2];
70 clock_id->id[3] = 0xFF;
71 clock_id->id[4] = 0xFE;
72 clock_id->id[5] = addr->addr[3];
73 clock_id->id[6] = addr->addr[4];
74 clock_id->id[7] = addr->addr[5];
75 return 0;
76 }
77 return -1;
78 }
79
clock_id_str(ptp_clk_id * clock_id)80 static const char *clock_id_str(ptp_clk_id *clock_id)
81 {
82 uint8_t *cid = clock_id->id;
83
84 snprintk(str_clock_id, sizeof(str_clock_id), "%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X",
85 cid[0],
86 cid[1],
87 cid[2],
88 cid[3],
89 cid[4],
90 cid[5],
91 cid[6],
92 cid[7]);
93
94 return str_clock_id;
95 }
96
clock_ns_to_timeinterval(int64_t val)97 static ptp_timeinterval clock_ns_to_timeinterval(int64_t val)
98 {
99 if (val < (int64_t)MIN_NSEC_TO_TIMEINTERVAL) {
100 val = MIN_NSEC_TO_TIMEINTERVAL;
101 } else if (val > (int64_t)MAX_NSEC_TO_TIMEINTERVAL) {
102 val = MAX_NSEC_TO_TIMEINTERVAL;
103 }
104
105 return (uint64_t)val << 16;
106 }
107
clock_forward_msg(struct ptp_port * ingress,struct ptp_port * port,struct ptp_msg * msg,bool * network_byte_order)108 static int clock_forward_msg(struct ptp_port *ingress,
109 struct ptp_port *port,
110 struct ptp_msg *msg,
111 bool *network_byte_order)
112 {
113 if (ingress == port) {
114 return 0;
115 }
116
117 if (*network_byte_order == false) {
118 ptp_msg_pre_send(msg);
119 *network_byte_order = true;
120 }
121
122 return ptp_transport_send(port, msg, PTP_SOCKET_GENERAL);
123 }
124
clock_forward_management_msg(struct ptp_port * port,struct ptp_msg * msg)125 static void clock_forward_management_msg(struct ptp_port *port, struct ptp_msg *msg)
126 {
127 int length;
128 struct ptp_port *iter;
129 bool net_byte_ord = false;
130 enum ptp_port_state state = ptp_port_state(port);
131
132 if (ptp_clock_type() != PTP_CLOCK_TYPE_BOUNDARY) {
133 /* Clocks other than Boundary Clock shouldn't retransmit messages. */
134 return;
135 }
136
137 if (msg->header.flags[0] & PTP_MSG_UNICAST_FLAG) {
138 return;
139 }
140
141 if (msg->management.boundary_hops &&
142 (state == PTP_PS_GRAND_MASTER ||
143 state == PTP_PS_TIME_TRANSMITTER ||
144 state == PTP_PS_PRE_TIME_TRANSMITTER ||
145 state == PTP_PS_TIME_RECEIVER ||
146 state == PTP_PS_UNCALIBRATED)) {
147 length = msg->header.msg_length;
148 msg->management.boundary_hops--;
149
150 SYS_SLIST_FOR_EACH_CONTAINER(&ptp_clk.ports_list, iter, node) {
151 if (clock_forward_msg(port, iter, msg, &net_byte_ord)) {
152 LOG_ERR("Failed to forward message to %d Port",
153 iter->port_ds.id.port_number);
154 }
155 }
156
157 if (net_byte_ord) {
158 ptp_msg_post_recv(port, msg, length);
159 msg->management.boundary_hops++;
160 }
161 }
162 }
163
clock_management_set(struct ptp_port * port,struct ptp_msg * req,struct ptp_tlv_mgmt * tlv)164 static int clock_management_set(struct ptp_port *port,
165 struct ptp_msg *req,
166 struct ptp_tlv_mgmt *tlv)
167 {
168 bool send_resp = false;
169
170 switch (tlv->id) {
171 case PTP_MGMT_PRIORITY1:
172 ptp_clk.default_ds.priority1 = *tlv->data;
173 send_resp = true;
174 break;
175 case PTP_MGMT_PRIORITY2:
176 ptp_clk.default_ds.priority2 = *tlv->data;
177 send_resp = true;
178 break;
179 default:
180 break;
181 }
182
183 return send_resp ? ptp_port_management_resp(port, req, tlv) : 0;
184 }
185
clock_update_grandmaster(void)186 static void clock_update_grandmaster(void)
187 {
188 memset(&ptp_clk.current_ds, 0, sizeof(struct ptp_current_ds));
189
190 memcpy(&ptp_clk.parent_ds.port_id.clk_id,
191 &ptp_clk.default_ds.clk_id,
192 sizeof(ptp_clk_id));
193 memcpy(&ptp_clk.parent_ds.gm_id,
194 &ptp_clk.default_ds.clk_id,
195 sizeof(ptp_clk_id));
196 ptp_clk.parent_ds.port_id.port_number = 0;
197 ptp_clk.parent_ds.gm_clk_quality = ptp_clk.default_ds.clk_quality;
198 ptp_clk.parent_ds.gm_priority1 = ptp_clk.default_ds.priority1;
199 ptp_clk.parent_ds.gm_priority2 = ptp_clk.default_ds.priority2;
200
201 ptp_clk.time_prop_ds.current_utc_offset = 37; /* IEEE 1588-2019 9.4 */
202 ptp_clk.time_prop_ds.time_src = ptp_clk.time_src;
203 ptp_clk.time_prop_ds.flags = 0;
204 }
205
clock_update_time_receiver(void)206 static void clock_update_time_receiver(void)
207 {
208 struct ptp_msg *best_msg = (struct ptp_msg *)k_fifo_peek_tail(&ptp_clk.best->messages);
209
210 ptp_clk.current_ds.steps_rm = 1 + ptp_clk.best->dataset.steps_rm;
211
212 memcpy(&ptp_clk.parent_ds.gm_id,
213 &best_msg->announce.gm_id,
214 sizeof(best_msg->announce.gm_id));
215 memcpy(&ptp_clk.parent_ds.port_id,
216 &ptp_clk.best->dataset.sender,
217 sizeof(ptp_clk.best->dataset.sender));
218 ptp_clk.parent_ds.gm_clk_quality = best_msg->announce.gm_clk_quality;
219 ptp_clk.parent_ds.gm_priority1 = best_msg->announce.gm_priority1;
220 ptp_clk.parent_ds.gm_priority2 = best_msg->announce.gm_priority2;
221
222 ptp_clk.time_prop_ds.current_utc_offset = best_msg->announce.current_utc_offset;
223 ptp_clk.time_prop_ds.flags = best_msg->header.flags[1];
224 }
225
clock_check_pollfd(void)226 static void clock_check_pollfd(void)
227 {
228 struct ptp_port *port;
229 struct zsock_pollfd *fd = &ptp_clk.pollfd[1];
230
231 if (ptp_clk.pollfd_valid) {
232 return;
233 }
234
235 SYS_SLIST_FOR_EACH_CONTAINER(&ptp_clk.ports_list, port, node) {
236 for (int i = 0; i < PTP_SOCKET_CNT; i++) {
237 fd->fd = port->socket[i];
238 fd->events = ZSOCK_POLLIN | ZSOCK_POLLPRI;
239 fd++;
240 }
241 }
242
243 ptp_clk.pollfd_valid = true;
244 }
245
ptp_clock_init(void)246 const struct ptp_clock *ptp_clock_init(void)
247 {
248 struct ptp_default_ds *dds = &ptp_clk.default_ds;
249 struct ptp_parent_ds *pds = &ptp_clk.parent_ds;
250 struct net_if *iface = net_if_get_first_by_type(&NET_L2_GET_NAME(ETHERNET));
251
252 ptp_clk.time_src = (enum ptp_time_src)PTP_TIME_SRC_INTERNAL_OSC;
253
254 /* Initialize Default Dataset. */
255 int ret = clock_generate_id(&dds->clk_id, iface);
256
257 if (ret) {
258 LOG_ERR("Couldn't assign Clock Identity.");
259 return NULL;
260 }
261
262 dds->type = (enum ptp_clock_type)CONFIG_PTP_CLOCK_TYPE;
263 dds->n_ports = 0;
264 dds->time_receiver_only = IS_ENABLED(CONFIG_PTP_TIME_RECEIVER_ONLY) ? true : false;
265
266 dds->clk_quality.cls = dds->time_receiver_only ? 255 : 248;
267 dds->clk_quality.accuracy = CONFIG_PTP_CLOCK_ACCURACY;
268 /* 0xFFFF means that value has not been computed - IEEE 1588-2019 7.6.3.3 */
269 dds->clk_quality.offset_scaled_log_variance = 0xFFFF;
270
271 dds->max_steps_rm = 255;
272
273 dds->priority1 = CONFIG_PTP_PRIORITY1;
274 dds->priority2 = CONFIG_PTP_PRIORITY2;
275
276 /* Initialize Parent Dataset. */
277 clock_update_grandmaster();
278 pds->obsreved_parent_offset_scaled_log_variance = 0xFFFF;
279 pds->obsreved_parent_clk_phase_change_rate = 0x7FFFFFFF;
280 /* Parent statistics haven't been measured - IEEE 1588-2019 7.6.4.2 */
281 pds->stats = false;
282
283 ptp_clk.phc = net_eth_get_ptp_clock(iface);
284 if (!ptp_clk.phc) {
285 LOG_ERR("Couldn't get PTP HW Clock for the interface.");
286 return NULL;
287 }
288
289 ptp_clk.pollfd[0].fd = zvfs_eventfd(0, ZVFS_EFD_NONBLOCK);
290 ptp_clk.pollfd[0].events = ZSOCK_POLLIN;
291
292 sys_slist_init(&ptp_clk.ports_list);
293 LOG_DBG("PTP Clock %s initialized", clock_id_str(&dds->clk_id));
294 return &ptp_clk;
295 }
296
ptp_clock_poll_sockets(void)297 struct zsock_pollfd *ptp_clock_poll_sockets(void)
298 {
299 int ret;
300
301 clock_check_pollfd();
302 ret = zsock_poll(ptp_clk.pollfd, PTP_SOCKET_CNT * ptp_clk.default_ds.n_ports + 1, -1);
303 if (ret > 0 && ptp_clk.pollfd[0].revents) {
304 zvfs_eventfd_t value;
305
306 zvfs_eventfd_read(ptp_clk.pollfd[0].fd, &value);
307 }
308
309 return &ptp_clk.pollfd[1];
310 }
311
ptp_clock_handle_state_decision_evt(void)312 void ptp_clock_handle_state_decision_evt(void)
313 {
314 struct ptp_foreign_tt_clock *best = NULL, *foreign;
315 struct ptp_port *port;
316 bool tt_changed = false;
317
318 if (!ptp_clk.state_decision_event) {
319 return;
320 }
321
322 SYS_SLIST_FOR_EACH_CONTAINER(&ptp_clk.ports_list, port, node) {
323 foreign = ptp_port_best_foreign(port);
324 if (!foreign) {
325 continue;
326 }
327 if (!best || ptp_btca_ds_cmp(&foreign->dataset, &best->dataset)) {
328 best = foreign;
329 }
330 }
331
332 ptp_clk.best = best;
333
334 SYS_SLIST_FOR_EACH_CONTAINER(&ptp_clk.ports_list, port, node) {
335 enum ptp_port_state state;
336 enum ptp_port_event event;
337
338 state = ptp_btca_state_decision(port);
339
340 switch (state) {
341 case PTP_PS_LISTENING:
342 event = PTP_EVT_NONE;
343 break;
344 case PTP_PS_GRAND_MASTER:
345 clock_update_grandmaster();
346 event = PTP_EVT_RS_GRAND_MASTER;
347 break;
348 case PTP_PS_TIME_TRANSMITTER:
349 event = PTP_EVT_RS_TIME_TRANSMITTER;
350 break;
351 case PTP_PS_TIME_RECEIVER:
352 clock_update_time_receiver();
353 event = PTP_EVT_RS_TIME_RECEIVER;
354 break;
355 case PTP_PS_PASSIVE:
356 event = PTP_EVT_RS_PASSIVE;
357 break;
358 default:
359 event = PTP_EVT_FAULT_DETECTED;
360 break;
361 }
362
363 ptp_port_event_handle(port, event, tt_changed);
364 }
365
366 ptp_clk.state_decision_event = false;
367 }
368
ptp_clock_management_msg_process(struct ptp_port * port,struct ptp_msg * msg)369 int ptp_clock_management_msg_process(struct ptp_port *port, struct ptp_msg *msg)
370 {
371 static const ptp_clk_id all_ones = {
372 .id = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
373 };
374 int ret;
375 bool state_decision_required = false;
376 enum ptp_mgmt_op action = ptp_mgmt_action(msg);
377 struct ptp_port_id *target_port = &msg->management.target_port_id;
378 const struct ptp_default_ds *dds = ptp_clock_default_ds();
379 struct ptp_tlv_mgmt *mgmt = (struct ptp_tlv_mgmt *)msg->management.suffix;
380 struct ptp_port *iter;
381
382 if (!ptp_clock_id_eq(&dds->clk_id, &target_port->clk_id) &&
383 !ptp_clock_id_eq(&target_port->clk_id, &all_ones)) {
384 return state_decision_required;
385 }
386
387 if (sys_slist_len(&msg->tlvs) != 1) {
388 /* IEEE 1588-2019 15.3.2 - PTP mgmt msg transports single mgmt TLV */
389 return state_decision_required;
390 }
391
392 clock_forward_management_msg(port, msg);
393
394 switch (action) {
395 case PTP_MGMT_SET:
396 ret = clock_management_set(port, msg, mgmt);
397 if (ret < 0) {
398 return state_decision_required;
399 }
400 state_decision_required = ret ? true : false;
401 break;
402 case PTP_MGMT_GET:
403 __fallthrough;
404 case PTP_MGMT_CMD:
405 break;
406 default:
407 return state_decision_required;
408 }
409
410 switch (mgmt->id) {
411 case PTP_MGMT_CLOCK_DESCRIPTION:
412 __fallthrough;
413 case PTP_MGMT_USER_DESCRIPTION:
414 __fallthrough;
415 case PTP_MGMT_SAVE_IN_NON_VOLATILE_STORAGE:
416 __fallthrough;
417 case PTP_MGMT_RESET_NON_VOLATILE_STORAGE:
418 __fallthrough;
419 case PTP_MGMT_INITIALIZE:
420 __fallthrough;
421 case PTP_MGMT_FAULT_LOG:
422 __fallthrough;
423 case PTP_MGMT_FAULT_LOG_RESET:
424 __fallthrough;
425 case PTP_MGMT_DOMAIN:
426 __fallthrough;
427 case PTP_MGMT_TIME_RECEIVER_ONLY:
428 __fallthrough;
429 case PTP_MGMT_ANNOUNCE_RECEIPT_TIMEOUT:
430 __fallthrough;
431 case PTP_MGMT_VERSION_NUMBER:
432 __fallthrough;
433 case PTP_MGMT_ENABLE_PORT:
434 __fallthrough;
435 case PTP_MGMT_DISABLE_PORT:
436 __fallthrough;
437 case PTP_MGMT_TIME:
438 __fallthrough;
439 case PTP_MGMT_CLOCK_ACCURACY:
440 __fallthrough;
441 case PTP_MGMT_UTC_PROPERTIES:
442 __fallthrough;
443 case PTP_MGMT_TRACEBILITY_PROPERTIES:
444 __fallthrough;
445 case PTP_MGMT_TIMESCALE_PROPERTIES:
446 __fallthrough;
447 case PTP_MGMT_UNICAST_NEGOTIATION_ENABLE:
448 __fallthrough;
449 case PTP_MGMT_PATH_TRACE_LIST:
450 __fallthrough;
451 case PTP_MGMT_PATH_TRACE_ENABLE:
452 __fallthrough;
453 case PTP_MGMT_GRANDMASTER_CLUSTER_TABLE:
454 __fallthrough;
455 case PTP_MGMT_UNICAST_TIME_TRANSMITTER_TABLE:
456 __fallthrough;
457 case PTP_MGMT_UNICAST_TIME_TRANSMITTER_MAX_TABLE_SIZE:
458 __fallthrough;
459 case PTP_MGMT_ACCEPTABLE_TIME_TRANSMITTER_TABLE:
460 __fallthrough;
461 case PTP_MGMT_ACCEPTABLE_TIME_TRANSMITTER_TABLE_ENABLED:
462 __fallthrough;
463 case PTP_MGMT_ACCEPTABLE_TIME_TRANSMITTER_MAX_TABLE_SIZE:
464 __fallthrough;
465 case PTP_MGMT_ALTERNATE_TIME_TRANSMITTER:
466 __fallthrough;
467 case PTP_MGMT_ALTERNATE_TIME_OFFSET_ENABLE:
468 __fallthrough;
469 case PTP_MGMT_ALTERNATE_TIME_OFFSET_NAME:
470 __fallthrough;
471 case PTP_MGMT_ALTERNATE_TIME_OFFSET_MAX_KEY:
472 __fallthrough;
473 case PTP_MGMT_ALTERNATE_TIME_OFFSET_PROPERTIES:
474 __fallthrough;
475 case PTP_MGMT_EXTERNAL_PORT_CONFIGURATION_ENABLED:
476 __fallthrough;
477 case PTP_MGMT_TIME_TRANSMITTER_ONLY:
478 __fallthrough;
479 case PTP_MGMT_HOLDOVER_UPGRADE_ENABLE:
480 __fallthrough;
481 case PTP_MGMT_EXT_PORT_CONFIG_PORT_DATA_SET:
482 __fallthrough;
483 case PTP_MGMT_TRANSPARENT_CLOCK_DEFAULT_DATA_SET:
484 __fallthrough;
485 case PTP_MGMT_TRANSPARENT_CLOCK_PORT_DATA_SET:
486 __fallthrough;
487 case PTP_MGMT_PRIMARY_DOMAIN:
488 __fallthrough;
489 case PTP_MGMT_DELAY_MECHANISM:
490 __fallthrough;
491 case PTP_MGMT_LOG_MIN_PDELAY_REQ_INTERVAL:
492 ptp_port_management_error(port, msg, PTP_MGMT_ERR_NOT_SUPPORTED);
493 break;
494 default:
495 if (target_port->port_number == port->port_ds.id.port_number) {
496 ptp_port_management_msg_process(port, port, msg, mgmt);
497 } else if (target_port->port_number == UINT16_MAX) {
498 SYS_SLIST_FOR_EACH_CONTAINER(&ptp_clk.ports_list, iter, node) {
499 if (ptp_port_management_msg_process(iter, port, msg, mgmt)) {
500 break;
501 }
502 }
503 }
504 break;
505 }
506
507 return state_decision_required;
508 }
509
ptp_servo_pi(int64_t nanosecond_diff)510 static double ptp_servo_pi(int64_t nanosecond_diff)
511 {
512 double kp = 0.7;
513 double ki = 0.3;
514 double ppb;
515
516 ptp_clk.pi_drift += ki * nanosecond_diff;
517 ppb = kp * nanosecond_diff + ptp_clk.pi_drift;
518
519 return ppb;
520 }
521
ptp_clock_synchronize(uint64_t ingress,uint64_t egress)522 void ptp_clock_synchronize(uint64_t ingress, uint64_t egress)
523 {
524 double ppb;
525 int64_t offset;
526 int64_t delay = ptp_clk.current_ds.mean_delay >> 16;
527
528 ptp_clk.timestamp.t1 = egress;
529 ptp_clk.timestamp.t2 = ingress;
530
531 if (!ptp_clk.current_ds.mean_delay) {
532 return;
533 }
534
535 offset = (int64_t)(ptp_clk.timestamp.t2 - ptp_clk.timestamp.t1) - delay;
536
537 /* If diff is too big, ptp_clk needs to be set first. */
538 if ((offset > (int64_t)NSEC_PER_SEC) || (offset < -(int64_t)NSEC_PER_SEC)) {
539 struct net_ptp_time current;
540 int32_t dest_nsec;
541
542 LOG_WRN("Clock offset exceeds 1 second.");
543
544 ptp_clock_get(ptp_clk.phc, ¤t);
545
546 current.second = (uint64_t)(current.second - (offset / NSEC_PER_SEC));
547 dest_nsec = (int32_t)(current.nanosecond - (offset % NSEC_PER_SEC));
548
549 if (dest_nsec < 0) {
550 current.second--;
551 dest_nsec += NSEC_PER_SEC;
552 } else if (dest_nsec >= NSEC_PER_SEC) {
553 current.second++;
554 dest_nsec -= NSEC_PER_SEC;
555 }
556
557 current.nanosecond = (uint32_t)dest_nsec;
558
559 ptp_clock_set(ptp_clk.phc, ¤t);
560 LOG_WRN("Set clock time: %"PRIu64".%09u", current.second, current.nanosecond);
561 return;
562 }
563
564 LOG_DBG("Offset %lldns", offset);
565 ptp_clk.current_ds.offset_from_tt = clock_ns_to_timeinterval(offset);
566
567 ppb = ptp_servo_pi(-offset);
568 ptp_clock_rate_adjust(ptp_clk.phc, 1.0 + (ppb / 1000000000.0));
569 }
570
ptp_clock_delay(uint64_t egress,uint64_t ingress)571 void ptp_clock_delay(uint64_t egress, uint64_t ingress)
572 {
573 int64_t delay;
574
575 if (ptp_clk.timestamp.t1 == 0 || ptp_clk.timestamp.t2 == 0) {
576 return;
577 }
578
579 ptp_clk.timestamp.t3 = egress;
580 ptp_clk.timestamp.t4 = ingress;
581
582 delay = ((int64_t)(ptp_clk.timestamp.t2 - ptp_clk.timestamp.t3) +
583 (int64_t)(ptp_clk.timestamp.t4 - ptp_clk.timestamp.t1)) /
584 2LL;
585
586 LOG_DBG("Delay %lldns", delay);
587 ptp_clk.current_ds.mean_delay = clock_ns_to_timeinterval(delay);
588 }
589
ptp_clock_ports_list(void)590 sys_slist_t *ptp_clock_ports_list(void)
591 {
592 return &ptp_clk.ports_list;
593 }
594
ptp_clock_type(void)595 enum ptp_clock_type ptp_clock_type(void)
596 {
597 return (enum ptp_clock_type)ptp_clk.default_ds.type;
598 }
599
ptp_clock_default_ds(void)600 const struct ptp_default_ds *ptp_clock_default_ds(void)
601 {
602 return &ptp_clk.default_ds;
603 }
604
ptp_clock_parent_ds(void)605 const struct ptp_parent_ds *ptp_clock_parent_ds(void)
606 {
607 return &ptp_clk.parent_ds;
608 }
609
ptp_clock_current_ds(void)610 const struct ptp_current_ds *ptp_clock_current_ds(void)
611 {
612 return &ptp_clk.current_ds;
613 }
614
ptp_clock_time_prop_ds(void)615 const struct ptp_time_prop_ds *ptp_clock_time_prop_ds(void)
616 {
617 return &ptp_clk.time_prop_ds;
618 }
619
ptp_clock_ds(void)620 const struct ptp_dataset *ptp_clock_ds(void)
621 {
622 struct ptp_dataset *ds = &ptp_clk.dataset;
623
624 ds->priority1 = ptp_clk.default_ds.priority1;
625 ds->clk_quality = ptp_clk.default_ds.clk_quality;
626 ds->priority2 = ptp_clk.default_ds.priority2;
627 ds->steps_rm = 0;
628 ds->sender.port_number = 0;
629 ds->receiver.port_number = 0;
630 memcpy(&ds->clk_id, &ptp_clk.default_ds.clk_id, sizeof(ptp_clk_id));
631 memcpy(&ds->sender.clk_id, &ptp_clk.default_ds.clk_id, sizeof(ptp_clk_id));
632 memcpy(&ds->receiver.clk_id, &ptp_clk.default_ds.clk_id, sizeof(ptp_clk_id));
633 return ds;
634 }
635
ptp_clock_best_foreign_ds(void)636 const struct ptp_dataset *ptp_clock_best_foreign_ds(void)
637 {
638 return ptp_clk.best ? &ptp_clk.best->dataset : NULL;
639 }
640
ptp_clock_port_from_iface(struct net_if * iface)641 struct ptp_port *ptp_clock_port_from_iface(struct net_if *iface)
642 {
643 struct ptp_port *port;
644
645 SYS_SLIST_FOR_EACH_CONTAINER(&ptp_clk.ports_list, port, node) {
646 if (port->iface == iface) {
647 return port;
648 }
649 }
650
651 return NULL;
652 }
653
ptp_clock_pollfd_invalidate(void)654 void ptp_clock_pollfd_invalidate(void)
655 {
656 ptp_clk.pollfd_valid = false;
657 }
658
ptp_clock_signal_timeout(void)659 void ptp_clock_signal_timeout(void)
660 {
661 zvfs_eventfd_write(ptp_clk.pollfd[0].fd, 1);
662 }
663
ptp_clock_state_decision_req(void)664 void ptp_clock_state_decision_req(void)
665 {
666 ptp_clk.state_decision_event = true;
667 }
668
ptp_clock_port_add(struct ptp_port * port)669 void ptp_clock_port_add(struct ptp_port *port)
670 {
671 ptp_clk.default_ds.n_ports++;
672 sys_slist_append(&ptp_clk.ports_list, &port->node);
673 }
674
ptp_clock_best_time_transmitter(void)675 const struct ptp_foreign_tt_clock *ptp_clock_best_time_transmitter(void)
676 {
677 return ptp_clk.best;
678 }
679
ptp_clock_id_eq(const ptp_clk_id * c1,const ptp_clk_id * c2)680 bool ptp_clock_id_eq(const ptp_clk_id *c1, const ptp_clk_id *c2)
681 {
682 return memcmp(c1, c2, sizeof(ptp_clk_id)) == 0;
683 }
684