e1000e: 82574/82583 TimeSync errata for SYSTIM read
authorTodd Fujinaka <todd.fujinaka@intel.com>
Sat, 3 May 2014 06:41:37 +0000 (06:41 +0000)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Tue, 27 May 2014 09:09:57 +0000 (02:09 -0700)
Due to a synchronization error, the value read from SYSTIML/SYSTIMH
might be incorrect.

Signed-off-by: Todd Fujinaka <todd.fujinaka@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
drivers/net/ethernet/intel/e1000e/e1000.h
drivers/net/ethernet/intel/e1000e/netdev.c

index e27e609..63bde99 100644 (file)
@@ -391,6 +391,8 @@ s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca);
  * 25MHz       46-bit  2^46 / 10^9 / 3600 = 19.55 hours
  */
 #define E1000_SYSTIM_OVERFLOW_PERIOD   (HZ * 60 * 60 * 4)
+#define E1000_MAX_82574_SYSTIM_REREADS 50
+#define E1000_82574_SYSTIM_EPSILON     (1ULL << 35ULL)
 
 /* hardware capability, feature, and workaround flags */
 #define FLAG_HAS_AMT                      (1 << 0)
index 6084e6b..95cf482 100644 (file)
@@ -4099,12 +4099,37 @@ static cycle_t e1000e_cyclecounter_read(const struct cyclecounter *cc)
        struct e1000_adapter *adapter = container_of(cc, struct e1000_adapter,
                                                     cc);
        struct e1000_hw *hw = &adapter->hw;
-       cycle_t systim;
+       cycle_t systim, systim_next;
 
        /* latch SYSTIMH on read of SYSTIML */
        systim = (cycle_t)er32(SYSTIML);
        systim |= (cycle_t)er32(SYSTIMH) << 32;
 
+       if ((hw->mac.type == e1000_82574) || (hw->mac.type == e1000_82583)) {
+               u64 incvalue, time_delta, rem, temp;
+               int i;
+
+               /* errata for 82574/82583 possible bad bits read from SYSTIMH/L
+                * check to see that the time is incrementing at a reasonable
+                * rate and is a multiple of incvalue
+                */
+               incvalue = er32(TIMINCA) & E1000_TIMINCA_INCVALUE_MASK;
+               for (i = 0; i < E1000_MAX_82574_SYSTIM_REREADS; i++) {
+                       /* latch SYSTIMH on read of SYSTIML */
+                       systim_next = (cycle_t)er32(SYSTIML);
+                       systim_next |= (cycle_t)er32(SYSTIMH) << 32;
+
+                       time_delta = systim_next - systim;
+                       temp = time_delta;
+                       rem = do_div(temp, incvalue);
+
+                       systim = systim_next;
+
+                       if ((time_delta < E1000_82574_SYSTIM_EPSILON) &&
+                           (rem == 0))
+                               break;
+               }
+       }
        return systim;
 }