diff options
author | Todd Fujinaka <todd.fujinaka@intel.com> | 2014-05-03 02:41:37 -0400 |
---|---|---|
committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2014-05-27 05:09:57 -0400 |
commit | 5e7ff970041321a26f2dc3aa41ba79e787fcf8f9 (patch) | |
tree | 7e72236781a130581d00b17c738926975b79f2a3 /drivers/net | |
parent | b3e5bf1ff32cbc58c56675498565020460c683cd (diff) |
e1000e: 82574/82583 TimeSync errata for SYSTIM read
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>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/ethernet/intel/e1000e/e1000.h | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/e1000e/netdev.c | 27 |
2 files changed, 28 insertions, 1 deletions
diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h index e27e60910949..63bde99a4ab4 100644 --- a/drivers/net/ethernet/intel/e1000e/e1000.h +++ b/drivers/net/ethernet/intel/e1000e/e1000.h | |||
@@ -391,6 +391,8 @@ s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca); | |||
391 | * 25MHz 46-bit 2^46 / 10^9 / 3600 = 19.55 hours | 391 | * 25MHz 46-bit 2^46 / 10^9 / 3600 = 19.55 hours |
392 | */ | 392 | */ |
393 | #define E1000_SYSTIM_OVERFLOW_PERIOD (HZ * 60 * 60 * 4) | 393 | #define E1000_SYSTIM_OVERFLOW_PERIOD (HZ * 60 * 60 * 4) |
394 | #define E1000_MAX_82574_SYSTIM_REREADS 50 | ||
395 | #define E1000_82574_SYSTIM_EPSILON (1ULL << 35ULL) | ||
394 | 396 | ||
395 | /* hardware capability, feature, and workaround flags */ | 397 | /* hardware capability, feature, and workaround flags */ |
396 | #define FLAG_HAS_AMT (1 << 0) | 398 | #define FLAG_HAS_AMT (1 << 0) |
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 6084e6ba45c2..95cf482cf0af 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c | |||
@@ -4099,12 +4099,37 @@ static cycle_t e1000e_cyclecounter_read(const struct cyclecounter *cc) | |||
4099 | struct e1000_adapter *adapter = container_of(cc, struct e1000_adapter, | 4099 | struct e1000_adapter *adapter = container_of(cc, struct e1000_adapter, |
4100 | cc); | 4100 | cc); |
4101 | struct e1000_hw *hw = &adapter->hw; | 4101 | struct e1000_hw *hw = &adapter->hw; |
4102 | cycle_t systim; | 4102 | cycle_t systim, systim_next; |
4103 | 4103 | ||
4104 | /* latch SYSTIMH on read of SYSTIML */ | 4104 | /* latch SYSTIMH on read of SYSTIML */ |
4105 | systim = (cycle_t)er32(SYSTIML); | 4105 | systim = (cycle_t)er32(SYSTIML); |
4106 | systim |= (cycle_t)er32(SYSTIMH) << 32; | 4106 | systim |= (cycle_t)er32(SYSTIMH) << 32; |
4107 | 4107 | ||
4108 | if ((hw->mac.type == e1000_82574) || (hw->mac.type == e1000_82583)) { | ||
4109 | u64 incvalue, time_delta, rem, temp; | ||
4110 | int i; | ||
4111 | |||
4112 | /* errata for 82574/82583 possible bad bits read from SYSTIMH/L | ||
4113 | * check to see that the time is incrementing at a reasonable | ||
4114 | * rate and is a multiple of incvalue | ||
4115 | */ | ||
4116 | incvalue = er32(TIMINCA) & E1000_TIMINCA_INCVALUE_MASK; | ||
4117 | for (i = 0; i < E1000_MAX_82574_SYSTIM_REREADS; i++) { | ||
4118 | /* latch SYSTIMH on read of SYSTIML */ | ||
4119 | systim_next = (cycle_t)er32(SYSTIML); | ||
4120 | systim_next |= (cycle_t)er32(SYSTIMH) << 32; | ||
4121 | |||
4122 | time_delta = systim_next - systim; | ||
4123 | temp = time_delta; | ||
4124 | rem = do_div(temp, incvalue); | ||
4125 | |||
4126 | systim = systim_next; | ||
4127 | |||
4128 | if ((time_delta < E1000_82574_SYSTIM_EPSILON) && | ||
4129 | (rem == 0)) | ||
4130 | break; | ||
4131 | } | ||
4132 | } | ||
4108 | return systim; | 4133 | return systim; |
4109 | } | 4134 | } |
4110 | 4135 | ||