Introduce peer to peer one step.

The 1588 standard defines one step operation for both Sync and
PDelay_Resp messages.  Up until now, hardware with P2P one step has
been rare, and kernel support was lacking.  This patch adds support of
the mode in anticipation of new kernel and hardware developments.

Signed-off-by: Richard Cochran <richardcochran@gmail.com>
master
Richard Cochran 2018-02-15 09:16:15 -08:00
parent 510777deca
commit 4842d2c7ec
7 changed files with 93 additions and 28 deletions

View File

@ -823,6 +823,7 @@ int clock_required_modes(struct clock *c)
break; break;
case TS_HARDWARE: case TS_HARDWARE:
case TS_ONESTEP: case TS_ONESTEP:
case TS_P2P1STEP:
required_modes |= SOF_TIMESTAMPING_TX_HARDWARE | required_modes |= SOF_TIMESTAMPING_TX_HARDWARE |
SOF_TIMESTAMPING_RX_HARDWARE | SOF_TIMESTAMPING_RX_HARDWARE |
SOF_TIMESTAMPING_RAW_HARDWARE; SOF_TIMESTAMPING_RAW_HARDWARE;
@ -947,6 +948,7 @@ struct clock *clock_create(enum clock_type type, struct config *config,
return NULL; return NULL;
break; break;
case TS_ONESTEP: case TS_ONESTEP:
case TS_P2P1STEP:
break; break;
} }
} }

View File

@ -82,6 +82,10 @@ kernel_flags()
if grep -q HWTSTAMP_TX_ONESTEP_SYNC ${prefix}${tstamp}; then if grep -q HWTSTAMP_TX_ONESTEP_SYNC ${prefix}${tstamp}; then
printf " -DHAVE_ONESTEP_SYNC" printf " -DHAVE_ONESTEP_SYNC"
fi fi
if grep -q HWTSTAMP_TX_ONESTEP_P2P ${prefix}${tstamp}; then
printf " -DHAVE_ONESTEP_P2P"
fi
} }
flags="$(user_flags)$(kernel_flags)" flags="$(user_flags)$(kernel_flags)"

View File

@ -54,6 +54,12 @@ enum _missing_hwtstamp_tx_types {
}; };
#endif #endif
#ifndef HAVE_ONESTEP_P2P
enum {
HWTSTAMP_TX_ONESTEP_P2P = 3,
};
#endif
#ifndef SIOCGHWTSTAMP #ifndef SIOCGHWTSTAMP
#define SIOCGHWTSTAMP 0x89b1 #define SIOCGHWTSTAMP 0x89b1
#endif #endif

1
msg.h
View File

