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