/* 16 nano second time quantas to wait before making a Drift adjustment */ #define QED_DRIFT_CNTR_TIME_QUANTA_SHIFT 0 /* Nano seconds to add/subtract when making a Drift adjustment */ #define QED_DRIFT_CNTR_ADJUSTMENT_SHIFT 28 /* Add/subtract the Adjustment_Value when making a Drift adjustment */ #define QED_DRIFT_CNTR_DIRECTION_SHIFT 31 #define QED_TIMESTAMP_MASK BIT(16) /* Param mask for Hardware to detect/timestamp the L2/L4 unicast PTP packets */ #define QED_PTP_UCAST_PARAM_MASK 0x70F
staticenum qed_resc_lock qed_ptcdev_to_resc(struct qed_hwfn *p_hwfn)
{ switch (MFW_PORT(p_hwfn)) { case 0: return QED_RESC_LOCK_PTP_PORT0; case 1: return QED_RESC_LOCK_PTP_PORT1; case 2: return QED_RESC_LOCK_PTP_PORT2; case 3: return QED_RESC_LOCK_PTP_PORT3; default: return QED_RESC_LOCK_RESC_INVALID;
}
}
/* Reset possibly old timestamps */
qed_wr(p_hwfn, p_ptt, NIG_REG_LLH_PTP_HOST_BUF_SEQID,
QED_TIMESTAMP_MASK);
return 0;
}
/* Adjust the HW clock by a rate given in parts-per-billion (ppb) units. * FW/HW accepts the adjustment value in terms of 3 parameters: * Drift period - adjustment happens once in certain number of nano seconds. * Drift value - time is adjusted by a certain value, for example by 5 ns. * Drift direction - add or subtract the adjustment value. * The routine translates ppb into the adjustment triplet in an optimal manner.
*/ staticint qed_ptp_hw_adjfreq(struct qed_dev *cdev, s32 ppb)
{
s64 best_val = 0, val, best_period = 0, period, approx_dev, dif, dif2; struct qed_hwfn *p_hwfn = QED_LEADING_HWFN(cdev); struct qed_ptt *p_ptt = p_hwfn->p_ptp_ptt;
u32 drift_ctr_cfg = 0, drift_state; int drift_dir = 1;
/* Adjustment value is up to +/-7ns, find an optimal value in * this range.
*/ for (val = 7; val > 0; val--) {
period = div_s64(val * 1000000000, ppb);
period -= 8;
period >>= 4; if (period < 1)
period = 1; if (period > 0xFFFFFFE)
period = 0xFFFFFFE;
/* Check both rounding ends for approximate error */
approx_dev = period * 16 + 8;
dif = ppb * approx_dev - val * 1000000000;
dif2 = dif + 16 * ppb;
if (dif < 0)
dif = -dif; if (dif2 < 0)
dif2 = -dif2;
/* Determine which end gives better approximation */ if (dif * (approx_dev + 16) > dif2 * approx_dev) {
period++;
approx_dev += 16;
dif = dif2;
}
/* Track best approximation found so far */ if (best_dif * approx_dev > dif * best_approx_dev) {
best_dif = dif;
best_val = val;
best_period = period;
best_approx_dev = approx_dev;
}
}
} elseif (ppb == 1) { /* This is a special case as its the only value which wouldn't * fit in a s64 variable. In order to prevent castings simple * handle it separately.
*/
best_val = 4;
best_period = 0xee6b27f;
} else {
best_val = 0;
best_period = 0xFFFFFFF;
}
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.