diff options
Diffstat (limited to 'drivers/net/ethernet/intel/e1000e/netdev.c')
| -rw-r--r-- | drivers/net/ethernet/intel/e1000e/netdev.c | 66 | 
1 files changed, 39 insertions, 27 deletions
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 02f443958f31..7017281ba2dc 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -4303,6 +4303,42 @@ void e1000e_reinit_locked(struct e1000_adapter *adapter)  }  /** + * e1000e_sanitize_systim - sanitize raw cycle counter reads + * @hw: pointer to the HW structure + * @systim: cycle_t value read, sanitized and returned + * + * 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. + **/ +static cycle_t e1000e_sanitize_systim(struct e1000_hw *hw, cycle_t systim) +{ +	u64 time_delta, rem, temp; +	cycle_t systim_next; +	u32 incvalue; +	int i; + +	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; +		/* VMWare users have seen incvalue of zero, don't div / 0 */ +		rem = incvalue ? do_div(temp, incvalue) : (time_delta != 0); + +		systim = systim_next; + +		if ((time_delta < E1000_82574_SYSTIM_EPSILON) && (rem == 0)) +			break; +	} + +	return systim; +} + +/**   * e1000e_cyclecounter_read - read raw cycle counter (used by time counter)   * @cc: cyclecounter structure   **/ @@ -4312,7 +4348,7 @@ static cycle_t e1000e_cyclecounter_read(const struct cyclecounter *cc)  						     cc);  	struct e1000_hw *hw = &adapter->hw;  	u32 systimel, systimeh; -	cycle_t systim, systim_next; +	cycle_t systim;  	/* SYSTIMH latching upon SYSTIML read does not work well.  	 * This means that if SYSTIML overflows after we read it but before  	 * we read SYSTIMH, the value of SYSTIMH has been incremented and we @@ -4335,33 +4371,9 @@ static cycle_t e1000e_cyclecounter_read(const struct cyclecounter *cc)  	systim = (cycle_t)systimel;  	systim |= (cycle_t)systimeh << 32; -	if ((hw->mac.type == e1000_82574) || (hw->mac.type == e1000_82583)) { -		u64 time_delta, rem, temp; -		u32 incvalue; -		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; -			/* VMWare users have seen incvalue of zero, don't div / 0 */ -			rem = incvalue ? do_div(temp, incvalue) : (time_delta != 0); - -			systim = systim_next; +	if (adapter->flags2 & FLAG2_CHECK_SYSTIM_OVERFLOW) +		systim = e1000e_sanitize_systim(hw, systim); -			if ((time_delta < E1000_82574_SYSTIM_EPSILON) && -			    (rem == 0)) -				break; -		} -	}  	return systim;  }  | 
