val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN);
val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | PTP_PIN_CFG_DOM);
val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_IDLE);
val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN);
val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK | PTP_PIN_CFG_DOM);
val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_LOAD);
val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN);
val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK |
PTP_PIN_CFG_DOM);
val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_IDLE);
val = ocelot_read_rix(ocelot, PTP_PIN_CFG, TOD_ACC_PIN);
val &= ~(PTP_PIN_CFG_SYNC | PTP_PIN_CFG_ACTION_MASK |
PTP_PIN_CFG_DOM);
val |= PTP_PIN_CFG_ACTION(PTP_PIN_ACTION_DELTA);
if (ocelot->ops->tas_clock_adjust)
ocelot->ops->tas_clock_adjust(ocelot);
} else { /* Fall back using ocelot_ptp_settime64 which is not exact. */ struct timespec64 ts;
u64 now;
ocelot_ptp_gettime64(ptp, &ts);
now = ktime_to_ns(timespec64_to_ktime(ts));
ts = ns_to_timespec64(now + delta);
ocelot_ptp_settime64(ptp, &ts);
}
return 0;
}
EXPORT_SYMBOL(ocelot_ptp_adjtime);
int ocelot_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
{ struct ocelot *ocelot = container_of(ptp, struct ocelot, ptp_info);
u32 unit = 0, direction = 0; unsignedlong flags;
u64 adj = 0;
staticint ocelot_ptp_tx_type_to_cmd(int tx_type, int *ptp_cmd)
{ switch (tx_type) { case HWTSTAMP_TX_ON:
*ptp_cmd = IFH_REW_OP_TWO_STEP_PTP; break; case HWTSTAMP_TX_ONESTEP_SYNC: /* IFH_REW_OP_ONE_STEP_PTP updates the correctionField, * what we need to update is the originTimestamp.
*/
*ptp_cmd = IFH_REW_OP_ORIGIN_PTP; break; case HWTSTAMP_TX_OFF:
*ptp_cmd = 0; break; default: return -ERANGE;
}
int ocelot_hwstamp_set(struct ocelot *ocelot, int port, struct kernel_hwtstamp_config *cfg, struct netlink_ext_ack *extack)
{ struct ocelot_port *ocelot_port = ocelot->ports[port]; bool l2 = false, l4 = false; int ptp_cmd; int err;
/* Tx type sanity check */
err = ocelot_ptp_tx_type_to_cmd(cfg->tx_type, &ptp_cmd); if (err) return err;
switch (cfg->rx_filter) { case HWTSTAMP_FILTER_NONE: break; case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
l4 = true; break; case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
l2 = true; break; case HWTSTAMP_FILTER_PTP_V2_EVENT: case HWTSTAMP_FILTER_PTP_V2_SYNC: case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
l2 = true;
l4 = true; break; default: return -ERANGE;
}
err = ocelot_setup_ptp_traps(ocelot, port, l2, l4); if (err) return err;
skb_queue_walk_safe(&ocelot_port->tx_skbs, skb, skb_tmp) { if (OCELOT_SKB_CB(skb)->ts_id != ts_id) continue;
/* Check that the timestamp ID is for the expected PTP * sequenceId. We don't have to test ptp_parse_header() against * NULL, because we've pre-validated the packet's ptp_class.
*/
hdr = ptp_parse_header(skb, OCELOT_SKB_CB(skb)->ptp_class); if (seqid != ntohs(hdr->sequence_id)) continue;
/* To get a better chance of acquiring a timestamp ID, first flush the * stale packets still waiting in the TX timestamping queue. They are * probably lost.
*/
skb_queue_walk_safe(&ocelot_port->tx_skbs, skb, skb_tmp) { if (time_before(OCELOT_SKB_CB(skb)->ptp_tx_time +
OCELOT_PTP_TX_TSTAMP_TIMEOUT, jiffies)) {
u64_stats_update_begin(&ocelot_port->ts_stats->syncp);
ocelot_port->ts_stats->lost++;
u64_stats_update_end(&ocelot_port->ts_stats->syncp);
dev_dbg_ratelimited(ocelot->dev, "port %d invalidating stale timestamp ID %u which seems lost\n",
port, OCELOT_SKB_CB(skb)->ts_id);
if (ocelot->ptp_skbs_in_flight == OCELOT_PTP_FIFO_SIZE) {
spin_unlock(&ocelot->ts_id_lock); return -EBUSY;
}
n = find_first_zero_bit(ts_id_in_flight, OCELOT_MAX_PTP_ID); if (n == OCELOT_MAX_PTP_ID) {
spin_unlock(&ocelot->ts_id_lock); return -EBUSY;
}
/* Found an available timestamp ID, use it */
OCELOT_SKB_CB(clone)->ts_id = n;
OCELOT_SKB_CB(clone)->ptp_tx_time = jiffies;
ocelot->ptp_skbs_in_flight++;
__skb_queue_tail(&ocelot_port->tx_skbs, clone);
spin_unlock(&ocelot->ts_id_lock);
dev_dbg_ratelimited(ocelot->dev, "port %d timestamp id %lu\n", port, n);
/* Store ptp_cmd in OCELOT_SKB_CB(skb)->ptp_cmd */ if (ptp_cmd == IFH_REW_OP_ORIGIN_PTP) { if (ocelot_ptp_is_onestep_sync(skb, ptp_class)) {
OCELOT_SKB_CB(skb)->ptp_cmd = ptp_cmd;
/* Fall back to two-step timestamping */
ptp_cmd = IFH_REW_OP_TWO_STEP_PTP;
}
if (ptp_cmd == IFH_REW_OP_TWO_STEP_PTP) {
*clone = skb_clone_sk(skb); if (!(*clone)) {
err = -ENOMEM; goto error;
}
/* Store timestamp ID in OCELOT_SKB_CB(clone)->ts_id */
err = ocelot_port_queue_ptp_tx_skb(ocelot, port, *clone); if (err) {
kfree_skb(*clone); goto error;
}
/* Check if a timestamp can be retrieved */ if (!(val & SYS_PTP_STATUS_PTP_MESS_VLD)) break;
WARN_ON(val & SYS_PTP_STATUS_PTP_OVFL);
/* Retrieve the ts ID and Tx port */
id = SYS_PTP_STATUS_PTP_MESS_ID_X(val);
txport = SYS_PTP_STATUS_PTP_MESS_TXPORT_X(val);
seqid = SYS_PTP_STATUS_PTP_MESS_SEQ_ID(val);
ocelot_port = ocelot->ports[txport];
/* Retrieve its associated skb */
skb_match = ocelot_port_dequeue_ptp_tx_skb(ocelot, txport, id,
seqid); if (!skb_match) {
u64_stats_update_begin(&ocelot_port->ts_stats->syncp);
ocelot_port->ts_stats->err++;
u64_stats_update_end(&ocelot_port->ts_stats->syncp);
dev_dbg_ratelimited(ocelot->dev, "port %d received TX timestamp (seqid %d, ts id %u) for packet previously declared stale\n",
txport, seqid, id);
/* Get the h/w timestamp */
ocelot_get_hwtimestamp(ocelot, &ts);
/* Set the timestamp into the skb */
memset(&shhwtstamps, 0, sizeof(shhwtstamps));
shhwtstamps.hwtstamp = ktime_set(ts.tv_sec, ts.tv_nsec);
skb_complete_tx_timestamp(skb_match, &shhwtstamps);
ptp_clock = ptp_clock_register(&ocelot->ptp_info, ocelot->dev); if (IS_ERR(ptp_clock)) return PTR_ERR(ptp_clock); /* Check if PHC support is missing at the configuration level */ if (!ptp_clock) return 0;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.