net/ixgbe/base: simplify VLAN management
authorBeilei Xing <beilei.xing@intel.com>
Thu, 23 Jun 2016 07:22:29 +0000 (15:22 +0800)
committerBruce Richardson <bruce.richardson@intel.com>
Mon, 27 Jun 2016 14:17:53 +0000 (16:17 +0200)
This patch simplifies the adding and removing VLANs from
VFTA/VLVF/VLVFB registers. The logic to determine the registers to use
has been simplified to (vid / 32) and (1 - vid / 32). Many conditional
paths and checks are no longer needed with this patch.

Signed-off-by: Beilei Xing <beilei.xing@intel.com>
drivers/net/ixgbe/base/ixgbe_api.c
drivers/net/ixgbe/base/ixgbe_api.h
drivers/net/ixgbe/base/ixgbe_common.c
drivers/net/ixgbe/base/ixgbe_common.h
drivers/net/ixgbe/base/ixgbe_type.h

index e117b86..90deaf1 100644 (file)
@@ -1080,8 +1080,8 @@ s32 ixgbe_clear_vfta(struct ixgbe_hw *hw)
  *  ixgbe_set_vfta - Set VLAN filter table
  *  @hw: pointer to hardware structure
  *  @vlan: VLAN id to write to VLAN filter
- *  @vind: VMDq output index that maps queue to VLAN id in VFTA
- *  @vlan_on: boolean flag to turn on/off VLAN in VFTA
+ *  @vind: VMDq output index that maps queue to VLAN id in VLVFB
+ *  @vlan_on: boolean flag to turn on/off VLAN
  *
  *  Turn on/off specified VLAN in the VLAN filter table.
  **/
@@ -1095,18 +1095,20 @@ s32 ixgbe_set_vfta(struct ixgbe_hw *hw, u32 vlan, u32 vind, bool vlan_on)
  *  ixgbe_set_vlvf - Set VLAN Pool Filter
  *  @hw: pointer to hardware structure
  *  @vlan: VLAN id to write to VLAN filter
