/* On older silicon variants of CN10K, atomic update feature * is not available.
*/ if ((is_ptp_dev_cn10ka(ptp) || is_ptp_dev_cnf10ka(ptp)) &&
(is_rev_A0(ptp) || is_rev_A1(ptp))) returnfalse;
/* Errata: * Issue #1: At the time of 1 sec rollover of the nano-second counter, * the nano-second counter is set to 0. However, it should be set to * (existing counter_value - 10^9). * * Issue #2: The nano-second counter rolls over at 0x3B9A_C9FF. * It should roll over at 0x3B9A_CA00.
*/
/* calculate ptp_clock_comp value */
comp = ((u64)1000000000ULL << 32) / ptp_clock_freq; /* use CYCLE_MULT to avoid accuracy loss due to integer arithmetic */
cycle_time = NSEC_PER_SEC * CYCLE_MULT / ptp_clock_freq; /* cycles per sec */
cycles_per_sec = ptp_clock_freq;
/* check whether ptp nanosecond counter rolls over early */
cycle = cycles_per_sec - 1;
ptp_clock_nsec = (cycle * comp) >> 32; while (ptp_clock_nsec < NSEC_PER_SEC) { if (ptp_clock_nsec == 0x3B9AC9FF) goto calc_adj_comp;
cycle++;
ptp_clock_nsec = (cycle * comp) >> 32;
} /* compute nanoseconds lost per second when nsec counter rolls over */
ns_drift = ptp_clock_nsec - NSEC_PER_SEC; /* calculate ptp_clock_comp adjustment */ if (ns_drift > 0) {
adj = comp * ns_drift;
adj = adj / 1000000000ULL;
} /* speed up the ptp clock to account for nanoseconds lost */
comp += adj; return comp;
calc_adj_comp: /* slow down the ptp clock to not rollover early */
adj = comp * cycle_time;
adj = adj / 1000000000ULL;
adj = adj / CYCLE_MULT;
comp -= adj;
/* Check PTP block is present in hardware */ if (!pci_dev_present(ptp_id_table)) return ERR_PTR(-ENODEV); /* Check driver is bound to PTP block */ if (!ptp)
ptp = ERR_PTR(-EPROBE_DEFER); elseif (!IS_ERR(ptp))
pci_dev_get(ptp->pdev);
/* The hardware adds the clock compensation value to the PTP clock * on every coprocessor clock cycle. Typical convention is that it * represent number of nanosecond betwen each cycle. In this * convention compensation value is in 64 bit fixed-point * representation where upper 32 bits are number of nanoseconds * and lower is fractions of nanosecond. * The scaled_ppm represent the ratio in "parts per million" by which * the compensation value should be corrected. * To calculate new compenstation value we use 64bit fixed point * arithmetic on following formula * comp = tbase + tbase * scaled_ppm / (1M * 2^16) * where tbase is the basic compensation value calculated * initialy in the probe function.
*/ /* convert scaled_ppm to ppb */
ppb = 1 + scaled_ppm;
ppb *= 125;
ppb >>= 13;
staticint ptp_config_hrtimer(struct ptp *ptp, int on)
{
u64 ptp_clock_hi;
if (on) {
ptp_clock_hi = readq(ptp->reg_base + PTP_CLOCK_HI);
ptp_hrtimer_start(ptp, (ktime_t)ptp_clock_hi);
} else { if (hrtimer_active(&ptp->hrtimer))
hrtimer_cancel(&ptp->hrtimer);
}
return 0;
}
staticint ptp_pps_on(struct ptp *ptp, int on, u64 period)
{
u64 clock_cfg;
clock_cfg = readq(ptp->reg_base + PTP_CLOCK_CFG); if (on) { if (cn10k_ptp_errata(ptp) && period != NSEC_PER_SEC) {
dev_err(&ptp->pdev->dev, "Supports max period value as 1 second\n"); return -EINVAL;
}
if (period > (8 * NSEC_PER_SEC)) {
dev_err(&ptp->pdev->dev, "Supports max period as 8 seconds\n"); return -EINVAL;
}
if (on && cn10k_ptp_errata(ptp)) { /* The ptp_clock_hi rollsover to zero once clock cycle before it * reaches one second boundary. so, program the pps_lo_incr in * such a way that the pps threshold value comparison at one * second boundary will succeed and pps edge changes. After each * one second boundary, the hrtimer handler will be invoked and * reprograms the pps threshold value.
*/
ptp->clock_period = NSEC_PER_SEC / ptp->clock_rate;
writeq((0x1dcd6500ULL - ptp->clock_period) << 32,
ptp->reg_base + PTP_PPS_LO_INCR);
}
if (cn10k_ptp_errata(ptp))
ptp_config_hrtimer(ptp, on);
error: /* For `ptp_get()` we need to differentiate between the case * when the core has not tried to probe this device and the case when * the probe failed. In the later case we keep the error in * `dev->driver_data`.
*/
pci_set_drvdata(pdev, ERR_PTR(err)); if (!first_ptp_block)
first_ptp_block = ERR_PTR(err);
int rvu_mbox_handler_ptp_op(struct rvu *rvu, struct ptp_req *req, struct ptp_rsp *rsp)
{ int err = 0;
/* This function is the PTP mailbox handler invoked when * called by AF consumers/netdev drivers via mailbox mechanism. * It is used by netdev driver to get the PTP clock and to set * frequency adjustments. Since mailbox can be called without * notion of whether the driver is bound to ptp device below * validation is needed as first step.
*/ if (!rvu->ptp) return -ENODEV;
switch (req->op) { case PTP_OP_ADJFINE:
err = ptp_adjfine(rvu->ptp, req->scaled_ppm); break; case PTP_OP_GET_CLOCK:
err = ptp_get_clock(rvu->ptp, &rsp->clk); break; case PTP_OP_GET_TSTMP:
err = ptp_get_tstmp(rvu->ptp, &rsp->clk); break; case PTP_OP_SET_THRESH:
err = ptp_set_thresh(rvu->ptp, req->thresh); break; case PTP_OP_PPS_ON:
err = ptp_pps_on(rvu->ptp, req->pps_on, req->period); break; case PTP_OP_ADJTIME:
ptp_atomic_adjtime(rvu->ptp, req->delta); break; case PTP_OP_SET_CLOCK:
ptp_atomic_update(rvu->ptp, (u64)req->clk); break; default:
err = -EINVAL; break;
}
return err;
}
int rvu_mbox_handler_ptp_get_cap(struct rvu *rvu, struct msg_req *req, struct ptp_get_cap_rsp *rsp)
{ if (!rvu->ptp) return -ENODEV;
if (is_tstmp_atomic_update_supported(rvu))
rsp->cap |= PTP_CAP_HW_ATOMIC_UPDATE; else
rsp->cap &= ~BIT_ULL_MASK(0);
return 0;
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet)
¤
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.