/* The scaled_ppm parameter is ppm (parts per million) with a 16-bit fractional * part, which means that a value of 1 in one of those fields actually means * 2^-16 ppm, and 2^16=65536 is 1 ppm.
*/ #define SCALE_FACTOR 65536000000ULL #define IWL_PTP_WRAP_THRESHOLD_USEC (5000)
#define IWL_PTP_GET_CROSS_TS_NUM 5
staticvoid iwl_mvm_ptp_update_new_read(struct iwl_mvm *mvm, u32 gp2)
{ /* If the difference is above the threshold, assume it's a wraparound. * Otherwise assume it's an old read and ignore it.
*/ if (gp2 < mvm->ptp_data.last_gp2 &&
mvm->ptp_data.last_gp2 - gp2 < IWL_PTP_WRAP_THRESHOLD_USEC) {
IWL_DEBUG_INFO(mvm, "PTP: ignore old read (gp2=%u, last_gp2=%u)\n",
gp2, mvm->ptp_data.last_gp2); return;
}
if (gp2 < mvm->ptp_data.last_gp2) {
mvm->ptp_data.wrap_counter++;
IWL_DEBUG_INFO(mvm, "PTP: wraparound detected (new counter=%u)\n",
mvm->ptp_data.wrap_counter);
}
/* It is possible that a GP2 timestamp was received from fw before the * last scale update. Since we don't know how to scale - ignore it.
*/ if (base_time_ns < last_gp2_ns) {
IWL_DEBUG_INFO(mvm, "Time before scale update - ignore\n"); return 0;
}
for (i = 0; i < IWL_PTP_GET_CROSS_TS_NUM; i++) {
iwl_mvm_get_sync_time(mvm, CLOCK_REALTIME, &tmp_gp2, NULL,
&tmp_sys_time);
new_diff = tmp_sys_time - ((u64)tmp_gp2 * NSEC_PER_USEC); if (!diff || new_diff < diff) {
*sys_time = tmp_sys_time;
*gp2 = tmp_gp2;
diff = new_diff;
IWL_DEBUG_INFO(mvm, "PTP: new times: gp2=%u sys=%lld\n",
*gp2, *sys_time);
}
}
}
staticint
iwl_mvm_phc_get_crosstimestamp(struct ptp_clock_info *ptp, struct system_device_crosststamp *xtstamp)
{ struct iwl_mvm *mvm = container_of(ptp, struct iwl_mvm,
ptp_data.ptp_clock_info); int ret = 0; /* Raw value read from GP2 register in usec */
u32 gp2; /* GP2 value in ns*/
s64 gp2_ns; /* System (wall) time */
ktime_t sys_time;
if (!mvm->ptp_data.ptp_clock) {
IWL_ERR(mvm, "No PHC clock registered\n"); return -ENODEV;
}
mutex_lock(&mvm->mutex); if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SYNCED_TIME)) {
ret = iwl_mvm_get_crosstimestamp_fw(mvm, &gp2, &sys_time);
/* iwl_mvm_ptp_init - initialize PTP for devices which support it. * @mvm: internal mvm structure, see &struct iwl_mvm. * * Performs the required steps for enabling PTP support.
*/ void iwl_mvm_ptp_init(struct iwl_mvm *mvm)
{ /* Warn if the interface already has a ptp_clock defined */ if (WARN_ON(mvm->ptp_data.ptp_clock)) return;
/* Give a short 'friendly name' to identify the PHC clock */
snprintf(mvm->ptp_data.ptp_clock_info.name, sizeof(mvm->ptp_data.ptp_clock_info.name), "%s", "iwlwifi-PTP");
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.