Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1128c756 authored by Carolyn Wyborny's avatar Carolyn Wyborny Committed by Jeff Kirsher
Browse files

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: default avatarCarolyn Wyborny <carolyn.wyborny@intel.com>
Tested-by: default avatarAaron Brown <aaron.f.brown@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent b6e0c419
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -1051,6 +1051,9 @@ static s32 igb_init_hw_82575(struct e1000_hw *hw)

	/* Disabling VLAN filtering */
	hw_dbg("Initializing the IEEE VLAN\n");
	if (hw->mac.type == e1000_i350)
		igb_clear_vfta_i350(hw);
	else
		igb_clear_vfta(hw);

	/* Setup the receive address */
+53 −3
Original line number Diff line number Diff line
@@ -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;
	}

	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;
}
+1 −0
Original line number Diff line number Diff line
@@ -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);
+1 −0
Original line number Diff line number Diff line
@@ -363,6 +363,7 @@ struct igb_adapter {
	u32 rss_queues;
	u32 wvbr;
	int node;
	u32 *shadow_vfta;
};

#define IGB_FLAG_HAS_MSI           (1 << 0)
+6 −0
Original line number Diff line number Diff line
@@ -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");