sfc: Rewrite adjustment of PPS event in a clearer way
authorBen Hutchings <bhutchings@solarflare.com>
Wed, 12 Feb 2014 18:58:46 +0000 (18:58 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 12 Feb 2014 22:53:34 +0000 (17:53 -0500)
There is substantial latency in generation and handling of PPS events
from the NIC, which we have to correct for before passing a host
timestamp to the PPS subsystem.  We compare clocks with the MC,
giving us two offsets to subtract from the timestamp generated by
pps_get_ts():

(a) Time from the last good sync (where we got host and NIC timestamps
    for nearly the same instant) to the time we called pps_get_ts()
(b) Time from NIC top of second to the last good sync

We currently calculate (a) + (b) in a quite confusing way.
Instead, calculate (a) completely, then add (b) to it.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: Shradha Shah <sshah@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/sfc/ptp.c

index 7d0de5002f4112ef985e458d2af45f14bf313196..28275e395cb87885649e44145f3bc9bb07a7f7b0 100644 (file)
@@ -766,37 +766,36 @@ efx_ptp_process_times(struct efx_nic *efx, MCDI_DECLARE_STRUCT_PTR(synch_buf),
                return -EAGAIN;
        }
 
-       /* Convert the NIC time into kernel time. No correction is required-
-        * this time is the output of a firmware process.
-        */
-       mc_time = ptp->nic_to_kernel_time(ptp->timeset[last_good].major,
-                                         ptp->timeset[last_good].minor, 0);
-
-       /* Calculate delay from actual PPS to last_time */
-       delta = ktime_to_timespec(mc_time);
-       delta.tv_nsec +=
-               last_time->ts_real.tv_nsec -
-               (ptp->timeset[last_good].host_start & MC_NANOSECOND_MASK);
-
-       /* It is possible that the seconds rolled over between taking
+       /* Calculate delay from last good sync (host time) to last_time.
+        * It is possible that the seconds rolled over between taking
         * the start reading and the last value written by the host.  The
         * timescales are such that a gap of more than one second is never
-        * expected.
+        * expected.  delta is *not* normalised.
         */
        start_sec = ptp->timeset[last_good].host_start >> MC_NANOSECOND_BITS;
        last_sec = last_time->ts_real.tv_sec & MC_SECOND_MASK;
-       if (start_sec != last_sec) {
-               if (((start_sec + 1) & MC_SECOND_MASK) != last_sec) {
-                       netif_warn(efx, hw, efx->net_dev,
-                                  "PTP bad synchronisation seconds\n");
-                       return -EAGAIN;
-               } else {
-                       delta.tv_sec = 1;
-               }
-       } else {
-               delta.tv_sec = 0;
+       if (start_sec != last_sec &&
+           ((start_sec + 1) & MC_SECOND_MASK) != last_sec) {
+               netif_warn(efx, hw, efx->net_dev,
+                          "PTP bad synchronisation seconds\n");
+               return -EAGAIN;
        }
+       delta.tv_sec = (last_sec - start_sec) & 1;
+       delta.tv_nsec =
+               last_time->ts_real.tv_nsec -
+               (ptp->timeset[last_good].host_start & MC_NANOSECOND_MASK);
+
+       /* Convert the NIC time at last good sync into kernel time.
+        * No correction is required - this time is the output of a
+        * firmware process.
+        */
+       mc_time = ptp->nic_to_kernel_time(ptp->timeset[last_good].major,
+                                         ptp->timeset[last_good].minor, 0);
+
+       /* Calculate delay from NIC top of second to last_time */
+       delta.tv_nsec += ktime_to_timespec(mc_time).tv_nsec;
 
+       /* Set PPS timestamp to match NIC top of second */
        ptp->host_time_pps = *last_time;
        pps_sub_ts(&ptp->host_time_pps, delta);