igb: Refactor VFTA configuration
authorAlexander Duyck <aduyck@mirantis.com>
Thu, 7 Jan 2016 07:10:30 +0000 (23:10 -0800)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Tue, 16 Feb 2016 00:24:13 +0000 (16:24 -0800)
This patch starts the clean-up process on the VFTA configuration.
Specifically in this patch I attempt to address and simplify several items
while also updating the code to bring it more inline with what is already
in ixgbe.

Signed-off-by: Alexander Duyck <aduyck@mirantis.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
drivers/net/ethernet/intel/igb/e1000_82575.c
drivers/net/ethernet/intel/igb/e1000_hw.h
drivers/net/ethernet/intel/igb/e1000_mac.c
drivers/net/ethernet/intel/igb/e1000_mac.h

index adb33e2..fff5052 100644 (file)
@@ -34,6 +34,7 @@
 #include "e1000_mac.h"
 #include "e1000_82575.h"
 #include "e1000_i210.h"
+#include "igb.h"
 
 static s32  igb_get_invariants_82575(struct e1000_hw *);
 static s32  igb_acquire_phy_82575(struct e1000_hw *);
@@ -71,6 +72,32 @@ static s32 igb_update_nvm_checksum_i350(struct e1000_hw *hw);
 static const u16 e1000_82580_rxpbs_table[] = {
        36, 72, 144, 1, 2, 4, 8, 16, 35, 70, 140 };
 
+/* 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_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.
+ **/
+static void igb_write_vfta_i350(struct e1000_hw *hw, u32 offset, u32 value)
+{
+       struct igb_adapter *adapter = hw->back;
+       int i;
+
+       for (i = 10; i--;)
+               array_wr32(E1000_VFTA, offset, value);
+
+       wrfl();
+       adapter->shadow_vfta[offset] = value;
+}
+
 /**
  *  igb_sgmii_uses_mdio_82575 - Determine if I2C pins are for external MDIO
  *  @hw: pointer to the HW structure
@@ -429,6 +456,11 @@ static s32 igb_init_mac_params_82575(struct e1000_hw *hw)
                mac->ops.release_swfw_sync = igb_release_swfw_sync_82575;
        }
 
+       if ((hw->mac.type == e1000_i350) || (hw->mac.type == e1000_i354))
+               mac->ops.write_vfta = igb_write_vfta_i350;
+       else
+               mac->ops.write_vfta = igb_write_vfta;
+
        /* Set if part includes ASF firmware */
        mac->asf_firmware_present = true;
        /* Set if manageability features are enabled. */
@@ -1517,10 +1549,7 @@ 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) || (hw->mac.type == e1000_i354))
-               igb_clear_vfta_i350(hw);
-       else
-               igb_clear_vfta(hw);
+       igb_clear_vfta(hw);
 
        /* Setup the receive address */
        igb_init_rx_addrs(hw, rar_count);
index 4034207..f0c416e 100644 (file)
@@ -325,7 +325,7 @@ struct e1000_mac_operations {
        s32 (*get_thermal_sensor_data)(struct e1000_hw *);
        s32 (*init_thermal_sensor_thresh)(struct e1000_hw *);
 #endif
-
+       void (*write_vfta)(struct e1000_hw *, u32, u32);
 };
 
 struct e1000_phy_operations {
index 2a88595..97f6fae 100644 (file)
@@ -92,10 +92,8 @@ void igb_clear_vfta(struct e1000_hw *hw)
 {
        u32 offset;
 
-       for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
-               array_wr32(E1000_VFTA, offset, 0);
-               wrfl();
-       }
+       for (offset = E1000_VLAN_FILTER_TBL_SIZE; offset--;)
+               hw->mac.ops.write_vfta(hw, offset, 0);
 }
 
 /**
@@ -107,54 +105,14 @@ void igb_clear_vfta(struct e1000_hw *hw)
  *  Writes value at the given offset in the register array which stores
  *  the VLAN filter table.
  **/
-static void igb_write_vfta(struct e1000_hw *hw, u32 offset, u32 value)
+void igb_write_vfta(struct e1000_hw *hw, u32 offset, u32 value)
 {
+       struct igb_adapter *adapter = hw->back;
+
        array_wr32(E1000_VFTA, offset, 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.
- **/
-static 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();
+       adapter->shadow_vfta[offset] = value;
 }
 
 /**
@@ -185,38 +143,42 @@ void igb_init_rx_addrs(struct e1000_hw *hw, u16 rar_count)
 /**
  *  igb_vfta_set - enable or disable vlan in VLAN filter table
  *  @hw: pointer to the HW structure
- *  @vid: VLAN id to add or remove
- *  @add: if true add filter, if false remove
+ *  @vlan: VLAN id to add or remove
+ *  @vlan_on: if true add filter, if false remove
  *
  *  Sets or clears a bit in the VLAN filter table array based on VLAN id
  *  and if we are adding or removing the filter
  **/
-s32 igb_vfta_set(struct e1000_hw *hw, u32 vid, bool add)
+s32 igb_vfta_set(struct e1000_hw *hw, u32 vlan, bool vlan_on)
 {
-       u32 index = (vid >> E1000_VFTA_ENTRY_SHIFT) & E1000_VFTA_ENTRY_MASK;
-       u32 mask = 1 << (vid & E1000_VFTA_ENTRY_BIT_SHIFT_MASK);
-       u32 vfta;
        struct igb_adapter *adapter = hw->back;
-       s32 ret_val = 0;
+       u32 regidx, vfta_delta, vfta;
+
+       if (vlan > 4095)
+               return E1000_ERR_PARAM;
+
+       /* Part 1
+        * The VFTA is a bitstring made up of 128 32-bit registers
+        * that enable the particular VLAN id, much like the MTA:
+        *    bits[11-5]: which register
+        *    bits[4-0]:  which bit in the register
+        */
+       regidx = vlan / 32;
+       vfta_delta = 1 << (vlan % 32);
+       vfta = adapter->shadow_vfta[regidx];
 
-       vfta = adapter->shadow_vfta[index];
+       /* vfta_delta represents the difference between the current value
+        * of vfta and the value we want in the register.  Since the diff
+        * is an XOR mask we can just update vfta using an XOR.
+        */
+       vfta_delta &= vlan_on ? ~vfta : vfta;
+       vfta ^= vfta_delta;
 
        /* bit was set/cleared before we started */
-       if ((!!(vfta & mask)) == add) {
-               ret_val = -E1000_ERR_CONFIG;
-       } else {
-               if (add)
-                       vfta |= mask;
-               else
-                       vfta &= ~mask;
-       }
-       if ((hw->mac.type == e1000_i350) || (hw->mac.type == e1000_i354))
-               igb_write_vfta_i350(hw, index, vfta);
-       else
-               igb_write_vfta(hw, index, vfta);
-       adapter->shadow_vfta[index] = vfta;
+       if (vfta_delta)
+               hw->mac.ops.write_vfta(hw, regidx, vfta);
 
-       return ret_val;
+       return 0;
 }
 
 /**
index ea24961..4fbb953 100644 (file)
@@ -56,7 +56,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);
+void igb_write_vfta(struct e1000_hw *hw, u32 offset, u32 value);
 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);