Skip to content
This repository was archived by the owner on Sep 24, 2020. It is now read-only.

Commit 04a244c

Browse files
amaftei-xilinxgregkh
authored andcommitted
sfc: fix timestamp reconstruction at 16-bit rollover points
[ Upstream commit 23797b9 ] 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 <[email protected]> Acked-by: Martin Habets <[email protected]> Signed-off-by: David S. Miller <[email protected]> Signed-off-by: Sasha Levin <[email protected]>
1 parent 5043d35 commit 04a244c

File tree

1 file changed

+35
-3
lines changed
  • drivers/net/ethernet/sfc

1 file changed

+35
-3
lines changed

drivers/net/ethernet/sfc/ptp.c

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -563,13 +563,45 @@ efx_ptp_mac_nic_to_ktime_correction(struct efx_nic *efx,
563563
u32 nic_major, u32 nic_minor,
564564
s32 correction)
565565
{
566+
u32 sync_timestamp;
566567
ktime_t kt = { 0 };
568+
s16 delta;
567569

568570
if (!(nic_major & 0x80000000)) {
569571
WARN_ON_ONCE(nic_major >> 16);
570-
/* Use the top bits from the latest sync event. */
571-
nic_major &= 0xffff;
572-
nic_major |= (last_sync_timestamp_major(efx) & 0xffff0000);
572+
573+
/* Medford provides 48 bits of timestamp, so we must get the top
574+
* 16 bits from the timesync event state.
575+
*
576+
* We only have the lower 16 bits of the time now, but we do
577+
* have a full resolution timestamp at some point in past. As
578+
* long as the difference between the (real) now and the sync
579+
* is less than 2^15, then we can reconstruct the difference
580+
* between those two numbers using only the lower 16 bits of
581+
* each.
582+
*
583+
* Put another way
584+
*
585+
* a - b = ((a mod k) - b) mod k
586+
*
587+
* when -k/2 < (a-b) < k/2. In our case k is 2^16. We know
588+
* (a mod k) and b, so can calculate the delta, a - b.
589+
*
590+
*/
591+
sync_timestamp = last_sync_timestamp_major(efx);
592+
593+
/* Because delta is s16 this does an implicit mask down to
594+
* 16 bits which is what we need, assuming
595+
* MEDFORD_TX_SECS_EVENT_BITS is 16. delta is signed so that
596+
* we can deal with the (unlikely) case of sync timestamps
597+
* arriving from the future.
598+
*/
599+
delta = nic_major - sync_timestamp;
600+
601+
/* Recover the fully specified time now, by applying the offset
602+
* to the (fully specified) sync time.
603+
*/
604+
nic_major = sync_timestamp + delta;
573605

574606
kt = ptp->nic_to_kernel_time(nic_major, nic_minor,
575607
correction);

0 commit comments

Comments
 (0)