staticint ionic_hwstamp_tx_mode(int config_tx_type)
{ switch (config_tx_type) { case HWTSTAMP_TX_OFF: return IONIC_TXSTAMP_OFF; case HWTSTAMP_TX_ON: return IONIC_TXSTAMP_ON; case HWTSTAMP_TX_ONESTEP_SYNC: return IONIC_TXSTAMP_ONESTEP_SYNC; case HWTSTAMP_TX_ONESTEP_P2P: return IONIC_TXSTAMP_ONESTEP_P2P; default: return -ERANGE;
}
}
static u64 ionic_hwstamp_rx_filt(int config_rx_filter)
{ switch (config_rx_filter) { case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: return IONIC_PKT_CLS_PTP1_ALL; case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: return IONIC_PKT_CLS_PTP1_SYNC; case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: return IONIC_PKT_CLS_PTP1_SYNC | IONIC_PKT_CLS_PTP1_DREQ;
case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: return IONIC_PKT_CLS_PTP2_L4_ALL; case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: return IONIC_PKT_CLS_PTP2_L4_SYNC; case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: return IONIC_PKT_CLS_PTP2_L4_SYNC | IONIC_PKT_CLS_PTP2_L4_DREQ;
case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: return IONIC_PKT_CLS_PTP2_L2_ALL; case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: return IONIC_PKT_CLS_PTP2_L2_SYNC; case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: return IONIC_PKT_CLS_PTP2_L2_SYNC | IONIC_PKT_CLS_PTP2_L2_DREQ;
case HWTSTAMP_FILTER_PTP_V2_EVENT: return IONIC_PKT_CLS_PTP2_ALL; case HWTSTAMP_FILTER_PTP_V2_SYNC: return IONIC_PKT_CLS_PTP2_SYNC; case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: return IONIC_PKT_CLS_PTP2_SYNC | IONIC_PKT_CLS_PTP2_DREQ;
case HWTSTAMP_FILTER_NTP_ALL: return IONIC_PKT_CLS_NTP_ALL;
if (!lif->phc || !lif->phc->ptp) return -EOPNOTSUPP;
mutex_lock(&lif->phc->config_lock);
if (new_ts) {
config = new_ts;
} else { /* If called with new_ts == NULL, replay the previous request * primarily for recovery after a FW_RESET. * We saved the previous configuration request info, so copy * the previous request for reference, clear the current state * to match the device's reset state, and run with it.
*/
config = &ts;
memcpy(config, &lif->phc->ts_config, sizeof(*config));
memset(&lif->phc->ts_config, 0, sizeof(lif->phc->ts_config));
lif->phc->ts_config_tx_mode = 0;
lif->phc->ts_config_rx_filt = 0;
}
/* If tick_high changed, re-read tick_low once more. Assume tick_high * cannot change again so soon as in the span of re-reading tick_low.
*/ if (tick_high != tick_high_before) {
ptp_read_system_prets(sts);
tick_low = ioread32(&ionic->idev.hwstamp_regs->tick_low);
ptp_read_system_postts(sts);
}
/* Reject phc adjustments during device upgrade */ if (test_bit(IONIC_LIF_F_FW_RESET, phc->lif->state)) return -EBUSY;
/* Adjustment value scaled by 2^16 million */
adj = (s64)scaled_ppm * phc->init_cc_mult;
/* Adjustment value to scale */
adj /= (s64)SCALED_PPM;
/* Final adjusted multiplier */
adj += phc->init_cc_mult;
spin_lock_irqsave(&phc->lock, irqflags);
/* update the point-in-time basis to now, before adjusting the rate */
timecounter_read(&phc->tc);
phc->cc.mult = adj;
/* Setphc commands are posted in-order, sequenced by phc->lock. We * need to drop the lock before waiting for the command to complete.
*/
err = ionic_setphc_cmd(phc, &ctx);
/* Reject phc adjustments during device upgrade */ if (test_bit(IONIC_LIF_F_FW_RESET, phc->lif->state)) return -EBUSY;
spin_lock_irqsave(&phc->lock, irqflags);
timecounter_adjtime(&phc->tc, delta);
/* Setphc commands are posted in-order, sequenced by phc->lock. We * need to drop the lock before waiting for the command to complete.
*/
err = ionic_setphc_cmd(phc, &ctx);
/* Reject phc adjustments during device upgrade */ if (test_bit(IONIC_LIF_F_FW_RESET, phc->lif->state)) return -EBUSY;
ns = timespec64_to_ns(ts);
spin_lock_irqsave(&phc->lock, irqflags);
timecounter_init(&phc->tc, &phc->cc, ns);
/* Setphc commands are posted in-order, sequenced by phc->lock. We * need to drop the lock before waiting for the command to complete.
*/
err = ionic_setphc_cmd(phc, &ctx);
/* Do not update phc during device upgrade, but keep polling to resume * after upgrade. Since we don't update the point in time basis, there * is no expectation that we are maintaining the phc time during the * upgrade. After upgrade, it will need to be readjusted back to the * correct time by the ptp daemon.
*/ if (test_bit(IONIC_LIF_F_FW_RESET, phc->lif->state)) return phc->aux_work_delay;
spin_lock_irqsave(&phc->lock, irqflags);
/* update point-in-time basis to now */
timecounter_read(&phc->tc);
/* Setphc commands are posted in-order, sequenced by phc->lock. We * need to drop the lock before waiting for the command to complete.
*/
err = ionic_setphc_cmd(phc, &ctx);
/* max ticks is limited by the multiplier, or by the update period. */ if (phc->cc.shift + 2 + ilog2(IONIC_PHC_UPDATE_NS) >= 64) { /* max ticks that do not overflow when multiplied by max * adjusted multiplier (twice the initial multiplier)
*/
diff = U64_MAX / phc->cc.mult / 2;
} else { /* approx ticks at four times the update period */
diff = (u64)IONIC_PHC_UPDATE_NS << (phc->cc.shift + 2);
diff = DIV_ROUND_UP(diff, phc->cc.mult);
}
/* constrain to the hardware bitmask */
diff &= phc->cc.mask;
/* the wrap period is now defined by diff * * we will update the time basis at about 1/4 the wrap period, so * should not see a difference of more than +/- diff/4. * * this is sufficient not see a difference of more than +/- diff/2, as * required by timecounter_cyc2time, to detect an old time stamp. * * adjust the initial multiplier, being careful to avoid overflow: * - do not overflow 63 bits: init_cc_mult * SCALED_PPM * - do not overflow 64 bits: max_mult * (diff / 2) * * we want to increase the initial multiplier as much as possible, to * allow for more precise adjustment in ionic_phc_adjfine. * * only adjust the multiplier if we can double it or more.
*/
mult = U64_MAX / 2 / max(diff / 2, SCALED_PPM);
shift = mult / phc->cc.mult; if (shift >= 2) { /* initial multiplier will be 2^n of hardware cc.mult */
shift = fls(shift); /* increase cc.mult and cc.shift by the same 2^n and n. */
phc->cc.mult <<= shift;
phc->cc.shift += shift;
}
/* Update cycle_last at 1/4 the wrap period, or IONIC_PHC_UPDATE_NS */
delay = min_t(u64, IONIC_PHC_UPDATE_NS,
cyclecounter_cyc2ns(&phc->cc, diff / 4, 0, &frac));
dev_dbg(lif->ionic->dev, "Work delay %llu ms\n", delay / NSEC_PER_MSEC);
phc->aux_work_delay = nsecs_to_jiffies(delay);
phc->ptp_info = ionic_ptp_info;
/* We have allowed to adjust the multiplier up to +/- 1 part per 1. * Here expressed as NORMAL_PPB (1 billion parts per billion).
*/
phc->ptp_info.max_adj = NORMAL_PPB;
lif->phc = phc;
}
void ionic_lif_free_phc(struct ionic_lif *lif)
{ if (!lif->phc) return;
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.