@ -61,6 +61,7 @@ enum timestamp_type {
TS_HARDWARE, TS_HARDWARE,
TS_LEGACY_HW, TS_LEGACY_HW,
TS_ONESTEP, TS_ONESTEP,
TS_P2P1STEP,
}; };
struct hw_timestamp { struct hw_timestamp {

79
port.c
View File

@ -1450,7 +1450,21 @@ static int port_tx_sync(struct port *p, struct address *dst)
struct ptp_message *msg, *fup; struct ptp_message *msg, *fup;
int err, event; int err, event;
event = p->timestamping == TS_ONESTEP ? TRANS_ONESTEP : TRANS_EVENT; switch (p->timestamping) {
case TS_SOFTWARE:
case TS_LEGACY_HW:
case TS_HARDWARE:
event = TRANS_EVENT;
break;
case TS_ONESTEP:
event = TRANS_ONESTEP;
break;
case TS_P2P1STEP:
event = TRANS_P2P1STEP;
break;
default:
return -1;
}
if (!port_capable(p)) { if (!port_capable(p)) {
return 0; return 0;
@ -1478,7 +1492,7 @@ static int port_tx_sync(struct port *p, struct address *dst)
msg->header.control = CTL_SYNC; msg->header.control = CTL_SYNC;
msg->header.logMessageInterval = p->logSyncInterval; msg->header.logMessageInterval = p->logSyncInterval;
if (p->timestamping != TS_ONESTEP) if (p->timestamping != TS_ONESTEP && p->timestamping != TS_P2P1STEP)
msg->header.flagField[0] |= TWO_STEP; msg->header.flagField[0] |= TWO_STEP;
if (dst) { if (dst) {
@ -1490,7 +1504,7 @@ static int port_tx_sync(struct port *p, struct address *dst)
pr_err("port %hu: send sync failed", portnum(p)); pr_err("port %hu: send sync failed", portnum(p));
goto out; goto out;
} }
if (p->timestamping == TS_ONESTEP) { if (p->timestamping == TS_ONESTEP || p->timestamping == TS_P2P1STEP) {
goto out; goto out;
} else if (msg_sots_missing(msg)) { } else if (msg_sots_missing(msg)) {
pr_err("missing timestamp on transmitted sync"); pr_err("missing timestamp on transmitted sync");
@ -1934,7 +1948,21 @@ static void process_follow_up(struct port *p, struct ptp_message *m)
static int process_pdelay_req(struct port *p, struct ptp_message *m) static int process_pdelay_req(struct port *p, struct ptp_message *m)
{ {
struct ptp_message *rsp, *fup; struct ptp_message *rsp, *fup;
int err; int err, event;
switch (p->timestamping) {
case TS_SOFTWARE:
case TS_LEGACY_HW:
case TS_HARDWARE:
case TS_ONESTEP:
event = TRANS_EVENT;
break;
case TS_P2P1STEP:
event = TRANS_P2P1STEP;
break;
default:
return -1;
}
if (p->delayMechanism == DM_E2E) { if (p->delayMechanism == DM_E2E) {
pr_warning("port %hu: pdelay_req on E2E port", portnum(p)); pr_warning("port %hu: pdelay_req on E2E port", portnum(p));
@ -1980,19 +2008,36 @@ static int process_pdelay_req(struct port *p, struct ptp_message *m)
rsp->header.sequenceId = m->header.sequenceId; rsp->header.sequenceId = m->header.sequenceId;
rsp->header.control = CTL_OTHER; rsp->header.control = CTL_OTHER;
rsp->header.logMessageInterval = 0x7f; rsp->header.logMessageInterval = 0x7f;
/*
* NB - There is no kernel support for one step P2P messaging,
* so we always send a follow up message.
*/
rsp->header.flagField[0] |= TWO_STEP;
/* /*
* NB - We do not have any fraction nanoseconds for the correction * NB - We do not have any fraction nanoseconds for the correction
* fields, neither in the response or the follow up. * fields, neither in the response or the follow up.
*/ */
rsp->pdelay_resp.requestReceiptTimestamp = tmv_to_Timestamp(m->hwts.ts); if (p->timestamping == TS_P2P1STEP) {
rsp->header.correction = m->header.correction;
} else {
rsp->header.flagField[0] |= TWO_STEP;
rsp->pdelay_resp.requestReceiptTimestamp =
tmv_to_Timestamp(m->hwts.ts);
}
rsp->pdelay_resp.requestingPortIdentity = m->header.sourcePortIdentity; rsp->pdelay_resp.requestingPortIdentity = m->header.sourcePortIdentity;
err = peer_prepare_and_send(p, rsp, event);
if (err) {
pr_err("port %hu: send peer delay response failed", portnum(p));
goto out;
}
if (p->timestamping == TS_P2P1STEP) {
goto out;
} else if (msg_sots_missing(rsp)) {
pr_err("missing timestamp on transmitted peer delay response");
err = -1;
goto out;
}
/*
* Send the follow up message right away.
*/
fup->hwts.type = p->timestamping; fup->hwts.type = p->timestamping;
fup->header.tsmt = PDELAY_RESP_FOLLOW_UP | p->transportSpecific; fup->header.tsmt = PDELAY_RESP_FOLLOW_UP | p->transportSpecific;
@ -2007,23 +2052,12 @@ static int process_pdelay_req(struct port *p, struct ptp_message *m)
fup->pdelay_resp_fup.requestingPortIdentity = m->header.sourcePortIdentity; fup->pdelay_resp_fup.requestingPortIdentity = m->header.sourcePortIdentity;
err = peer_prepare_and_send(p, rsp, 1);
if (err) {
pr_err("port %hu: send peer delay response failed", portnum(p));
goto out;
}
if (msg_sots_missing(rsp)) {
pr_err("missing timestamp on transmitted peer delay response");
goto out;
}
fup->pdelay_resp_fup.responseOriginTimestamp = fup->pdelay_resp_fup.responseOriginTimestamp =
tmv_to_Timestamp(rsp->hwts.ts); tmv_to_Timestamp(rsp->hwts.ts);
err = peer_prepare_and_send(p, fup, 0); err = peer_prepare_and_send(p, fup, 0);
if (err) if (err)
pr_err("port %hu: send pdelay_resp_fup failed", portnum(p)); pr_err("port %hu: send pdelay_resp_fup failed", portnum(p));
out: out:
msg_put(rsp); msg_put(rsp);
msg_put(fup); msg_put(fup);
@ -2530,7 +2564,8 @@ enum fsm_event port_event(struct port *p, int fd_index)
msg_put(msg); msg_put(msg);
return EV_NONE; return EV_NONE;
} }
if (msg_sots_missing(msg)) { if (msg_sots_missing(msg) &&
!(p->timestamping == TS_P2P1STEP && msg_type(msg) == PDELAY_REQ)) {
pr_err("port %hu: received %s without timestamp", pr_err("port %hu: received %s without timestamp",
portnum(p), msg_type_string(msg_type(msg))); portnum(p), msg_type_string(msg_type(msg)));
msg_put(msg); msg_put(msg);

28
sk.c
View File

@ -43,7 +43,7 @@ int sk_check_fupsync;
/* private methods */ /* private methods */
static int hwts_init(int fd, const char *device, int rx_filter, int one_step) static int hwts_init(int fd, const char *device, int rx_filter, int tx_type)
{ {
struct ifreq ifreq; struct ifreq ifreq;
struct hwtstamp_config cfg, req; struct hwtstamp_config cfg, req;
@ -55,7 +55,7 @@ static int hwts_init(int fd, const char *device, int rx_filter, int one_step)
strncpy(ifreq.ifr_name, device, sizeof(ifreq.ifr_name) - 1); strncpy(ifreq.ifr_name, device, sizeof(ifreq.ifr_name) - 1);
ifreq.ifr_data = (void *) &cfg; ifreq.ifr_data = (void *) &cfg;
cfg.tx_type = one_step ? HWTSTAMP_TX_ONESTEP_SYNC : HWTSTAMP_TX_ON; cfg.tx_type = tx_type;
cfg.rx_filter = rx_filter; cfg.rx_filter = rx_filter;
req = cfg; req = cfg;
err = ioctl(fd, SIOCSHWTSTAMP, &ifreq); err = ioctl(fd, SIOCSHWTSTAMP, &ifreq);
@ -359,6 +359,7 @@ int sk_receive(int fd, void *buf, int buflen,
break; break;
case TS_HARDWARE: case TS_HARDWARE:
case TS_ONESTEP: case TS_ONESTEP:
case TS_P2P1STEP:
hwts->ts = timespec_to_tmv(ts[2]); hwts->ts = timespec_to_tmv(ts[2]);
break; break;
case TS_LEGACY_HW: case TS_LEGACY_HW:
@ -394,7 +395,7 @@ int sk_set_priority(int fd, uint8_t dscp)
int sk_timestamping_init(int fd, const char *device, enum timestamp_type type, int sk_timestamping_init(int fd, const char *device, enum timestamp_type type,
enum transport_type transport) enum transport_type transport)
{ {
int err, filter1, filter2 = 0, flags, one_step; int err, filter1, filter2 = 0, flags, tx_type;
switch (type) { switch (type) {
case TS_SOFTWARE: case TS_SOFTWARE:
@ -404,6 +405,7 @@ int sk_timestamping_init(int fd, const char *device, enum timestamp_type type,
break; break;
case TS_HARDWARE: case TS_HARDWARE:
case TS_ONESTEP: case TS_ONESTEP:
case TS_P2P1STEP:
flags = SOF_TIMESTAMPING_TX_HARDWARE | flags = SOF_TIMESTAMPING_TX_HARDWARE |
SOF_TIMESTAMPING_RX_HARDWARE | SOF_TIMESTAMPING_RX_HARDWARE |
SOF_TIMESTAMPING_RAW_HARDWARE; SOF_TIMESTAMPING_RAW_HARDWARE;
@ -419,7 +421,21 @@ int sk_timestamping_init(int fd, const char *device, enum timestamp_type type,
if (type != TS_SOFTWARE) { if (type != TS_SOFTWARE) {
filter1 = HWTSTAMP_FILTER_PTP_V2_EVENT; filter1 = HWTSTAMP_FILTER_PTP_V2_EVENT;
one_step = type == TS_ONESTEP ? 1 : 0; switch (type) {
case TS_SOFTWARE:
tx_type = HWTSTAMP_TX_OFF;
break;
case TS_HARDWARE:
case TS_LEGACY_HW:
tx_type = HWTSTAMP_TX_ON;
break;
case TS_ONESTEP:
tx_type = HWTSTAMP_TX_ONESTEP_SYNC;
break;
case TS_P2P1STEP:
tx_type = HWTSTAMP_TX_ONESTEP_P2P;
break;
}
switch (transport) { switch (transport) {
case TRANS_UDP_IPV4: case TRANS_UDP_IPV4:
case TRANS_UDP_IPV6: case TRANS_UDP_IPV6:
@ -434,10 +450,10 @@ int sk_timestamping_init(int fd, const char *device, enum timestamp_type type,
case TRANS_UDS: case TRANS_UDS:
return -1; return -1;
} }
err = hwts_init(fd, device, filter1, one_step); err = hwts_init(fd, device, filter1, tx_type);
if (err) { if (err) {
pr_info("driver rejected most general HWTSTAMP filter"); pr_info("driver rejected most general HWTSTAMP filter");
err = hwts_init(fd, device, filter2, one_step); err = hwts_init(fd, device, filter2, tx_type);
if (err) { if (err) {
pr_err("ioctl SIOCSHWTSTAMP failed: %m"); pr_err("ioctl SIOCSHWTSTAMP failed: %m");
return err; return err;

View File

@ -49,6 +49,7 @@ enum transport_event {
TRANS_GENERAL, TRANS_GENERAL,
TRANS_EVENT, TRANS_EVENT,
TRANS_ONESTEP, TRANS_ONESTEP,
TRANS_P2P1STEP,
}; };
struct transport; struct transport;