ixgbe: Fix VLAN promisc in relation to SR-IOV
authorAlexander Duyck <aduyck@mirantis.com>
Tue, 3 Nov 2015 01:10:19 +0000 (17:10 -0800)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Sat, 12 Dec 2015 09:54:36 +0000 (01:54 -0800)
This patch is a follow-on for enabling VLAN promiscuous and allowing the PF
to add VLANs without adding a VLVF entry.  What this patch does is go
through and free the VLVF registers if they are not needed as the VLAN
belongs only to the PF which is the default pool.

Signed-off-by: Alexander Duyck <aduyck@mirantis.com>
Tested-by: Phil Schmitt <phillip.j.schmitt@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
drivers/net/ethernet/intel/ixgbe/ixgbe.h
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c

index 0269c0ca997c24ea36d8149a1e9cd6a2c5c30351..f4c9a42dafcfb018d3b9b34a9d8bd72d09c5fc09 100644 (file)
@@ -898,6 +898,7 @@ int ixgbe_add_mac_filter(struct ixgbe_adapter *adapter,
                         const u8 *addr, u16 queue);
 int ixgbe_del_mac_filter(struct ixgbe_adapter *adapter,
                         const u8 *addr, u16 queue);
+void ixgbe_update_pf_promisc_vlvf(struct ixgbe_adapter *adapter, u32 vid);
 void ixgbe_clear_interrupt_scheme(struct ixgbe_adapter *adapter);
 netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *, struct ixgbe_adapter *,
                                  struct ixgbe_ring *);
index 431c70ca603eed63b0e6d50934f5daac1452f475..66c64a3767198d78f49efe2b52bf03a99de0dc04 100644 (file)
@@ -3908,6 +3908,50 @@ static int ixgbe_vlan_rx_add_vid(struct net_device *netdev,
        return 0;
 }
 