- *  @vind: VMDq output index that maps queue to VLAN id in VFVFB
- *  @vlan_on: boolean flag to turn on/off VLAN in VFVF
- *  @vfta_changed: pointer to boolean flag which indicates whether VFTA
- *                 should be changed
+ *  @vind: VMDq output index that maps queue to VLAN id in VLVFB
+ *  @vlan_on: boolean flag to turn on/off VLAN in VLVF
+ *  @vfta_delta: pointer to the difference between the current value of VFTA
+ *               and the desired value
+ *  @vfta: the desired value of the VFTA
  *
  *  Turn on/off specified bit in VLVF table.
  **/
 s32 ixgbe_set_vlvf(struct ixgbe_hw *hw, u32 vlan, u32 vind, bool vlan_on,
-                   bool *vfta_changed)
+                  u32 *vfta_delta, u32 vfta)
 {
        return ixgbe_call_func(hw, hw->mac.ops.set_vlvf, (hw, vlan, vind,
-                              vlan_on, vfta_changed), IXGBE_NOT_IMPLEMENTED);
+                              vlan_on, vfta_delta, vfta),
+                              IXGBE_NOT_IMPLEMENTED);
 }
 
 /**
index f5970a8..9431d14 100644 (file)
@@ -126,7 +126,7 @@ s32 ixgbe_clear_vfta(struct ixgbe_hw *hw);
 s32 ixgbe_set_vfta(struct ixgbe_hw *hw, u32 vlan,
                   u32 vind, bool vlan_on);
 s32 ixgbe_set_vlvf(struct ixgbe_hw *hw, u32 vlan, u32 vind,
-                  bool vlan_on, bool *vfta_changed);
+                  bool vlan_on, u32 *vfta_delta, u32 vfta);
 s32 ixgbe_fc_enable(struct ixgbe_hw *hw);
 s32 ixgbe_setup_fc(struct ixgbe_hw *hw);
 s32 ixgbe_set_fw_drv_ver(struct ixgbe_hw *hw, u8 maj, u8 min, u8 build,
index 0a708cf..4551a2a 100644 (file)
@@ -3853,24 +3853,20 @@ s32 ixgbe_find_vlvf_slot(struct ixgbe_hw *hw, u32 vlan)
  *  ixgbe_set_vfta_generic - Set VLAN filter table
  *  @hw: pointer to hardware structure
  *  @vlan: VLAN id to write to VLAN filter
- *  @vind: VMDq output index that maps queue to VLAN id in VFVFB
- *  @vlan_on: boolean flag to turn on/off VLAN in VFVF
+ *  @vind: VMDq output index that maps queue to VLAN id in VLVFB
+ *  @vlan_on: boolean flag to turn on/off VLAN
  *
  *  Turn on/off specified VLAN in the VLAN filter table.
  **/
 s32 ixgbe_set_vfta_generic(struct ixgbe_hw *hw, u32 vlan, u32 vind,
                           bool vlan_on)
 {
-       s32 regindex;
-       u32 bitindex;
-       u32 vfta;
-       u32 targetbit;
-       s32 ret_val = IXGBE_SUCCESS;
-       bool vfta_changed = false;
+       u32 regidx, vfta_delta, vfta;
+       s32 ret_val;
 
        DEBUGFUNC("ixgbe_set_vfta_generic");
 
-       if (vlan > 4095)
+       if (vlan > 4095 || vind > 63)
                return IXGBE_ERR_PARAM;
 
        /*
@@ -3885,33 +3881,28 @@ s32 ixgbe_set_vfta_generic(struct ixgbe_hw *hw, u32 vlan, u32 vind,
         *    bits[11-5]: which register
         *    bits[4-0]:  which bit in the register
         */
-       regindex = (vlan >> 5) & 0x7F;
-       bitindex = vlan & 0x1F;
-       targetbit = (1 << bitindex);
-       vfta = IXGBE_READ_REG(hw, IXGBE_VFTA(regindex));
-
-       if (vlan_on) {
-               if (!(vfta & targetbit)) {
-                       vfta |= targetbit;
-                       vfta_changed = true;
-               }
-       } else {
-               if ((vfta & targetbit)) {
-                       vfta &= ~targetbit;
-                       vfta_changed = true;
-               }
-       }
+       regidx = vlan / 32;
+       vfta_delta = 1 << (vlan % 32);
+       vfta = IXGBE_READ_REG(hw, IXGBE_VFTA(regidx));
+
+       /* 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 the vfta using an XOR
+        */
+       vfta_delta &= vlan_on ? ~vfta : vfta;
+       vfta ^= vfta_delta;
 
        /* Part 2
         * Call ixgbe_set_vlvf_generic to set VLVFB and VLVF
         */
-       ret_val = ixgbe_set_vlvf_generic(hw, vlan, vind, vlan_on,
-                                        &vfta_changed);
+       ret_val = ixgbe_set_vlvf_generic(hw, vlan, vind, vlan_on, &vfta_delta,
+                                        vfta);
        if (ret_val != IXGBE_SUCCESS)
                return ret_val;
 
-       if (vfta_changed)
-               IXGBE_WRITE_REG(hw, IXGBE_VFTA(regindex), vfta);
+       /* Update VFTA now that we are ready for traffic */
+       if (vfta_delta)
+               IXGBE_WRITE_REG(hw, IXGBE_VFTA(regidx), vfta);
 
        return IXGBE_SUCCESS;
 }
@@ -3920,21 +3911,23 @@ s32 ixgbe_set_vfta_generic(struct ixgbe_hw *hw, u32 vlan, u32 vind,
  *  ixgbe_set_vlvf_generic - Set VLAN Pool Filter
  *  @hw: pointer to hardware structure
  *  @vlan: VLAN id to write to VLAN filter
- *  @vind: VMDq output index that maps queue to VLAN id in VFVFB
- *  @vlan_on: boolean flag to turn on/off VLAN in VFVF
- *  @vfta_changed: pointer to boolean flag which indicates whether VFTA
- *                 should be changed
+ *  @vind: VMDq output index that maps queue to VLAN id in VLVFB
+ *  @vlan_on: boolean flag to turn on/off VLAN in VLVF
+ *  @vfta_delta: pointer to the difference between the current value of VFTA
+ * and the desired value
+ *  @vfta: the desired value of the VFTA
  *
  *  Turn on/off specified bit in VLVF table.
  **/
 s32 ixgbe_set_vlvf_generic(struct ixgbe_hw *hw, u32 vlan, u32 vind,
-                           bool vlan_on, bool *vfta_changed)
+                          bool vlan_on, u32 *vfta_delta, u32 vfta)
 {
-       u32 vt;
+       u32 bits;
+       s32 vlvf_index;
 
        DEBUGFUNC("ixgbe_set_vlvf_generic");
 
-       if (vlan > 4095)
+       if (vlan > 4095 || vind > 63)
                return IXGBE_ERR_PARAM;
 
        /* If VT Mode is set
@@ -3944,82 +3937,57 @@ s32 ixgbe_set_vlvf_generic(struct ixgbe_hw *hw, u32 vlan, u32 vind,
         *   Or !vlan_on
         *     clear the pool bit and possibly the vind
         */
-       vt = IXGBE_READ_REG(hw, IXGBE_VT_CTL);
-       if (vt & IXGBE_VT_CTL_VT_ENABLE) {
-               s32 vlvf_index;
-               u32 bits;
-
-               vlvf_index = ixgbe_find_vlvf_slot(hw, vlan);
-               if (vlvf_index < 0)
-                       return vlvf_index;
-
-               if (vlan_on) {
-                       /* set the pool bit */
-                       if (vind < 32) {
-                               bits = IXGBE_READ_REG(hw,
-                                               IXGBE_VLVFB(vlvf_index * 2));
-                               bits |= (1 << vind);
-                               IXGBE_WRITE_REG(hw,
-                                               IXGBE_VLVFB(vlvf_index * 2),
-                                               bits);
-                       } else {
-                               bits = IXGBE_READ_REG(hw,
-                                       IXGBE_VLVFB((vlvf_index * 2) + 1));
-                               bits |= (1 << (vind - 32));
-                               IXGBE_WRITE_REG(hw,
-                                       IXGBE_VLVFB((vlvf_index * 2) + 1),
-                                       bits);
-                       }
-               } else {
-                       /* clear the pool bit */
-                       if (vind < 32) {
-                               bits = IXGBE_READ_REG(hw,
-                                               IXGBE_VLVFB(vlvf_index * 2));
-                               bits &= ~(1 << vind);
-                               IXGBE_WRITE_REG(hw,
-                                               IXGBE_VLVFB(vlvf_index * 2),
-                                               bits);
-                               bits |= IXGBE_READ_REG(hw,
-                                       IXGBE_VLVFB((vlvf_index * 2) + 1));
-                       } else {
-                               bits = IXGBE_READ_REG(hw,
-                                       IXGBE_VLVFB((vlvf_index * 2) + 1));
-                               bits &= ~(1 << (vind - 32));
-                               IXGBE_WRITE_REG(hw,
-                                       IXGBE_VLVFB((vlvf_index * 2) + 1),
-                                       bits);
-                               bits |= IXGBE_READ_REG(hw,
-                                               IXGBE_VLVFB(vlvf_index * 2));
-                       }
-               }
+       if (!(IXGBE_READ_REG(hw, IXGBE_VT_CTL) & IXGBE_VT_CTL_VT_ENABLE))
+               return IXGBE_SUCCESS;
+       vlvf_index = ixgbe_find_vlvf_slot(hw, vlan);
+       if (vlvf_index < 0)
+               return vlvf_index;
 
-               /*
-                * If there are still bits set in the VLVFB registers
-                * for the VLAN ID indicated we need to see if the
-                * caller is requesting that we clear the VFTA entry bit.
-                * If the caller has requested that we clear the VFTA
-                * entry bit but there are still pools/VFs using this VLAN
-                * ID entry then ignore the request.  We're not worried
-                * about the case where we're turning the VFTA VLAN ID
-                * entry bit on, only when requested to turn it off as
-                * there may be multiple pools and/or VFs using the
-                * VLAN ID entry.  In that case we cannot clear the
-                * VFTA bit until all pools/VFs using that VLAN ID have also
-                * been cleared.  This will be indicated by "bits" being
-                * zero.
+       bits = IXGBE_READ_REG(hw, IXGBE_VLVFB(vlvf_index * 2 + vind / 32));
+
+       /* set the pool bit */
+       bits |= 1 << (vind % 32);
+       if (vlan_on)
+               goto vlvf_update;
+
+       /* clear the pool bit */
+       bits ^= 1 << (vind % 32);
+
+       if (!bits &&
+           !IXGBE_READ_REG(hw, IXGBE_VLVFB(vlvf_index * 2 + 1 - vind / 32))) {
+               /* Clear VFTA first, then disable VLVF.  Otherwise
+                * we run the risk of stray packets leaking into
+                * the PF via the default pool
                 */
-               if (bits) {
-                       IXGBE_WRITE_REG(hw, IXGBE_VLVF(vlvf_index),
-                                       (IXGBE_VLVF_VIEN | vlan));
-                       if ((!vlan_on) && (vfta_changed != NULL)) {
-                               /* someone wants to clear the vfta entry
-                                * but some pools/VFs are still using it.
-                                * Ignore it. */
-                               *vfta_changed = false;
-                       }
-               } else
-                       IXGBE_WRITE_REG(hw, IXGBE_VLVF(vlvf_index), 0);
+               if (vfta_delta)
+                       IXGBE_WRITE_REG(hw, IXGBE_VFTA(vlan / 32), vfta);
+
+               /* disable VLVF and clear remaining bit from pool */
+               IXGBE_WRITE_REG(hw, IXGBE_VLVF(vlvf_index), 0);
+               IXGBE_WRITE_REG(hw, IXGBE_VLVFB(vlvf_index * 2 + vind / 32), 0);
+
+               return IXGBE_SUCCESS;
        }
+       /* If there are still bits set in the VLVFB registers
+        * for the VLAN ID indicated we need to see if the
+        * caller is requesting that we clear the VFTA entry bit.
+        * If the caller has requested that we clear the VFTA
+        * entry bit but there are still pools/VFs using this VLAN
+        * ID entry then ignore the request.  We're not worried
+        * about the case where we're turning the VFTA VLAN ID
+        * entry bit on, only when requested to turn it off as
+        * there may be multiple pools and/or VFs using the
+        * VLAN ID entry.  In that case we cannot clear the
+        * VFTA bit until all pools/VFs using that VLAN ID have also
+        * been cleared.  This will be indicated by "bits" being
+        * zero.
+        */
+       *vfta_delta = 0;
+
+vlvf_update:
+       /* record pool change and enable VLAN ID if not already enabled */
+       IXGBE_WRITE_REG(hw, IXGBE_VLVFB(vlvf_index * 2 + vind / 32), bits);
+       IXGBE_WRITE_REG(hw, IXGBE_VLVF(vlvf_index), IXGBE_VLVF_VIEN | vlan);
 
        return IXGBE_SUCCESS;
 }
@@ -4042,7 +4010,7 @@ s32 ixgbe_clear_vfta_generic(struct ixgbe_hw *hw)
        for (offset = 0; offset < IXGBE_VLVF_ENTRIES; offset++) {
                IXGBE_WRITE_REG(hw, IXGBE_VLVF(offset), 0);
                IXGBE_WRITE_REG(hw, IXGBE_VLVFB(offset * 2), 0);
-               IXGBE_WRITE_REG(hw, IXGBE_VLVFB((offset * 2) + 1), 0);
+               IXGBE_WRITE_REG(hw, IXGBE_VLVFB(offset * 2 + 1), 0);
        }
 
        return IXGBE_SUCCESS;
index fd67a88..b4cd366 100644 (file)
@@ -135,7 +135,7 @@ s32 ixgbe_init_uta_tables_generic(struct ixgbe_hw *hw);
 s32 ixgbe_set_vfta_generic(struct ixgbe_hw *hw, u32 vlan,
                         u32 vind, bool vlan_on);
 s32 ixgbe_set_vlvf_generic(struct ixgbe_hw *hw, u32 vlan, u32 vind,
-                          bool vlan_on, bool *vfta_changed);
+                          bool vlan_on, u32 *vfta_delta, u32 vfta);
 s32 ixgbe_clear_vfta_generic(struct ixgbe_hw *hw);
 s32 ixgbe_find_vlvf_slot(struct ixgbe_hw *hw, u32 vlan);
 
index ec1f4e0..b1fd079 100644 (file)
@@ -3866,7 +3866,7 @@ struct ixgbe_mac_operations {
        s32 (*disable_mc)(struct ixgbe_hw *);
        s32 (*clear_vfta)(struct ixgbe_hw *);
        s32 (*set_vfta)(struct ixgbe_hw *, u32, u32, bool);
-       s32 (*set_vlvf)(struct ixgbe_hw *, u32, u32, bool, bool *);
+       s32 (*set_vlvf)(struct ixgbe_hw *, u32, u32, bool, u32 *, u32);
        s32 (*init_uta_tables)(struct ixgbe_hw *);
        void (*set_mac_anti_spoofing)(struct ixgbe_hw *, bool, int);
        void (*set_vlan_anti_spoofing)(struct ixgbe_hw *, bool, int);