Commit 16369564 authored by Alexander Duyck's avatar Alexander Duyck Committed by Jeff Kirsher

ixgbe: Add support for VLAN promiscuous with SR-IOV

This patch adds support for VLAN promiscuous with SR-IOV enabled.

The code prior to this patch was only adding the PF to VLANs that the VF
had added.  As such enabling promiscuous mode would actually not add any
additional VLAN filters so visibility was limited.  This lead to a number
of issues as the bridge and OVS would expect us to accept all VLAN tagged
packets when promiscuous mode was enabled, and instead we would filter out
most if not all depending on the configuration of the PF.

With this patch what we do is set all the bits in the VFTA and all of the
VLVF bits associated with the pool belonging to the PF.  By doing this the
PF is guaranteed to receive all VLAN tagged traffic associated with the RAR
filters assigned to the PF.  In addition we will clean up those same bits
in the event of promiscuous mode being disabled.
Signed-off-by: default avatarAlexander Duyck <aduyck@mirantis.com>
Tested-by: default avatarPhil Schmitt <phillip.j.schmitt@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
parent c2bc9ce9
...@@ -664,6 +664,7 @@ struct ixgbe_adapter { ...@@ -664,6 +664,7 @@ struct ixgbe_adapter {
#ifdef CONFIG_IXGBE_VXLAN #ifdef CONFIG_IXGBE_VXLAN
#define IXGBE_FLAG2_VXLAN_REREG_NEEDED BIT(12) #define IXGBE_FLAG2_VXLAN_REREG_NEEDED BIT(12)
#endif #endif
#define IXGBE_FLAG2_VLAN_PROMISC BIT(13)
/* Tx fast path data */ /* Tx fast path data */
int num_tx_queues; int num_tx_queues;
......
...@@ -3702,6 +3702,9 @@ static void ixgbe_configure_virtualization(struct ixgbe_adapter *adapter) ...@@ -3702,6 +3702,9 @@ static void ixgbe_configure_virtualization(struct ixgbe_adapter *adapter)
/* Map PF MAC address in RAR Entry 0 to first pool following VFs */ /* Map PF MAC address in RAR Entry 0 to first pool following VFs */
hw->mac.ops.set_vmdq(hw, 0, VMDQ_P(0)); hw->mac.ops.set_vmdq(hw, 0, VMDQ_P(0));
/* clear VLAN promisc flag so VFTA will be updated if necessary */
adapter->flags2 &= ~IXGBE_FLAG2_VLAN_PROMISC;
/* /*
* Set up VF register offsets for selected VT Mode, * Set up VF register offsets for selected VT Mode,
* i.e. 32 or 64 VFs for SR-IOV * i.e. 32 or 64 VFs for SR-IOV
...@@ -3990,6 +3993,129 @@ static void ixgbe_vlan_strip_enable(struct ixgbe_adapter *adapter) ...@@ -3990,6 +3993,129 @@ static void ixgbe_vlan_strip_enable(struct ixgbe_adapter *adapter)
} }
} }
static void ixgbe_vlan_promisc_enable(struct ixgbe_adapter *adapter)
{
struct ixgbe_hw *hw = &adapter->hw;
u32 vlnctrl, i;
switch (hw->mac.type) {
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
case ixgbe_mac_X550:
case ixgbe_mac_X550EM_x:
default:
if (adapter->flags & IXGBE_FLAG_VMDQ_ENABLED)
break;
/* fall through */
case ixgbe_mac_82598EB:
/* legacy case, we can just disable VLAN filtering */
vlnctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
vlnctrl &= ~(IXGBE_VLNCTRL_VFE | IXGBE_VLNCTRL_CFIEN);
IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
return;
}
/* We are already in VLAN promisc, nothing to do */
if (adapter->flags2 & IXGBE_FLAG2_VLAN_PROMISC)
return;
/* Set flag so we don't redo unnecessary work */
adapter->flags2 |= IXGBE_FLAG2_VLAN_PROMISC;
/* Add PF to all active pools */
for (i = IXGBE_VLVF_ENTRIES; --i;) {
u32 reg_offset = IXGBE_VLVFB(i * 2 + VMDQ_P(0) / 32);
u32 vlvfb = IXGBE_READ_REG(hw, reg_offset);
vlvfb |= 1 << (VMDQ_P(0) % 32);
IXGBE_WRITE_REG(hw, reg_offset, vlvfb);
}
/* Set all bits in the VLAN filter table array */
for (i = hw->mac.vft_size; i--;)
IXGBE_WRITE_REG(hw, IXGBE_VFTA(i), ~0U);
}
#define VFTA_BLOCK_SIZE 8
static void ixgbe_scrub_vfta(struct ixgbe_adapter *adapter, u32 vfta_offset)
{
struct ixgbe_hw *hw = &adapter->hw;
u32 vfta[VFTA_BLOCK_SIZE] = { 0 };
u32 vid_start = vfta_offset * 32;
u32 vid_end = vid_start + (VFTA_BLOCK_SIZE * 32);
u32 i, vid, word, bits;
for (i = IXGBE_VLVF_ENTRIES; --i;) {
u32 vlvf = IXGBE_READ_REG(hw, IXGBE_VLVF(i));
/* pull VLAN ID from VLVF */
vid = vlvf & VLAN_VID_MASK;
/* only concern outselves with a certain range */
if (vid < vid_start || vid >= vid_end)
continue;
if (vlvf) {
/* record VLAN ID in VFTA */
vfta[(vid - vid_start) / 32] |= 1 << (vid % 32);
/* if PF is part of this then continue */
if (test_bit(vid, adapter->active_vlans))
continue;
}
/* remove PF from the pool */
word = i * 2 + VMDQ_P(0) / 32;
bits = ~(1 << (VMDQ_P(0) % 32));
bits &= IXGBE_READ_REG(hw, IXGBE_VLVFB(word));
IXGBE_WRITE_REG(hw, IXGBE_VLVFB(word), bits);
}
/* extract values from active_vlans and write back to VFTA */
for (i = VFTA_BLOCK_SIZE; i--;) {
vid = (vfta_offset + i) * 32;
word = vid / BITS_PER_LONG;
bits = vid % BITS_PER_LONG;
vfta[i] |= adapter->active_vlans[word] >> bits;
IXGBE_WRITE_REG(hw, IXGBE_VFTA(vfta_offset + i), vfta[i]);
}
}
static void ixgbe_vlan_promisc_disable(struct ixgbe_adapter *adapter)
{
struct ixgbe_hw *hw = &adapter->hw;
u32 vlnctrl, i;
switch (hw->mac.type) {
case ixgbe_mac_82599EB:
case ixgbe_mac_X540:
case ixgbe_mac_X550:
case ixgbe_mac_X550EM_x:
default:
if (adapter->flags & IXGBE_FLAG_VMDQ_ENABLED)
break;
/* fall through */
case ixgbe_mac_82598EB:
vlnctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
vlnctrl &= ~IXGBE_VLNCTRL_CFIEN;
vlnctrl |= IXGBE_VLNCTRL_VFE;
IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
return;
}
/* We are not in VLAN promisc, nothing to do */
if (!(adapter->flags2 & IXGBE_FLAG2_VLAN_PROMISC))
return;
/* Set flag so we don't redo unnecessary work */
adapter->flags2 &= ~IXGBE_FLAG2_VLAN_PROMISC;
for (i = 0; i < hw->mac.vft_size; i += VFTA_BLOCK_SIZE)
ixgbe_scrub_vfta(adapter, i);
}
static void ixgbe_restore_vlan(struct ixgbe_adapter *adapter) static void ixgbe_restore_vlan(struct ixgbe_adapter *adapter)
{ {
u16 vid; u16 vid;
...@@ -4246,12 +4372,10 @@ void ixgbe_set_rx_mode(struct net_device *netdev) ...@@ -4246,12 +4372,10 @@ void ixgbe_set_rx_mode(struct net_device *netdev)
struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_adapter *adapter = netdev_priv(netdev);
struct ixgbe_hw *hw = &adapter->hw; struct ixgbe_hw *hw = &adapter->hw;
u32 fctrl, vmolr = IXGBE_VMOLR_BAM | IXGBE_VMOLR_AUPE; u32 fctrl, vmolr = IXGBE_VMOLR_BAM | IXGBE_VMOLR_AUPE;
u32 vlnctrl;
int count; int count;
/* Check for Promiscuous and All Multicast modes */ /* Check for Promiscuous and All Multicast modes */
fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL); fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
vlnctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
/* set all bits that we expect to always be set */ /* set all bits that we expect to always be set */
fctrl &= ~IXGBE_FCTRL_SBP; /* disable store-bad-packets */ fctrl &= ~IXGBE_FCTRL_SBP; /* disable store-bad-packets */
...@@ -4261,25 +4385,18 @@ void ixgbe_set_rx_mode(struct net_device *netdev) ...@@ -4261,25 +4385,18 @@ void ixgbe_set_rx_mode(struct net_device *netdev)
/* clear the bits we are changing the status of */ /* clear the bits we are changing the status of */
fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
vlnctrl &= ~(IXGBE_VLNCTRL_VFE | IXGBE_VLNCTRL_CFIEN);
if (netdev->flags & IFF_PROMISC) { if (netdev->flags & IFF_PROMISC) {
hw->addr_ctrl.user_set_promisc = true; hw->addr_ctrl.user_set_promisc = true;
fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE); fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
vmolr |= IXGBE_VMOLR_MPE; vmolr |= IXGBE_VMOLR_MPE;
/* Only disable hardware filter vlans in promiscuous mode ixgbe_vlan_promisc_enable(adapter);
* if SR-IOV and VMDQ are disabled - otherwise ensure
* that hardware VLAN filters remain enabled.
*/
if (adapter->flags & (IXGBE_FLAG_VMDQ_ENABLED |
IXGBE_FLAG_SRIOV_ENABLED))
vlnctrl |= (IXGBE_VLNCTRL_VFE | IXGBE_VLNCTRL_CFIEN);
} else { } else {
if (netdev->flags & IFF_ALLMULTI) { if (netdev->flags & IFF_ALLMULTI) {
fctrl |= IXGBE_FCTRL_MPE; fctrl |= IXGBE_FCTRL_MPE;
vmolr |= IXGBE_VMOLR_MPE; vmolr |= IXGBE_VMOLR_MPE;
} }
vlnctrl |= IXGBE_VLNCTRL_VFE;
hw->addr_ctrl.user_set_promisc = false; hw->addr_ctrl.user_set_promisc = false;
ixgbe_vlan_promisc_disable(adapter);
} }
/* /*
...@@ -4323,7 +4440,6 @@ void ixgbe_set_rx_mode(struct net_device *netdev) ...@@ -4323,7 +4440,6 @@ void ixgbe_set_rx_mode(struct net_device *netdev)
/* NOTE: VLAN filtering is disabled by setting PROMISC */ /* NOTE: VLAN filtering is disabled by setting PROMISC */
} }
IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl); IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl);
if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment