diff options
author | Carolyn Wyborny <carolyn.wyborny@intel.com> | 2011-10-14 04:13:49 +0400 |
---|---|---|
committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2011-10-21 14:19:39 +0400 |
commit | 1128c756bef8285db3bbde5b26d4a6b4c7e2e613 (patch) | |
tree | 265057e706f6d147c72099deb2b21f2fd74b6b33 /drivers/net/ethernet/intel/igb/e1000_mac.c | |
parent | b6e0c419f040cee87813660bb4efd1fe43a8ebee (diff) | |
download | linux-1128c756bef8285db3bbde5b26d4a6b4c7e2e613.tar.xz |
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 bad3e1425ffb..73aac082c44d 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; } |