[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <d298a514-5b0b-eaab-6806-de10e3fe88f5@solarflare.com>
Date: Thu, 27 Feb 2020 17:49:05 +0000
From: Martin Habets <mhabets@...arflare.com>
To: "Alex Maftei (amaftei)" <amaftei@...arflare.com>,
<netdev@...r.kernel.org>, <davem@...emloft.net>
CC: <linux-net-drivers@...arflare.com>
Subject: Re: [PATCH net] sfc: fix timestamp reconstruction at 16-bit rollover
points
On 26/02/2020 17:33, Alex Maftei (amaftei) wrote:
> We can't just use the top bits of the last sync event as they could be
> off-by-one every 65,536 seconds, giving an error in reconstruction of
> 65,536 seconds.
>
> This patch uses the difference in the bottom 16 bits (mod 2^16) to
> calculate an offset that needs to be applied to the last sync event to
> get to the current time.
>
> Signed-off-by: Alexandru-Mihai Maftei <amaftei@...arflare.com>
Acked-by: Martin Habets <mhabets@...arflare.com>
> ---
> drivers/net/ethernet/sfc/ptp.c | 38 +++++++++++++++++++++++++++++++---
> 1 file changed, 35 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/net/ethernet/sfc/ptp.c b/drivers/net/ethernet/sfc/ptp.c
> index af15a737c675..59b4f16896a8 100644
> --- a/drivers/net/ethernet/sfc/ptp.c
> +++ b/drivers/net/ethernet/sfc/ptp.c
> @@ -560,13 +560,45 @@ efx_ptp_mac_nic_to_ktime_correction(struct efx_nic *efx,
> u32 nic_major, u32 nic_minor,
> s32 correction)
> {
> + u32 sync_timestamp;
> ktime_t kt = { 0 };
> + s16 delta;
>
> if (!(nic_major & 0x80000000)) {
> WARN_ON_ONCE(nic_major >> 16);
> - /* Use the top bits from the latest sync event. */
> - nic_major &= 0xffff;
> - nic_major |= (last_sync_timestamp_major(efx) & 0xffff0000);
> +
> + /* Medford provides 48 bits of timestamp, so we must get the top
> + * 16 bits from the timesync event state.
> + *
> + * We only have the lower 16 bits of the time now, but we do
> + * have a full resolution timestamp at some point in past. As
> + * long as the difference between the (real) now and the sync
> + * is less than 2^15, then we can reconstruct the difference
> + * between those two numbers using only the lower 16 bits of
> + * each.
> + *
> + * Put another way
> + *
> + * a - b = ((a mod k) - b) mod k
> + *
> + * when -k/2 < (a-b) < k/2. In our case k is 2^16. We know
> + * (a mod k) and b, so can calculate the delta, a - b.
> + *
> + */
> + sync_timestamp = last_sync_timestamp_major(efx);
> +
> + /* Because delta is s16 this does an implicit mask down to
> + * 16 bits which is what we need, assuming
> + * MEDFORD_TX_SECS_EVENT_BITS is 16. delta is signed so that
> + * we can deal with the (unlikely) case of sync timestamps
> + * arriving from the future.
> + */
> + delta = nic_major - sync_timestamp;
> +
> + /* Recover the fully specified time now, by applying the offset
> + * to the (fully specified) sync time.
> + */
> + nic_major = sync_timestamp + delta;
>
> kt = ptp->nic_to_kernel_time(nic_major, nic_minor,
> correction);
>
Powered by blists - more mailing lists