diff options
author | Laurence Evans <levans@solarflare.com> | 2018-01-25 17:28:04 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-01-25 16:05:15 -0500 |
commit | 88a4fb5fce303c1ffd0e7863c01fc9e38f2e1717 (patch) | |
tree | 7a904f8c8643c2e61235fbea0309ef4c1067f1a3 /drivers/net/ethernet/sfc/ptp.c | |
parent | 1280c0f8aafc4c09c59c576c8d50f367070b2619 (diff) | |
download | lwn-88a4fb5fce303c1ffd0e7863c01fc9e38f2e1717.tar.gz lwn-88a4fb5fce303c1ffd0e7863c01fc9e38f2e1717.zip |
sfc: support Medford2 frequency adjustment format
Support increased precision frequency adjustment format (FP44) used
by Medford2 adapters.
Signed-off-by: Laurence Evans <levans@solarflare.com>
Signed-off-by: Edward Cree <ecree@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/sfc/ptp.c')
-rw-r--r-- | drivers/net/ethernet/sfc/ptp.c | 45 |
1 files changed, 31 insertions, 14 deletions
diff --git a/drivers/net/ethernet/sfc/ptp.c b/drivers/net/ethernet/sfc/ptp.c index 196b0768b2f2..433d29d6bc95 100644 --- a/drivers/net/ethernet/sfc/ptp.c +++ b/drivers/net/ethernet/sfc/ptp.c @@ -149,18 +149,14 @@ enum ptp_packet_state { /* Maximum parts-per-billion adjustment that is acceptable */ #define MAX_PPB 1000000 -/* Number of bits required to hold the above */ -#define MAX_PPB_BITS 20 - -/* Number of extra bits allowed when calculating fractional ns. - * EXTRA_BITS + MC_CMD_PTP_IN_ADJUST_BITS + MAX_PPB_BITS should - * be less than 63. - */ -#define PPB_EXTRA_BITS 2 - /* Precalculate scale word to avoid long long division at runtime */ -#define PPB_SCALE_WORD ((1LL << (PPB_EXTRA_BITS + MC_CMD_PTP_IN_ADJUST_BITS +\ - MAX_PPB_BITS)) / 1000000000LL) +/* This is equivalent to 2^66 / 10^9. */ +#define PPB_SCALE_WORD ((1LL << (57)) / 1953125LL) + +/* How much to shift down after scaling to convert to FP40 */ +#define PPB_SHIFT_FP40 26 +/* ... and FP44. */ +#define PPB_SHIFT_FP44 22 #define PTP_SYNC_ATTEMPTS 4 @@ -261,6 +257,8 @@ struct efx_ptp_timeset { * @evt_code: Last event code * @start: Address at which MC indicates ready for synchronisation * @host_time_pps: Host time at last PPS + * @adjfreq_ppb_shift: Shift required to convert scaled parts-per-billion + * frequency adjustment into a fixed point fractional nanosecond format. * @current_adjfreq: Current ppb adjustment. * @phc_clock: Pointer to registered phc device (if primary function) * @phc_clock_info: Registration structure for phc device @@ -310,6 +308,7 @@ struct efx_ptp_data { unsigned int sync_event_minor_shift; } nic_time; unsigned int min_synchronisation_ns; + unsigned int capabilities; struct { s32 ptp_tx; s32 ptp_rx; @@ -323,6 +322,7 @@ struct efx_ptp_data { int evt_code; struct efx_buffer start; struct pps_event_time host_time_pps; + unsigned int adjfreq_ppb_shift; s64 current_adjfreq; struct ptp_clock *phc_clock; struct ptp_clock_info phc_clock_info; @@ -676,6 +676,22 @@ static int efx_ptp_get_attributes(struct efx_nic *efx) else ptp->min_synchronisation_ns = DEFAULT_MIN_SYNCHRONISATION_NS; + if (rc == 0 && + out_len >= MC_CMD_PTP_OUT_GET_ATTRIBUTES_LEN) + ptp->capabilities = MCDI_DWORD(outbuf, + PTP_OUT_GET_ATTRIBUTES_CAPABILITIES); + else + ptp->capabilities = 0; + + /* Set up the shift for conversion between frequency + * adjustments in parts-per-billion and the fixed-point + * fractional ns format that the adapter uses. + */ + if (ptp->capabilities & (1 << MC_CMD_PTP_OUT_GET_ATTRIBUTES_FP44_FREQ_ADJ_LBN)) + ptp->adjfreq_ppb_shift = PPB_SHIFT_FP44; + else + ptp->adjfreq_ppb_shift = PPB_SHIFT_FP40; + return 0; } @@ -2027,9 +2043,10 @@ static int efx_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta) else if (delta < -MAX_PPB) delta = -MAX_PPB; - /* Convert ppb to fixed point ns. */ - adjustment_ns = (((s64)delta * PPB_SCALE_WORD) >> - (PPB_EXTRA_BITS + MAX_PPB_BITS)); + /* Convert ppb to fixed point ns taking care to round correctly. */ + adjustment_ns = ((s64)delta * PPB_SCALE_WORD + + (1 << (ptp_data->adjfreq_ppb_shift - 1))) >> + ptp_data->adjfreq_ppb_shift; MCDI_SET_DWORD(inadj, PTP_IN_OP, MC_CMD_PTP_OP_ADJUST); MCDI_SET_DWORD(inadj, PTP_IN_PERIPH_ID, 0); |