[Linuxptp-devel] [RFC 1/1] Add avnu_ap to enable AVnu Automotive Profile
PTP IEEE 1588 stack for Linux
Brought to you by:
rcochran
From: Vedang P. <ved...@in...> - 2018-07-16 21:35:32
|
This adds a new config option "avnu_ap" for ptp4l. Setting this option to 1 will enable the AVnu Automotive Profile (AVnu AP) [1] for the device. When it is active, best master clock algorithm (BMCA) will be disabled. gmCapable will be used to determine whether a device will be grand master or slave. By default, avnu_ap is set to 0. Setting it to 1 enables the AVnu Automotive Profile. It will have following consequences while running ptp4l: - When the port will initialize, the port will directly go into PS_GRAND_MASTER when gmCapable set to 1 or to PS_UNCALIBRATED when gmCapable is set to 0. - BMCA won't run. So, Announce messages (on master) and announce timeouts (on slave) will be disabled. - Source port identity won't be checked while processing Sync and Follow_Up messages. - SLAVE devices will not transition to MASTER when it receives Sync timeout. In all, this will add capabilities described in sections 6.2.1.1 and 6.3 (lines 191 to 199 - first 2 points) in [1]. Please note that this option is currently only supported for ordinary clocks running on 802.3 network transport. Defining avnu_ap in boundary clocks or any other mode of transport will return error. [1] - http://avnu.org/wp-content/uploads/2014/05/Automotive-Ethernet-AVB- Func-Interop-Spec-v1.5-Public.pdf Change-Id: Ida703d867c3f3bf405b66021c91d444505e9b042 Signed-off-by: Patel, Vedang <ved...@in...> --- clock.c | 15 +++++++- clock.h | 8 +++++ config.c | 1 + configs/AVnu.cfg | 22 ++++++++++++ configs/default.cfg | 1 + fsm.c | 11 ++++++ port.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++---- ptp4l.8 | 10 ++++++ 8 files changed, 159 insertions(+), 8 deletions(-) create mode 100644 configs/AVnu.cfg diff --git a/clock.c b/clock.c index 2400b2fb0dc3..501a1f511ba6 100644 --- a/clock.c +++ b/clock.c @@ -98,7 +98,8 @@ struct clock { int sde; int free_running; int freq_est_interval; - int grand_master_capable; /* for 802.1AS only */ + int grand_master_capable; /* for 802.1AS and AVnu AP only */ + int avnu_ap; /* For AVnu Automotive Profile (AVnu AP) only */ int utc_timescale; int utc_offset_set; int leap_set; @@ -1093,6 +1094,13 @@ struct clock *clock_create(enum clock_type type, struct config *config, } } + /* Specific to AVnu Automotive Profile. */ + c->avnu_ap = config_get_int(config, NULL, "avnu_ap"); + if (c->avnu_ap && c->type != CLOCK_TYPE_ORDINARY) { + pr_err("Only ordinary clocks are supported by AVnu_AP.\n"); + return NULL; + } + /* Initialize the parentDS. */ clock_update_grandmaster(c); c->dad.pds.parentStats = 0; @@ -1806,3 +1814,8 @@ double clock_rate_ratio(struct clock *c) } return servo_rate_ratio(c->servo); } + +int clock_avnu_ap(struct clock *c) +{ + return c->avnu_ap; +} diff --git a/clock.h b/clock.h index cc2910a59c4a..a51bca19b0ae 100644 --- a/clock.h +++ b/clock.h @@ -338,4 +338,12 @@ void clock_check_ts(struct clock *c, uint64_t ts); */ double clock_rate_ratio(struct clock *c); +/** + * Obtain the value for avnu_ap. This is used to determine whether device is + * running AVnu Automotive profile. + * @param c The clock interface. + * @return The value of avnu_ap. + */ +int clock_avnu_ap(struct clock *c); + #endif diff --git a/config.c b/config.c index 7914ba4b5166..9ee25bbb8f5e 100644 --- a/config.c +++ b/config.c @@ -191,6 +191,7 @@ static struct config_enum tsproc_enu[] = { struct config_item config_tab[] = { PORT_ITEM_INT("announceReceiptTimeout", 3, 2, UINT8_MAX), GLOB_ITEM_INT("assume_two_step", 0, 0, 1), + GLOB_ITEM_INT("avnu_ap", 0, 0, 1), PORT_ITEM_INT("boundary_clock_jbod", 0, 0, 1), GLOB_ITEM_INT("check_fup_sync", 0, 0, 1), GLOB_ITEM_INT("clockAccuracy", 0xfe, 0, UINT8_MAX), diff --git a/configs/AVnu.cfg b/configs/AVnu.cfg new file mode 100644 index 000000000000..9fa0a1d65e59 --- /dev/null +++ b/configs/AVnu.cfg @@ -0,0 +1,22 @@ +# +# AVnu Automotive Profile example configuration containing those attributes +# which differ from the defaults. See the file, default.cfg, for the complete +# list of available options. +# +# Since BMCA is disabled in AVnu AP, the gmCapable config option will have to +# be used to determine whether the device is a grand master or slave. +[global] +priority1 248 +priority2 248 +logSyncInterval -3 +syncReceiptTimeout 3 +neighborPropDelayThresh 800 +min_neighbor_prop_delay -20000000 +assume_two_step 1 +path_trace_enabled 1 +follow_up_info 1 +transportSpecific 0x1 +ptp_dst_mac 01:80:C2:00:00:0E +network_transport L2 +delay_mechanism P2P +avnu_ap 1 diff --git a/configs/default.cfg b/configs/default.cfg index c5a8b57c9314..248ccad5d963 100644 --- a/configs/default.cfg +++ b/configs/default.cfg @@ -90,6 +90,7 @@ delay_filter_length 10 egressLatency 0 ingressLatency 0 boundary_clock_jbod 0 +avnu_ap 0 # # Clock description # diff --git a/fsm.c b/fsm.c index ce6efad30937..af05abdae294 100644 --- a/fsm.c +++ b/fsm.c @@ -34,6 +34,17 @@ enum port_state ptp_fsm(enum port_state state, enum fsm_event event, int mdiff) case EV_INIT_COMPLETE: next = PS_LISTENING; break; + /* + * The following 2 cases are specific to AVnu AP. When we are + * running AVnu AP, BMCA is not run. So, we need to assign the + * state right after the ports initialization is complete. + */ + case EV_RS_GRAND_MASTER: + next = PS_GRAND_MASTER; + break; + case EV_RS_SLAVE: + next = PS_UNCALIBRATED; + break; default: break; } diff --git a/port.c b/port.c index e85f9fa6f52e..fff2523c62b8 100644 --- a/port.c +++ b/port.c @@ -1611,7 +1611,12 @@ int port_initialize(struct port *p) p->fda.fd[FD_FIRST_TIMER + i] = fd[i]; } - if (port_set_announce_tmo(p)) { + /* + * Do not set announce timeouts when running AVnu Automotive profiles. + * This is done as part of disabling the Best Master Clock Algorithm + * (BMCA) as specified in section 6.3 point 1 (lines 191 to 195). + */ + if (!clock_avnu_ap(p->clock) && port_set_announce_tmo(p)) { goto no_tmo; } if (unicast_client_enabled(p) && unicast_client_set_tmo(p)) { @@ -1717,6 +1722,14 @@ int process_announce(struct port *p, struct ptp_message *m) return result; } + /* + * Do not process Announce messages when running AVnu Automotive + * Profile, conforming to Section 6.3 point 1 (lines 191-195). + */ + if (clock_avnu_ap(p->clock)) { + return result; + } + switch (p->state) { case PS_INITIALIZING: case PS_FAULTY: @@ -1874,8 +1887,15 @@ void process_follow_up(struct port *p, struct ptp_message *m) case PS_SLAVE: break; } + + /* + * Do not verify source port identity if we are running AVnu Automotive + * Profile. This is conforming to Section 6.3 point 2 (lines 196 to + * 199) of AVnu Automotive Profile version 1.5. + */ master = clock_parent_identity(p->clock); - if (!pid_eq(&master, &m->header.sourcePortIdentity)) { + if (!clock_avnu_ap(p->clock) && + !pid_eq(&master, &m->header.sourcePortIdentity)) { return; } @@ -2177,8 +2197,15 @@ void process_sync(struct port *p, struct ptp_message *m) case PS_SLAVE: break; } + + /* + * Do not verify source port identity we are running AVnu Automotive + * Profile. This is conforming to Section 6.3 point 2 (lines 196 to + * 199) of AVnu Automotive Profile version 1.5. + */ master = clock_parent_identity(p->clock); - if (!pid_eq(&master, &m->header.sourcePortIdentity)) { + if (!clock_avnu_ap(p->clock) && + !pid_eq(&master, &m->header.sourcePortIdentity)) { return; } @@ -2331,7 +2358,20 @@ static void port_p2p_transition(struct port *p, enum port_state next) break; case PS_MASTER: case PS_GRAND_MASTER: - set_tmo_log(p->fda.fd[FD_MANNO_TIMER], 1, -10); /*~1ms*/ + /* + * Do not run BMCA in AVnu Automotive Profile (as mentioned in + * Section 6.3 point 1). + */ + if (clock_avnu_ap(p->clock)) { + /* + * If Avnu AP is active, we are skipping the + * PS_LISTENING state and directly going to PS_MASTER. + * So, set the delay timeout here. + */ + port_set_delay_tmo(p); + } else { + set_tmo_log(p->fda.fd[FD_MANNO_TIMER], 1, -10); /*~1ms*/ + } port_set_sync_tx_tmo(p); break; case PS_PASSIVE: @@ -2342,7 +2382,16 @@ static void port_p2p_transition(struct port *p, enum port_state next) flush_peer_delay(p); /* fall through */ case PS_SLAVE: - port_set_announce_tmo(p); + if (clock_avnu_ap(p->clock)) { + /* + * If AVnu AP is active, we are skipping the + * PS_LISTENING state and directly going to + * PS_UNCALIBRATED. So, set the delay timeout here. + */ + port_set_delay_tmo(p); + } else { + port_set_announce_tmo(p); + } break; }; } @@ -2460,7 +2509,18 @@ static enum fsm_event bc_event(struct port *p, int fd_index) port_renew_transport(p)) { return EV_FAULT_DETECTED; } - return EV_ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES; + + /* + * When AVnu AP is active, we never want the slave to + * transition to the master state. So, returning + * EV_SYNCHRONIZATION_FAULT ensures it returns back to + * PS_UNCALIBRATED. + */ + if (clock_avnu_ap(p->clock)) { + return EV_SYNCHRONIZATION_FAULT; + } else { + return EV_ANNOUNCE_RECEIPT_TIMEOUT_EXPIRES; + } case FD_DELAY_TIMER: pr_debug("port %hu: delay timeout", portnum(p)); @@ -2850,6 +2910,12 @@ struct port *port_open(int phc_index, p->jbod = config_get_int(cfg, interface->name, "boundary_clock_jbod"); transport = config_get_int(cfg, interface->name, "network_transport"); + if (clock_avnu_ap(clock) && transport != TRANS_UDS && + transport != TRANS_IEEE_802_3) { + pr_err("AVnu Automotive profile can only run on Layer 2 transport."); + goto err_port; + } + if (transport == TRANS_UDS) { ; /* UDS cannot have a PHC. */ } else if (!interface->ts_info.valid) { @@ -2891,6 +2957,12 @@ struct port *port_open(int phc_index, p->portIdentity.portNumber = number; p->state = PS_INITIALIZING; p->delayMechanism = config_get_int(cfg, p->name, "delay_mechanism"); + if (clock_avnu_ap(clock) && p->delayMechanism != DM_P2P && + transport != TRANS_UDS) { + pr_err("AVnu Automotive profile can only support P2P delay mechanism."); + goto err_port; + } + p->versionNumber = PTP_VERSION; if (number && unicast_client_claim_table(p)) { @@ -2991,7 +3063,20 @@ int port_state_update(struct port *p, enum fsm_event event, int mdiff) if (port_initialize(p)) { event = EV_FAULT_DETECTED; } else { - event = EV_INIT_COMPLETE; + /* + * UDS ports are not used for time synchronization. + * So, do not set state when AVnu AP is activated. + */ + if (transport_type(p->trp) != TRANS_UDS && + clock_avnu_ap(p->clock)) { + if (clock_gm_capable(p->clock)) { + event = EV_RS_GRAND_MASTER; + } else { + event = EV_RS_SLAVE; + } + } else { + event = EV_INIT_COMPLETE; + } } next = p->state_machine(next, event, 0); } diff --git a/ptp4l.8 b/ptp4l.8 index 10c5c2f967cb..0dd13d2ba52b 100644 --- a/ptp4l.8 +++ b/ptp4l.8 @@ -661,6 +661,16 @@ The time source is a single byte code that gives an idea of the kind of local clock in use. The value is purely informational, having no effect on the outcome of the Best Master Clock algorithm, and is advertised when the clock becomes grand master. +.TP +.B avnu_ap +Enable Avnu Automotive Profile. This profile should always be run along with +802.1AS. When set to 1, gmCapable is used to determine whether the clock will +be a grand master for the local network. If gmCapable is 1, the device will +assume the grand master state else it will be the slave. Care should be taken +to make sure there is only 1 grand master in the network. The best master +clock algorithm (BMCA) won't run when Automotive profile is active. Also, +source port identity won't be checked in Sync and Follow_Up messages. The +default value of avnu_ap is 0 (disabled). .SH UNICAST DISCOVERY OPTIONS -- 2.7.3 |