diff options
| author | Carolyn Wyborny <carolyn.wyborny@intel.com> | 2011-10-14 00:13:49 +0000 | 
|---|---|---|
| committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2011-10-21 03:19:39 -0700 | 
| commit | 1128c756bef8285db3bbde5b26d4a6b4c7e2e613 (patch) | |
| tree | 265057e706f6d147c72099deb2b21f2fd74b6b33 /drivers/net/ethernet/intel/igb/e1000_mac.c | |
| parent | b6e0c419f040cee87813660bb4efd1fe43a8ebee (diff) | |
| download | olio-linux-3.10-1128c756bef8285db3bbde5b26d4a6b4c7e2e613.tar.xz olio-linux-3.10-1128c756bef8285db3bbde5b26d4a6b4c7e2e613.zip  | |
igb: VFTA Table Fix for i350 devices
Due to a hardware problem, writes to the VFTA register can
theoretically fail. Although the likelihood of this is very low.
This patch adds a shadow vfta in the adapter struct for reading
and adds new write functions for these devices to work around the problem.
Signed-off-by: Carolyn Wyborny <carolyn.wyborny@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/ethernet/intel/igb/e1000_mac.c')
| -rw-r--r-- | drivers/net/ethernet/intel/igb/e1000_mac.c | 56 | 
1 files changed, 53 insertions, 3 deletions
diff --git a/drivers/net/ethernet/intel/igb/e1000_mac.c b/drivers/net/ethernet/intel/igb/e1000_mac.c index bad3e1425ff..73aac082c44 100644 --- a/drivers/net/ethernet/intel/igb/e1000_mac.c +++ b/drivers/net/ethernet/intel/igb/e1000_mac.c @@ -117,6 +117,50 @@ static void igb_write_vfta(struct e1000_hw *hw, u32 offset, u32 value)  	wrfl();  } +/* Due to a hw errata, if the host tries to  configure the VFTA register + * while performing queries from the BMC or DMA, then the VFTA in some + * cases won't be written. + */ + +/** + *  igb_clear_vfta_i350 - Clear VLAN filter table + *  @hw: pointer to the HW structure + * + *  Clears the register array which contains the VLAN filter table by + *  setting all the values to 0. + **/ +void igb_clear_vfta_i350(struct e1000_hw *hw) +{ +	u32 offset; +	int i; + +	for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) { +		for (i = 0; i < 10; i++) +			array_wr32(E1000_VFTA, offset, 0); + +		wrfl(); +	} +} + +/** + *  igb_write_vfta_i350 - Write value to VLAN filter table + *  @hw: pointer to the HW structure + *  @offset: register offset in VLAN filter table + *  @value: register value written to VLAN filter table + * + *  Writes value at the given offset in the register array which stores + *  the VLAN filter table. + **/ +void igb_write_vfta_i350(struct e1000_hw *hw, u32 offset, u32 value) +{ +	int i; + +	for (i = 0; i < 10; i++) +		array_wr32(E1000_VFTA, offset, value); + +	wrfl(); +} +  /**   *  igb_init_rx_addrs - Initialize receive address's   *  @hw: pointer to the HW structure @@ -155,9 +199,12 @@ s32 igb_vfta_set(struct e1000_hw *hw, u32 vid, bool add)  {  	u32 index = (vid >> E1000_VFTA_ENTRY_SHIFT) & E1000_VFTA_ENTRY_MASK;  	u32 mask = 1 << (vid & E1000_VFTA_ENTRY_BIT_SHIFT_MASK); -	u32 vfta = array_rd32(E1000_VFTA, index); +	u32 vfta; +	struct igb_adapter *adapter = hw->back;  	s32 ret_val = 0; +	vfta = adapter->shadow_vfta[index]; +  	/* bit was set/cleared before we started */  	if ((!!(vfta & mask)) == add) {  		ret_val = -E1000_ERR_CONFIG; @@ -167,8 +214,11 @@ s32 igb_vfta_set(struct e1000_hw *hw, u32 vid, bool add)  		else  			vfta &= ~mask;  	} - -	igb_write_vfta(hw, index, vfta); +	if (hw->mac.type == e1000_i350) +		igb_write_vfta_i350(hw, index, vfta); +	else +		igb_write_vfta(hw, index, vfta); +	adapter->shadow_vfta[index] = vfta;  	return ret_val;  }  |