1 /*
2 * Copyright (c) 2017 Intel Corporation.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/logging/log.h>
8 LOG_MODULE_DECLARE(net_gptp, CONFIG_NET_GPTP_LOG_LEVEL);
9
10 #include "gptp_messages.h"
11 #include "gptp_md.h"
12 #include "gptp_data_set.h"
13 #include "gptp_private.h"
14
gptp_md_sync_prepare(struct net_pkt * pkt,struct gptp_md_sync_info * sync_send,int port_number)15 static void gptp_md_sync_prepare(struct net_pkt *pkt,
16 struct gptp_md_sync_info *sync_send,
17 int port_number)
18 {
19 struct gptp_hdr *hdr;
20
21 hdr = GPTP_HDR(pkt);
22
23 memcpy(&hdr->port_id.clk_id, &sync_send->src_port_id.clk_id,
24 GPTP_CLOCK_ID_LEN);
25
26 hdr->port_id.port_number = htons(port_number);
27
28 hdr->log_msg_interval = sync_send->log_msg_interval;
29 }
30
gptp_md_follow_up_prepare(struct net_pkt * pkt,struct gptp_md_sync_info * sync_send,int port_number)31 static void gptp_md_follow_up_prepare(struct net_pkt *pkt,
32 struct gptp_md_sync_info *sync_send,
33 int port_number)
34 {
35 struct gptp_hdr *hdr;
36 struct gptp_follow_up *fup;
37
38 hdr = GPTP_HDR(pkt);
39 fup = GPTP_FOLLOW_UP(pkt);
40
41 memcpy(&hdr->port_id.clk_id, &sync_send->src_port_id.clk_id,
42 GPTP_CLOCK_ID_LEN);
43
44 hdr->port_id.port_number = htons(port_number);
45
46 hdr->log_msg_interval = sync_send->log_msg_interval;
47
48 fup->tlv_hdr.type = htons(GPTP_TLV_ORGANIZATION_EXT);
49 fup->tlv_hdr.len = htons(sizeof(struct gptp_follow_up_tlv));
50 fup->tlv.org_id[0] = GPTP_FUP_TLV_ORG_ID_BYTE_0;
51 fup->tlv.org_id[1] = GPTP_FUP_TLV_ORG_ID_BYTE_1;
52 fup->tlv.org_id[2] = GPTP_FUP_TLV_ORG_ID_BYTE_2;
53 fup->tlv.org_sub_type[0] = 0U;
54 fup->tlv.org_sub_type[1] = 0U;
55 fup->tlv.org_sub_type[2] = GPTP_FUP_TLV_ORG_SUB_TYPE;
56
57 fup->tlv.cumulative_scaled_rate_offset =
58 (sync_send->rate_ratio - 1.0) * GPTP_POW2_41;
59 fup->tlv.cumulative_scaled_rate_offset =
60 ntohl(fup->tlv.cumulative_scaled_rate_offset);
61 fup->tlv.gm_time_base_indicator =
62 ntohs(sync_send->gm_time_base_indicator);
63 fup->tlv.last_gm_phase_change.high =
64 ntohl(sync_send->last_gm_phase_change.high);
65 fup->tlv.last_gm_phase_change.low =
66 ntohll(sync_send->last_gm_phase_change.low);
67 fup->tlv.scaled_last_gm_freq_change = sync_send->last_gm_freq_change;
68 fup->tlv.scaled_last_gm_freq_change =
69 ntohl(fup->tlv.scaled_last_gm_freq_change);
70 }
71
gptp_set_md_sync_receive(int port,struct gptp_md_sync_info * sync_rcv)72 static int gptp_set_md_sync_receive(int port,
73 struct gptp_md_sync_info *sync_rcv)
74 {
75 struct gptp_sync_rcv_state *state;
76 struct gptp_port_ds *port_ds;
77 struct gptp_hdr *sync_hdr, *fup_hdr;
78 struct gptp_follow_up *fup;
79 struct net_ptp_time *sync_ts;
80 double prop_delay_rated;
81 double delay_asymmetry_rated;
82
83 state = &GPTP_PORT_STATE(port)->sync_rcv;
84 if (!state->rcvd_sync_ptr || !state->rcvd_follow_up_ptr) {
85 return -EINVAL;
86 }
87
88 port_ds = GPTP_PORT_DS(port);
89
90 sync_hdr = GPTP_HDR(state->rcvd_sync_ptr);
91 fup_hdr = GPTP_HDR(state->rcvd_follow_up_ptr);
92 fup = GPTP_FOLLOW_UP(state->rcvd_follow_up_ptr);
93 sync_ts = &state->rcvd_sync_ptr->timestamp;
94
95 sync_rcv->follow_up_correction_field =
96 (ntohll(fup_hdr->correction_field) >> 16);
97 memcpy(&sync_rcv->src_port_id, &sync_hdr->port_id,
98 sizeof(struct gptp_port_identity));
99 sync_rcv->log_msg_interval = fup_hdr->log_msg_interval;
100 sync_rcv->precise_orig_ts._sec.high =
101 ntohs(fup->prec_orig_ts_secs_high);
102 sync_rcv->precise_orig_ts._sec.low = ntohl(fup->prec_orig_ts_secs_low);
103 sync_rcv->precise_orig_ts.nanosecond = ntohl(fup->prec_orig_ts_nsecs);
104
105 /* Compute time when sync was sent by the remote. */
106 sync_rcv->upstream_tx_time = sync_ts->second;
107 sync_rcv->upstream_tx_time *= NSEC_PER_SEC;
108 sync_rcv->upstream_tx_time += sync_ts->nanosecond;
109
110 prop_delay_rated = port_ds->neighbor_prop_delay;
111 prop_delay_rated /= port_ds->neighbor_rate_ratio;
112
113 sync_rcv->upstream_tx_time -= prop_delay_rated;
114
115 delay_asymmetry_rated = port_ds->delay_asymmetry;
116 delay_asymmetry_rated /= port_ds->neighbor_rate_ratio;
117
118 sync_rcv->upstream_tx_time -= delay_asymmetry_rated;
119
120 sync_rcv->rate_ratio = ntohl(fup->tlv.cumulative_scaled_rate_offset);
121 sync_rcv->rate_ratio /= GPTP_POW2_41;
122 sync_rcv->rate_ratio += 1;
123
124 sync_rcv->gm_time_base_indicator =
125 ntohs(fup->tlv.gm_time_base_indicator);
126 sync_rcv->last_gm_phase_change.high =
127 ntohl(fup->tlv.last_gm_phase_change.high);
128 sync_rcv->last_gm_phase_change.low =
129 ntohll(fup->tlv.last_gm_phase_change.low);
130 sync_rcv->last_gm_freq_change =
131 ntohl(fup->tlv.scaled_last_gm_freq_change);
132
133 return 0;
134 }
135
gptp_md_pdelay_reset(int port)136 static void gptp_md_pdelay_reset(int port)
137 {
138 struct gptp_pdelay_req_state *state;
139 struct gptp_port_ds *port_ds;
140
141 NET_WARN("Reset Pdelay requests");
142
143 state = &GPTP_PORT_STATE(port)->pdelay_req;
144 port_ds = GPTP_PORT_DS(port);
145
146 if (state->lost_responses < port_ds->allowed_lost_responses) {
147 state->lost_responses += 1U;
148 } else {
149 port_ds->is_measuring_delay = false;
150 port_ds->as_capable = false;
151 state->init_pdelay_compute = true;
152 }
153 }
154
gptp_md_pdelay_check_multiple_resp(int port)155 static void gptp_md_pdelay_check_multiple_resp(int port)
156 {
157 struct gptp_pdelay_req_state *state;
158 struct gptp_port_ds *port_ds;
159 int duration;
160
161 state = &GPTP_PORT_STATE(port)->pdelay_req;
162 port_ds = GPTP_PORT_DS(port);
163
164 if ((state->rcvd_pdelay_resp > 1) ||
165 (state->rcvd_pdelay_follow_up > 1)) {
166 port_ds->as_capable = false;
167 NET_WARN("Too many responses (%d / %d)",
168 state->rcvd_pdelay_resp,
169 state->rcvd_pdelay_follow_up);
170 state->multiple_resp_count++;
171 } else {
172 state->multiple_resp_count = 0U;
173 }
174
175 if (state->multiple_resp_count >= 3U) {
176 state->multiple_resp_count = 0U;
177 k_timer_stop(&state->pdelay_timer);
178 state->pdelay_timer_expired = false;
179
180 /* Subtract time spent since last pDelay request. */
181 duration = GPTP_MULTIPLE_PDELAY_RESP_WAIT -
182 gptp_uscaled_ns_to_timer_ms(&port_ds->pdelay_req_itv);
183
184 k_timer_start(&state->pdelay_timer, K_MSEC(duration),
185 K_NO_WAIT);
186 } else {
187 state->state = GPTP_PDELAY_REQ_SEND_REQ;
188 }
189 }
190
gptp_md_compute_pdelay_rate_ratio(int port)191 static void gptp_md_compute_pdelay_rate_ratio(int port)
192 {
193 uint64_t ingress_tstamp = 0U;
194 uint64_t resp_evt_tstamp = 0U;
195 struct gptp_pdelay_resp_follow_up *fup;
196 struct gptp_pdelay_req_state *state;
197 struct gptp_port_ds *port_ds;
198 struct net_pkt *pkt;
199 struct gptp_hdr *hdr;
200 double neighbor_rate_ratio;
201
202 state = &GPTP_PORT_STATE(port)->pdelay_req;
203 port_ds = GPTP_PORT_DS(port);
204
205 /* Get ingress timestamp. */
206 pkt = state->rcvd_pdelay_resp_ptr;
207 if (pkt) {
208 ingress_tstamp =
209 gptp_timestamp_to_nsec(net_pkt_timestamp(pkt));
210 }
211
212 /* Get peer corrected timestamp. */
213 pkt = state->rcvd_pdelay_follow_up_ptr;
214 if (pkt) {
215 hdr = GPTP_HDR(pkt);
216 fup = GPTP_PDELAY_RESP_FOLLOWUP(pkt);
217
218 resp_evt_tstamp = ntohs(fup->resp_orig_ts_secs_high);
219 resp_evt_tstamp <<= 32;
220 resp_evt_tstamp |= ntohl(fup->resp_orig_ts_secs_low);
221 resp_evt_tstamp *= NSEC_PER_SEC;
222 resp_evt_tstamp += ntohl(fup->resp_orig_ts_nsecs);
223 resp_evt_tstamp += (ntohll(hdr->correction_field) >> 16);
224 }
225
226 if (state->init_pdelay_compute) {
227 state->init_pdelay_compute = false;
228
229 state->ini_resp_ingress_tstamp = ingress_tstamp;
230 state->ini_resp_evt_tstamp = resp_evt_tstamp;
231
232 neighbor_rate_ratio = 1.0;
233
234 state->neighbor_rate_ratio_valid = false;
235 } else {
236 if (resp_evt_tstamp == state->ini_resp_evt_tstamp) {
237 state->neighbor_rate_ratio_valid = false;
238 neighbor_rate_ratio = 1.0;
239 } else {
240 neighbor_rate_ratio =
241 (resp_evt_tstamp - state->ini_resp_evt_tstamp);
242 neighbor_rate_ratio /=
243 (ingress_tstamp -
244 state->ini_resp_ingress_tstamp);
245
246 /* Measure the ratio with the previously sent response.
247 */
248 state->ini_resp_ingress_tstamp = ingress_tstamp;
249 state->ini_resp_evt_tstamp = resp_evt_tstamp;
250 state->neighbor_rate_ratio_valid = true;
251 }
252 }
253
254 port_ds->neighbor_rate_ratio = neighbor_rate_ratio;
255 port_ds->neighbor_rate_ratio_valid = state->neighbor_rate_ratio_valid;
256 }
257
gptp_md_compute_prop_time(int port)258 static void gptp_md_compute_prop_time(int port)
259 {
260 uint64_t t1_ns = 0U, t2_ns = 0U, t3_ns = 0U, t4_ns = 0U;
261 struct gptp_pdelay_resp_follow_up *fup;
262 struct gptp_pdelay_req_state *state;
263 struct gptp_pdelay_resp *resp;
264 struct gptp_port_ds *port_ds;
265 struct gptp_hdr *hdr;
266 struct net_pkt *pkt;
267 double prop_time, turn_around;
268
269 state = &GPTP_PORT_STATE(port)->pdelay_req;
270 port_ds = GPTP_PORT_DS(port);
271
272 /* Get egress timestamp. */
273 pkt = state->tx_pdelay_req_ptr;
274 if (pkt) {
275 t1_ns = gptp_timestamp_to_nsec(net_pkt_timestamp(pkt));
276 }
277
278 /* Get ingress timestamp. */
279 pkt = state->rcvd_pdelay_resp_ptr;
280 if (pkt) {
281 t4_ns = gptp_timestamp_to_nsec(net_pkt_timestamp(pkt));
282 }
283
284 /* Get peer corrected timestamps. */
285 pkt = state->rcvd_pdelay_resp_ptr;
286 if (pkt) {
287 hdr = GPTP_HDR(pkt);
288 resp = GPTP_PDELAY_RESP(pkt);
289
290 t2_ns = ((uint64_t)ntohs(resp->req_receipt_ts_secs_high)) << 32;
291 t2_ns |= ntohl(resp->req_receipt_ts_secs_low);
292 t2_ns *= NSEC_PER_SEC;
293 t2_ns += ntohl(resp->req_receipt_ts_nsecs);
294 t2_ns += (ntohll(hdr->correction_field) >> 16);
295 }
296
297 pkt = state->rcvd_pdelay_follow_up_ptr;
298 if (pkt) {
299 hdr = GPTP_HDR(pkt);
300 fup = GPTP_PDELAY_RESP_FOLLOWUP(pkt);
301
302 t3_ns = ((uint64_t)ntohs(fup->resp_orig_ts_secs_high)) << 32;
303 t3_ns |= ntohl(fup->resp_orig_ts_secs_low);
304 t3_ns *= NSEC_PER_SEC;
305 t3_ns += ntohl(fup->resp_orig_ts_nsecs);
306 t3_ns += (ntohll(hdr->correction_field) >> 16);
307 }
308
309 prop_time = t4_ns - t1_ns;
310
311 turn_around = t3_ns - t2_ns;
312
313 /* Adjusting the turn-around time for peer to local clock rate
314 * difference. The check is implemented the same way as how Avnu/gptp
315 * daemon is doing it. This comment is also found in their source
316 * for the magic values "TODO: Are these .998 and 1.002 specifically
317 * defined in the standard?"
318 */
319 if (port_ds->neighbor_rate_ratio > .998 &&
320 port_ds->neighbor_rate_ratio < 1.002) {
321 turn_around *= port_ds->neighbor_rate_ratio;
322 }
323
324 prop_time -= turn_around;
325 prop_time /= 2;
326
327 port_ds->neighbor_prop_delay = prop_time;
328 }
329
gptp_md_pdelay_compute(int port)330 static void gptp_md_pdelay_compute(int port)
331 {
332 struct gptp_pdelay_req_state *state;
333 struct gptp_port_ds *port_ds;
334 struct gptp_hdr *hdr;
335 struct net_pkt *pkt;
336 bool local_clock;
337
338 state = &GPTP_PORT_STATE(port)->pdelay_req;
339 port_ds = GPTP_PORT_DS(port);
340
341 if (!state->tx_pdelay_req_ptr || !state->rcvd_pdelay_resp_ptr ||
342 !state->rcvd_pdelay_follow_up_ptr) {
343 NET_ERR("Compute path delay called without buffer ready");
344 port_ds->as_capable = false;
345 goto out;
346 }
347
348 if (port_ds->compute_neighbor_rate_ratio) {
349 gptp_md_compute_pdelay_rate_ratio(port);
350 }
351
352 if (port_ds->compute_neighbor_prop_delay) {
353 gptp_md_compute_prop_time(port);
354
355 NET_DBG("Neighbor prop delay %d",
356 (int32_t)port_ds->neighbor_prop_delay);
357 }
358
359 state->lost_responses = 0U;
360 port_ds->is_measuring_delay = true;
361
362 pkt = state->rcvd_pdelay_follow_up_ptr;
363 hdr = GPTP_HDR(pkt);
364
365 local_clock = !memcmp(gptp_domain.default_ds.clk_id,
366 hdr->port_id.clk_id,
367 GPTP_CLOCK_ID_LEN);
368 if (local_clock) {
369 NET_WARN("Discard path delay response from local clock.");
370 goto out;
371 }
372
373 if (!state->neighbor_rate_ratio_valid) {
374 goto out;
375 }
376
377 /*
378 * Currently, if the computed delay is negative, this means
379 * that it is negligible enough compared to other factors.
380 */
381 if ((port_ds->neighbor_prop_delay <=
382 port_ds->neighbor_prop_delay_thresh)) {
383 port_ds->as_capable = true;
384 } else {
385 port_ds->as_capable = false;
386
387 NET_WARN("Not AS capable: %u ns > %u ns",
388 (uint32_t)port_ds->neighbor_prop_delay,
389 (uint32_t)port_ds->neighbor_prop_delay_thresh);
390
391 GPTP_STATS_INC(port, neighbor_prop_delay_exceeded);
392 }
393
394 out:
395 /* Release buffers. */
396 if (state->tx_pdelay_req_ptr) {
397 net_pkt_unref(state->tx_pdelay_req_ptr);
398 state->tx_pdelay_req_ptr = NULL;
399 }
400
401 if (state->rcvd_pdelay_resp_ptr) {
402 net_pkt_unref(state->rcvd_pdelay_resp_ptr);
403 state->rcvd_pdelay_resp_ptr = NULL;
404 }
405
406 if (state->rcvd_pdelay_follow_up_ptr) {
407 net_pkt_unref(state->rcvd_pdelay_follow_up_ptr);
408 state->rcvd_pdelay_follow_up_ptr = NULL;
409 }
410 }
411
gptp_md_pdelay_req_timeout(struct k_timer * timer)412 static void gptp_md_pdelay_req_timeout(struct k_timer *timer)
413 {
414 struct gptp_pdelay_req_state *state;
415 int port;
416
417 for (port = GPTP_PORT_START; port < GPTP_PORT_END; port++) {
418 state = &GPTP_PORT_STATE(port)->pdelay_req;
419 if (timer == &state->pdelay_timer) {
420 state->pdelay_timer_expired = true;
421
422 if (state->rcvd_pdelay_resp == 0U) {
423 GPTP_STATS_INC(port,
424 pdelay_allowed_lost_resp_exceed_count);
425 }
426 }
427 }
428 }
429
gptp_md_start_pdelay_req(int port)430 static void gptp_md_start_pdelay_req(int port)
431 {
432 struct gptp_pdelay_req_state *state;
433 struct gptp_port_ds *port_ds;
434
435 port_ds = GPTP_PORT_DS(port);
436 state = &GPTP_PORT_STATE(port)->pdelay_req;
437
438 port_ds->neighbor_rate_ratio = 1.0;
439 port_ds->is_measuring_delay = false;
440 port_ds->as_capable = false;
441 state->lost_responses = 0U;
442 state->rcvd_pdelay_resp = 0U;
443 state->rcvd_pdelay_follow_up = 0U;
444 state->multiple_resp_count = 0U;
445 }
446
gptp_md_follow_up_receipt_timeout(struct k_timer * timer)447 static void gptp_md_follow_up_receipt_timeout(struct k_timer *timer)
448 {
449 struct gptp_sync_rcv_state *state;
450 int port;
451
452 for (port = GPTP_PORT_START; port < GPTP_PORT_END; port++) {
453 state = &GPTP_PORT_STATE(port)->sync_rcv;
454 if (timer == &state->follow_up_discard_timer) {
455 NET_WARN("No %s received after %s message",
456 "FOLLOWUP", "SYNC");
457 state->follow_up_timeout_expired = true;
458 }
459 }
460 }
461
gptp_md_init_pdelay_req_state_machine(int port)462 static void gptp_md_init_pdelay_req_state_machine(int port)
463 {
464 struct gptp_pdelay_req_state *state;
465
466 state = &GPTP_PORT_STATE(port)->pdelay_req;
467
468 k_timer_init(&state->pdelay_timer, gptp_md_pdelay_req_timeout, NULL);
469
470 state->state = GPTP_PDELAY_REQ_NOT_ENABLED;
471
472 state->neighbor_rate_ratio_valid = false;
473 state->init_pdelay_compute = true;
474 state->rcvd_pdelay_resp = 0U;
475 state->rcvd_pdelay_follow_up = 0U;
476 state->pdelay_timer_expired = false;
477
478 state->rcvd_pdelay_resp_ptr = NULL;
479 state->rcvd_pdelay_follow_up_ptr = NULL;
480 state->tx_pdelay_req_ptr = NULL;
481
482 state->ini_resp_evt_tstamp = 0U;
483 state->ini_resp_ingress_tstamp = 0U;
484 state->lost_responses = 0U;
485 }
486
gptp_md_init_pdelay_resp_state_machine(int port)487 static void gptp_md_init_pdelay_resp_state_machine(int port)
488 {
489 struct gptp_pdelay_resp_state *state;
490
491 state = &GPTP_PORT_STATE(port)->pdelay_resp;
492
493 state->state = GPTP_PDELAY_RESP_NOT_ENABLED;
494 }
495
gptp_md_init_sync_rcv_state_machine(int port)496 static void gptp_md_init_sync_rcv_state_machine(int port)
497 {
498 struct gptp_sync_rcv_state *state;
499
500 state = &GPTP_PORT_STATE(port)->sync_rcv;
501
502 k_timer_init(&state->follow_up_discard_timer,
503 gptp_md_follow_up_receipt_timeout, NULL);
504
505 state->rcvd_sync = false;
506 state->rcvd_follow_up = false;
507 state->rcvd_sync_ptr = NULL;
508 state->rcvd_follow_up_ptr = NULL;
509
510 state->follow_up_timeout_expired = false;
511 state->follow_up_receipt_timeout = 0U;
512
513 state->state = GPTP_SYNC_RCV_DISCARD;
514 }
515
gptp_md_init_sync_send_state_machine(int port)516 static void gptp_md_init_sync_send_state_machine(int port)
517 {
518 struct gptp_sync_send_state *state;
519
520 state = &GPTP_PORT_STATE(port)->sync_send;
521
522 state->rcvd_md_sync = false;
523 state->md_sync_timestamp_avail = false;
524 state->sync_send_ptr = NULL;
525 state->sync_ptr = NULL;
526
527 state->state = GPTP_SYNC_SEND_INITIALIZING;
528 }
529
gptp_md_init_state_machine(void)530 void gptp_md_init_state_machine(void)
531 {
532 int port;
533
534 for (port = GPTP_PORT_START; port < GPTP_PORT_END; port++) {
535 gptp_md_init_pdelay_req_state_machine(port);
536 gptp_md_init_pdelay_resp_state_machine(port);
537 gptp_md_init_sync_rcv_state_machine(port);
538 gptp_md_init_sync_send_state_machine(port);
539 }
540 }
541
gptp_md_pdelay_req_state_machine(int port)542 static void gptp_md_pdelay_req_state_machine(int port)
543 {
544 struct gptp_port_ds *port_ds;
545 struct gptp_pdelay_req_state *state;
546 struct net_pkt *pkt;
547
548 state = &GPTP_PORT_STATE(port)->pdelay_req;
549 port_ds = GPTP_PORT_DS(port);
550
551 /* Unset AS-Capable if multiple responses to a pDelay request have been
552 * received.
553 */
554 if (state->rcvd_pdelay_resp > 1 || state->rcvd_pdelay_follow_up > 1) {
555 port_ds->as_capable = false;
556 }
557
558 if (!port_ds->ptt_port_enabled) {
559 /* Make sure the timer is stopped. */
560 k_timer_stop(&state->pdelay_timer);
561 state->state = GPTP_PDELAY_REQ_NOT_ENABLED;
562 }
563
564 switch (state->state) {
565 case GPTP_PDELAY_REQ_NOT_ENABLED:
566 if (port_ds->ptt_port_enabled) {
567 /* (Re)Init interval (as defined in
568 * LinkDelaySyncIntervalSetting state machine).
569 */
570 port_ds->cur_log_pdelay_req_itv =
571 port_ds->ini_log_pdelay_req_itv;
572
573 gptp_set_time_itv(&port_ds->pdelay_req_itv, 1,
574 port_ds->cur_log_pdelay_req_itv);
575
576 port_ds->compute_neighbor_rate_ratio = true;
577 port_ds->compute_neighbor_prop_delay = true;
578
579 state->pdelay_timer_expired = true;
580 state->state = GPTP_PDELAY_REQ_INITIAL_SEND_REQ;
581 }
582
583 break;
584
585 case GPTP_PDELAY_REQ_RESET:
586 gptp_md_pdelay_reset(port);
587 /* Send a request on the next timer expiry. */
588 state->state = GPTP_PDELAY_REQ_WAIT_ITV_TIMER;
589 break;
590
591 case GPTP_PDELAY_REQ_INITIAL_SEND_REQ:
592 gptp_md_start_pdelay_req(port);
593 __fallthrough;
594
595 case GPTP_PDELAY_REQ_SEND_REQ:
596 if (state->tx_pdelay_req_ptr) {
597 net_pkt_unref(state->tx_pdelay_req_ptr);
598 state->tx_pdelay_req_ptr = NULL;
599 }
600
601 if (state->rcvd_pdelay_resp_ptr) {
602 net_pkt_unref(state->rcvd_pdelay_resp_ptr);
603 state->rcvd_pdelay_resp_ptr = NULL;
604 }
605
606 if (state->rcvd_pdelay_follow_up_ptr) {
607 net_pkt_unref(state->rcvd_pdelay_follow_up_ptr);
608 state->rcvd_pdelay_follow_up_ptr = NULL;
609 }
610
611 gptp_send_pdelay_req(port);
612
613 k_timer_stop(&state->pdelay_timer);
614 state->pdelay_timer_expired = false;
615 k_timer_start(&state->pdelay_timer,
616 K_MSEC(gptp_uscaled_ns_to_timer_ms(
617 &port_ds->pdelay_req_itv)),
618 K_NO_WAIT);
619 /*
620 * Transition directly to GPTP_PDELAY_REQ_WAIT_RESP.
621 * Check for the TX timestamp will be done during
622 * the computation of the path delay.
623 */
624 state->state = GPTP_PDELAY_REQ_WAIT_RESP;
625 break;
626
627 case GPTP_PDELAY_REQ_WAIT_RESP:
628 if (state->pdelay_timer_expired) {
629 state->state = GPTP_PDELAY_REQ_RESET;
630 } else if (state->rcvd_pdelay_resp != 0U) {
631 pkt = state->rcvd_pdelay_resp_ptr;
632 if (!gptp_handle_pdelay_resp(port, pkt)) {
633 state->state = GPTP_PDELAY_REQ_WAIT_FOLLOW_UP;
634 } else {
635 state->state = GPTP_PDELAY_REQ_RESET;
636 }
637 }
638
639 break;
640
641 case GPTP_PDELAY_REQ_WAIT_FOLLOW_UP:
642 if (state->pdelay_timer_expired) {
643 state->state = GPTP_PDELAY_REQ_RESET;
644 } else if (state->rcvd_pdelay_follow_up != 0U) {
645 pkt = state->rcvd_pdelay_follow_up_ptr;
646 if (!gptp_handle_pdelay_follow_up(port, pkt)) {
647 gptp_md_pdelay_compute(port);
648 state->state = GPTP_PDELAY_REQ_WAIT_ITV_TIMER;
649 } else {
650 state->state = GPTP_PDELAY_REQ_RESET;
651 }
652 }
653
654 break;
655
656 case GPTP_PDELAY_REQ_WAIT_ITV_TIMER:
657 if (state->pdelay_timer_expired) {
658 gptp_md_pdelay_check_multiple_resp(port);
659
660 state->rcvd_pdelay_resp = 0U;
661 state->rcvd_pdelay_follow_up = 0U;
662 }
663
664 break;
665 }
666 }
667
gptp_md_pdelay_resp_state_machine(int port)668 static void gptp_md_pdelay_resp_state_machine(int port)
669 {
670 struct gptp_port_ds *port_ds;
671 struct gptp_pdelay_resp_state *state;
672
673 state = &GPTP_PORT_STATE(port)->pdelay_resp;
674 port_ds = GPTP_PORT_DS(port);
675
676 if (!port_ds->ptt_port_enabled) {
677 state->state = GPTP_PDELAY_RESP_NOT_ENABLED;
678 }
679
680 switch (state->state) {
681 case GPTP_PDELAY_RESP_NOT_ENABLED:
682 if (port_ds->ptt_port_enabled) {
683 state->state = GPTP_PDELAY_RESP_INITIAL_WAIT_REQ;
684 }
685
686 break;
687
688 case GPTP_PDELAY_RESP_INITIAL_WAIT_REQ:
689 case GPTP_PDELAY_RESP_WAIT_REQ:
690 /* Handled in gptp_handle_msg for latency considerations. */
691 break;
692
693 case GPTP_PDELAY_RESP_WAIT_TSTAMP:
694 /* Handled in gptp_follow_up_callback. */
695 break;
696 }
697
698 }
699
gptp_md_sync_receive_state_machine(int port)700 static void gptp_md_sync_receive_state_machine(int port)
701 {
702 struct gptp_port_ds *port_ds;
703 struct gptp_sync_rcv_state *state;
704 struct gptp_pss_rcv_state *pss_state;
705
706 state = &GPTP_PORT_STATE(port)->sync_rcv;
707 pss_state = &GPTP_PORT_STATE(port)->pss_rcv;
708 port_ds = GPTP_PORT_DS(port);
709
710 if ((!port_ds->ptt_port_enabled) || !port_ds->as_capable) {
711 /* Make sure the timer is stopped. */
712 k_timer_stop(&state->follow_up_discard_timer);
713
714 /* Discard all received messages. */
715 if (state->rcvd_sync_ptr) {
716 net_pkt_unref(state->rcvd_sync_ptr);
717 state->rcvd_sync_ptr = NULL;
718 }
719
720 if (state->rcvd_follow_up_ptr) {
721 net_pkt_unref(state->rcvd_follow_up_ptr);
722 state->rcvd_follow_up_ptr = NULL;
723 }
724
725 state->rcvd_sync = false;
726 state->rcvd_follow_up = false;
727 state->state = GPTP_SYNC_RCV_DISCARD;
728 return;
729 }
730
731 switch (state->state) {
732 case GPTP_SYNC_RCV_DISCARD:
733 case GPTP_SYNC_RCV_WAIT_SYNC:
734 if (state->rcvd_sync) {
735 gptp_handle_sync(port, state->rcvd_sync_ptr);
736 state->rcvd_sync = false;
737 state->state = GPTP_SYNC_RCV_WAIT_FOLLOW_UP;
738 } else if (state->rcvd_follow_up) {
739 /* Delete late/early message. */
740 if (state->rcvd_follow_up_ptr) {
741 net_pkt_unref(state->rcvd_follow_up_ptr);
742 state->rcvd_follow_up_ptr = NULL;
743 }
744
745 state->rcvd_follow_up = false;
746 }
747
748 break;
749
750 case GPTP_SYNC_RCV_WAIT_FOLLOW_UP:
751 /* Never received a follow up for a sync message. */
752 if (state->follow_up_timeout_expired) {
753 k_timer_stop(&state->follow_up_discard_timer);
754 state->follow_up_timeout_expired = false;
755 state->state = GPTP_SYNC_RCV_DISCARD;
756 if (state->rcvd_sync_ptr) {
757 net_pkt_unref(state->rcvd_sync_ptr);
758 state->rcvd_sync_ptr = NULL;
759 }
760
761 state->rcvd_sync = false;
762 } else if (state->rcvd_sync) {
763 /* Handle received extra sync. */
764 gptp_handle_sync(port, state->rcvd_sync_ptr);
765 state->rcvd_sync = false;
766 } else if (state->rcvd_follow_up) {
767 if (!gptp_handle_follow_up(
768 port, state->rcvd_follow_up_ptr)) {
769
770 /*
771 * Fill the structure to be sent to
772 * PortSyncSyncReceive.
773 */
774 gptp_set_md_sync_receive(port,
775 &pss_state->sync_rcv);
776
777 pss_state->rcvd_md_sync = true;
778
779 state->state = GPTP_SYNC_RCV_WAIT_SYNC;
780
781 /* Buffers can be released now. */
782 if (state->rcvd_sync_ptr) {
783 net_pkt_unref(state->rcvd_sync_ptr);
784 state->rcvd_sync_ptr = NULL;
785 }
786
787 k_timer_stop(&state->follow_up_discard_timer);
788 state->follow_up_timeout_expired = false;
789 }
790 }
791
792 if (state->rcvd_follow_up_ptr) {
793 net_pkt_unref(state->rcvd_follow_up_ptr);
794 state->rcvd_follow_up_ptr = NULL;
795 }
796
797 state->rcvd_follow_up = false;
798 break;
799 }
800 }
801
gptp_md_sync_send_state_machine(int port)802 static void gptp_md_sync_send_state_machine(int port)
803 {
804 struct gptp_port_ds *port_ds;
805 struct gptp_sync_send_state *state;
806 struct net_pkt *pkt;
807
808 state = &GPTP_PORT_STATE(port)->sync_send;
809 port_ds = GPTP_PORT_DS(port);
810
811 if ((!port_ds->ptt_port_enabled) || !port_ds->as_capable) {
812 state->rcvd_md_sync = false;
813 state->state = GPTP_SYNC_SEND_INITIALIZING;
814
815 /* Sync sequence id is initialized in the port_ds init function
816 */
817 return;
818 }
819
820 switch (state->state) {
821 case GPTP_SYNC_SEND_INITIALIZING:
822 state->state = GPTP_SYNC_SEND_SEND_SYNC;
823 break;
824
825 case GPTP_SYNC_SEND_SEND_SYNC:
826 if (state->rcvd_md_sync) {
827 pkt = gptp_prepare_sync(port);
828 if (pkt) {
829 /* Reference message to track timestamp info */
830 state->sync_ptr = net_pkt_ref(pkt);
831 gptp_md_sync_prepare(pkt,
832 state->sync_send_ptr,
833 port);
834 gptp_send_sync(port, pkt);
835 }
836
837 state->rcvd_md_sync = false;
838 state->state = GPTP_SYNC_SEND_SEND_FUP;
839 }
840
841 break;
842
843 case GPTP_SYNC_SEND_SEND_FUP:
844 if (state->md_sync_timestamp_avail) {
845 state->md_sync_timestamp_avail = false;
846
847 if (!state->sync_ptr) {
848 NET_ERR("Sync message not available");
849 break;
850 }
851
852 pkt = gptp_prepare_follow_up(port, state->sync_ptr);
853 if (pkt) {
854 gptp_md_follow_up_prepare(pkt,
855 state->sync_send_ptr,
856 port);
857 gptp_send_follow_up(port, pkt);
858 }
859
860 net_pkt_unref(state->sync_ptr);
861 state->sync_ptr = NULL;
862
863 state->state = GPTP_SYNC_SEND_SEND_SYNC;
864 }
865
866 break;
867 }
868 }
869
gptp_md_state_machines(int port)870 void gptp_md_state_machines(int port)
871 {
872 gptp_md_pdelay_req_state_machine(port);
873 gptp_md_pdelay_resp_state_machine(port);
874 gptp_md_sync_receive_state_machine(port);
875 gptp_md_sync_send_state_machine(port);
876 }
877