mirror of https://gitee.com/openkylin/linux.git
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>
This commit is contained in:
parent
b6e0c419f0
commit
1128c756be
|
@ -1051,7 +1051,10 @@ static s32 igb_init_hw_82575(struct e1000_hw *hw)
|
|||
|
||||
/* Disabling VLAN filtering */
|
||||
hw_dbg("Initializing the IEEE VLAN\n");
|
||||
igb_clear_vfta(hw);
|
||||
if (hw->mac.type == e1000_i350)
|
||||
igb_clear_vfta_i350(hw);
|
||||
else
|
||||
igb_clear_vfta(hw);
|
||||
|
||||
/* Setup the receive address */
|
||||
igb_init_rx_addrs(hw, rar_count);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -60,6 +60,7 @@ s32 igb_write_8bit_ctrl_reg(struct e1000_hw *hw, u32 reg,
|
|||
|
||||
void igb_clear_hw_cntrs_base(struct e1000_hw *hw);
|
||||
void igb_clear_vfta(struct e1000_hw *hw);
|
||||
void igb_clear_vfta_i350(struct e1000_hw *hw);
|
||||
s32 igb_vfta_set(struct e1000_hw *hw, u32 vid, bool add);
|
||||
void igb_config_collision_dist(struct e1000_hw *hw);
|
||||
void igb_init_rx_addrs(struct e1000_hw *hw, u16 rar_count);
|
||||
|
|
|
@ -363,6 +363,7 @@ struct igb_adapter {
|
|||
u32 rss_queues;
|
||||
u32 wvbr;
|
||||
int node;
|
||||
u32 *shadow_vfta;
|
||||
};
|
||||
|
||||
#define IGB_FLAG_HAS_MSI (1 << 0)
|
||||
|
|
|
@ -2206,6 +2206,7 @@ static void __devexit igb_remove(struct pci_dev *pdev)
|
|||
pci_release_selected_regions(pdev,
|
||||
pci_select_bars(pdev, IORESOURCE_MEM));
|
||||
|
||||
kfree(adapter->shadow_vfta);
|
||||
free_netdev(netdev);
|
||||
|
||||
pci_disable_pcie_error_reporting(pdev);
|
||||
|
@ -2438,6 +2439,11 @@ static int __devinit igb_sw_init(struct igb_adapter *adapter)
|
|||
((adapter->rss_queues > 1) && (adapter->vfs_allocated_count > 6)))
|
||||
adapter->flags |= IGB_FLAG_QUEUE_PAIRS;
|
||||
|
||||
/* Setup and initialize a copy of the hw vlan table array */
|
||||
adapter->shadow_vfta = kzalloc(sizeof(u32) *
|
||||
E1000_VLAN_FILTER_TBL_SIZE,
|
||||
GFP_ATOMIC);
|
||||
|
||||
/* This call may decrease the number of queues */
|
||||
if (igb_init_interrupt_scheme(adapter)) {
|
||||
dev_err(&pdev->dev, "Unable to allocate memory for queues\n");
|
||||
|
|
Loading…
Reference in New Issue