+static int ixgbe_find_vlvf_entry(struct ixgbe_hw *hw, u32 vlan)
+{
+       u32 vlvf;
+       int idx;
+
+       /* short cut the special case */
+       if (vlan == 0)
+               return 0;
+
+       /* Search for the vlan id in the VLVF entries */
+       for (idx = IXGBE_VLVF_ENTRIES; --idx;) {
+               vlvf = IXGBE_READ_REG(hw, IXGBE_VLVF(idx));
+               if ((vlvf & VLAN_VID_MASK) == vlan)
+                       break;
+       }
+
+       return idx;
+}
+
+void ixgbe_update_pf_promisc_vlvf(struct ixgbe_adapter *adapter, u32 vid)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 bits, word;
+       int idx;
+
+       idx = ixgbe_find_vlvf_entry(hw, vid);
+       if (!idx)
+               return;
+
+       /* See if any other pools are set for this VLAN filter
+        * entry other than the PF.
+        */
+       word = idx * 2 + (VMDQ_P(0) / 32);
+       bits = ~(1 << (VMDQ_P(0)) % 32);
+       bits &= IXGBE_READ_REG(hw, IXGBE_VLVFB(word));
+
+       /* Disable the filter so this falls into the default pool. */
+       if (!bits && !IXGBE_READ_REG(hw, IXGBE_VLVFB(word ^ 1))) {
+               if (!(adapter->flags2 & IXGBE_FLAG2_VLAN_PROMISC))
+                       IXGBE_WRITE_REG(hw, IXGBE_VLVFB(word), 0);
+               IXGBE_WRITE_REG(hw, IXGBE_VLVF(idx), 0);
+       }
+}
+
 static int ixgbe_vlan_rx_kill_vid(struct net_device *netdev,
                                  __be16 proto, u16 vid)
 {
@@ -3915,7 +3959,11 @@ static int ixgbe_vlan_rx_kill_vid(struct net_device *netdev,
        struct ixgbe_hw *hw = &adapter->hw;
 
        /* remove VID from filter table */
-       hw->mac.ops.set_vfta(&adapter->hw, vid, VMDQ_P(0), false, true);
+       if (adapter->flags2 & IXGBE_FLAG2_VLAN_PROMISC)
+               ixgbe_update_pf_promisc_vlvf(adapter, vid);
+       else
+               hw->mac.ops.set_vfta(hw, vid, VMDQ_P(0), false, true);
+
        clear_bit(vid, adapter->active_vlans);
 
        return 0;
index 3380f14517dc6a7e2e5bd678cff195a7bc728141..03d4e5c9d71de79c7a8facef26e596fd5f88f819 100644 (file)
@@ -472,6 +472,17 @@ static int ixgbe_set_vf_vlan(struct ixgbe_adapter *adapter, int add, int vid,
 
        err = hw->mac.ops.set_vfta(hw, vid, vf, !!add, false);
 
+       if (add && !err)
+               return err;
+
+       /* If we failed to add the VF VLAN or we are removing the VF VLAN
+        * we may need to drop the PF pool bit in order to allow us to free
+        * up the VLVF resources.
+        */
+       if (test_bit(vid, adapter->active_vlans) ||
+           (adapter->flags2 & IXGBE_FLAG2_VLAN_PROMISC))
+               ixgbe_update_pf_promisc_vlvf(adapter, vid);
+
        return err;
 }
 
@@ -830,40 +841,14 @@ static int ixgbe_set_vf_mac_addr(struct ixgbe_adapter *adapter,
        return ixgbe_set_vf_mac(adapter, vf, new_mac) < 0;
 }
 
-static int ixgbe_find_vlvf_entry(struct ixgbe_hw *hw, u32 vlan)
-{
-       u32 vlvf;
-       s32 regindex;
-
-       /* short cut the special case */
-       if (vlan == 0)
-               return 0;
-
-       /* Search for the vlan id in the VLVF entries */
-       for (regindex = 1; regindex < IXGBE_VLVF_ENTRIES; regindex++) {
-               vlvf = IXGBE_READ_REG(hw, IXGBE_VLVF(regindex));
-               if ((vlvf & VLAN_VID_MASK) == vlan)
-                       break;
-       }
-
-       /* Return a negative value if not found */
-       if (regindex >= IXGBE_VLVF_ENTRIES)
-               regindex = -1;
-
-       return regindex;
-}
-
 static int ixgbe_set_vf_vlan_msg(struct ixgbe_adapter *adapter,
                                 u32 *msgbuf, u32 vf)
 {
+       u32 add = (msgbuf[0] & IXGBE_VT_MSGINFO_MASK) >> IXGBE_VT_MSGINFO_SHIFT;
+       u32 vid = (msgbuf[1] & IXGBE_VLVF_VLANID_MASK);
+       u8 tcs = netdev_get_num_tc(adapter->netdev);
        struct ixgbe_hw *hw = &adapter->hw;
-       int add = (msgbuf[0] & IXGBE_VT_MSGINFO_MASK) >> IXGBE_VT_MSGINFO_SHIFT;
-       int vid = (msgbuf[1] & IXGBE_VLVF_VLANID_MASK);
        int err;
-       s32 reg_ndx;
-       u32 vlvf;
-       u32 bits;
-       u8 tcs = netdev_get_num_tc(adapter->netdev);
 
        if (adapter->vfinfo[vf].pf_vlan || tcs) {
                e_warn(drv,
@@ -873,54 +858,19 @@ static int ixgbe_set_vf_vlan_msg(struct ixgbe_adapter *adapter,
                return -1;
        }
 
+       err = ixgbe_set_vf_vlan(adapter, add, vid, vf);
+       if (err)
+               return err;
+
+       if (adapter->vfinfo[vf].spoofchk_enabled)
+               hw->mac.ops.set_vlan_anti_spoofing(hw, true, vf);
+
        if (add)
                adapter->vfinfo[vf].vlan_count++;
        else if (adapter->vfinfo[vf].vlan_count)
                adapter->vfinfo[vf].vlan_count--;
 
-       /* in case of promiscuous mode any VLAN filter set for a VF must
-        * also have the PF pool added to it.
-        */
-       if (add && adapter->netdev->flags & IFF_PROMISC)
-               err = ixgbe_set_vf_vlan(adapter, add, vid, VMDQ_P(0));
-
-       err = ixgbe_set_vf_vlan(adapter, add, vid, vf);
-       if (!err && adapter->vfinfo[vf].spoofchk_enabled)
-               hw->mac.ops.set_vlan_anti_spoofing(hw, true, vf);
-
-       /* Go through all the checks to see if the VLAN filter should
-        * be wiped completely.
-        */
-       if (!add && adapter->netdev->flags & IFF_PROMISC) {
-               reg_ndx = ixgbe_find_vlvf_entry(hw, vid);
-               if (reg_ndx < 0)
-                       return err;
-               vlvf = IXGBE_READ_REG(hw, IXGBE_VLVF(reg_ndx));
-               /* See if any other pools are set for this VLAN filter
-                * entry other than the PF.
-                */
-               if (VMDQ_P(0) < 32) {
-                       bits = IXGBE_READ_REG(hw, IXGBE_VLVFB(reg_ndx * 2));
-                       bits &= ~(1 << VMDQ_P(0));
-                       bits |= IXGBE_READ_REG(hw,
-                                              IXGBE_VLVFB(reg_ndx * 2 + 1));
-               } else {
-                       bits = IXGBE_READ_REG(hw,
-                                             IXGBE_VLVFB(reg_ndx * 2 + 1));
-                       bits &= ~(1 << (VMDQ_P(0) - 32));
-                       bits |= IXGBE_READ_REG(hw, IXGBE_VLVFB(reg_ndx * 2));
-               }
-
-               /* If the filter was removed then ensure PF pool bit
-                * is cleared if the PF only added itself to the pool
-                * because the PF is in promiscuous mode.
-                */
-               if ((vlvf & VLAN_VID_MASK) == vid &&
-                   !test_bit(vid, adapter->active_vlans) && !bits)
-                       ixgbe_set_vf_vlan(adapter, add, vid, VMDQ_P(0));
-       }
-
-       return err;
+       return 0;
 }
 
 static int ixgbe_set_vf_macvlan_msg(struct ixgbe_adapter *adapter,