Commit af7251d4 authored by Alexander Duyck's avatar Alexander Duyck Committed by Tim Gardner

igb: Clean-up configuration of VF port VLANs

BugLink: http://bugs.launchpad.net/bugs/1547674

This patch is meant to clean-up the configuration of the VF port based VLAN
configuration.  The original logic was a bit muddled and had some
undesirable side effects such as VLANs being either completely stripped
from the port or VLANs being left when they shouldn't be.  The idea behind
this code is to avoid any events such as spurious spoof notifications when
we are removing one VLAN tag and replacing it with another.
Signed-off-by: default avatarAlexander Duyck <aduyck@mirantis.com>
Tested-by: default avatarAaron Brown <aaron.f.brown@intel.com>
Signed-off-by: default avatarJeff Kirsher <jeffrey.t.kirsher@intel.com>
(cherry picked from net-next commit a15d9259)
Signed-off-by: default avatarTim Gardner <tim.gardner@canonical.com>
parent 430f418b
......@@ -5786,53 +5786,6 @@ static void igb_clear_vf_vfta(struct igb_adapter *adapter, u32 vf)
}
}
static void igb_set_vmvir(struct igb_adapter *adapter, u32 vid, u32 vf)
{
struct e1000_hw *hw = &adapter->hw;
if (vid)
wr32(E1000_VMVIR(vf), (vid | E1000_VMVIR_VLANA_DEFAULT));
else
wr32(E1000_VMVIR(vf), 0);
}
static int igb_ndo_set_vf_vlan(struct net_device *netdev,
int vf, u16 vlan, u8 qos)
{
struct igb_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
int err = 0;
if ((vf >= adapter->vfs_allocated_count) || (vlan > 4095) || (qos > 7))
return -EINVAL;
if (vlan || qos) {
err = igb_vfta_set(hw, vlan, vf, !!vlan, false);
if (err)
goto out;
igb_set_vmvir(adapter, vlan | (qos << VLAN_PRIO_SHIFT), vf);
igb_set_vmolr(adapter, vf, !vlan);
adapter->vf_data[vf].pf_vlan = vlan;
adapter->vf_data[vf].pf_qos = qos;
dev_info(&adapter->pdev->dev,
"Setting VLAN %d, QOS 0x%x on VF %d\n", vlan, qos, vf);
if (test_bit(__IGB_DOWN, &adapter->state)) {
dev_warn(&adapter->pdev->dev,
"The VF VLAN has been set, but the PF device is not up.\n");
dev_warn(&adapter->pdev->dev,
"Bring the PF device up before attempting to use the VF device.\n");
}
} else {
igb_vfta_set(hw, adapter->vf_data[vf].pf_vlan, vf,
false, false);
igb_set_vmvir(adapter, vlan, vf);
igb_set_vmolr(adapter, vf, true);
adapter->vf_data[vf].pf_vlan = 0;
adapter->vf_data[vf].pf_qos = 0;
}
out:
return err;
}
static int igb_find_vlvf_entry(struct igb_adapter *adapter, int vid)
{
struct e1000_hw *hw = &adapter->hw;
......@@ -5853,23 +5806,25 @@ static int igb_find_vlvf_entry(struct igb_adapter *adapter, int vid)
return i;
}
static int igb_set_vf_vlan(struct igb_adapter *adapter, u32 *msgbuf, u32 vf)
static s32 igb_set_vf_vlan(struct igb_adapter *adapter, u32 vid,
bool add, u32 vf)
{
int pf_id = adapter->vfs_allocated_count;
struct e1000_hw *hw = &adapter->hw;
int add = (msgbuf[0] & E1000_VT_MSGINFO_MASK) >> E1000_VT_MSGINFO_SHIFT;
int vid = (msgbuf[1] & E1000_VLVF_VLANID_MASK);
int err = 0;
int err;
/* If in promiscuous mode we need to make sure the PF also has
* the VLAN filter set.
/* If VLAN overlaps with one the PF is currently monitoring make
* sure that we are able to allocate a VLVF entry. This may be
* redundant but it guarantees PF will maintain visibility to
* the VLAN.
*/
if (add && (adapter->netdev->flags & IFF_PROMISC))
err = igb_vfta_set(hw, vid, adapter->vfs_allocated_count,
true, false);
if (err)
goto out;
if (add && (adapter->netdev->flags & IFF_PROMISC)) {
err = igb_vfta_set(hw, vid, pf_id, true, false);
if (err)
return err;
}
err = igb_vfta_set(hw, vid, vf, !!add, false);
err = igb_vfta_set(hw, vid, vf, add, false);
if (err)
goto out;
......@@ -5904,23 +5859,107 @@ static int igb_set_vf_vlan(struct igb_adapter *adapter, u32 *msgbuf, u32 vf)
return err;
}
static inline void igb_vf_reset(struct igb_adapter *adapter, u32 vf)
static void igb_set_vmvir(struct igb_adapter *adapter, u32 vid, u32 vf)
{
/* clear flags - except flag that indicates PF has set the MAC */
adapter->vf_data[vf].flags &= IGB_VF_FLAG_PF_SET_MAC;
adapter->vf_data[vf].last_nack = jiffies;
struct e1000_hw *hw = &adapter->hw;
/* reset offloads to defaults */
if (vid)
wr32(E1000_VMVIR(vf), (vid | E1000_VMVIR_VLANA_DEFAULT));
else
wr32(E1000_VMVIR(vf), 0);
}
static int igb_enable_port_vlan(struct igb_adapter *adapter, int vf,
u16 vlan, u8 qos)
{
int err;
err = igb_set_vf_vlan(adapter, vlan, true, vf);
if (err)
return err;
igb_set_vmvir(adapter, vlan | (qos << VLAN_PRIO_SHIFT), vf);
igb_set_vmolr(adapter, vf, !vlan);
/* revoke access to previous VLAN */
if (vlan != adapter->vf_data[vf].pf_vlan)
igb_set_vf_vlan(adapter, adapter->vf_data[vf].pf_vlan,
false, vf);
adapter->vf_data[vf].pf_vlan = vlan;
adapter->vf_data[vf].pf_qos = qos;
dev_info(&adapter->pdev->dev,
"Setting VLAN %d, QOS 0x%x on VF %d\n", vlan, qos, vf);
if (test_bit(__IGB_DOWN, &adapter->state)) {
dev_warn(&adapter->pdev->dev,
"The VF VLAN has been set, but the PF device is not up.\n");
dev_warn(&adapter->pdev->dev,
"Bring the PF device up before attempting to use the VF device.\n");
}
return err;
}
static int igb_disable_port_vlan(struct igb_adapter *adapter, int vf)
{
/* Restore tagless access via VLAN 0 */
igb_set_vf_vlan(adapter, 0, true, vf);
igb_set_vmvir(adapter, 0, vf);
igb_set_vmolr(adapter, vf, true);
/* Remove any PF assigned VLAN */
if (adapter->vf_data[vf].pf_vlan)
igb_set_vf_vlan(adapter, adapter->vf_data[vf].pf_vlan,
false, vf);
adapter->vf_data[vf].pf_vlan = 0;
adapter->vf_data[vf].pf_qos = 0;
return 0;
}
static int igb_ndo_set_vf_vlan(struct net_device *netdev,
int vf, u16 vlan, u8 qos)
{
struct igb_adapter *adapter = netdev_priv(netdev);
if ((vf >= adapter->vfs_allocated_count) || (vlan > 4095) || (qos > 7))
return -EINVAL;
return (vlan || qos) ? igb_enable_port_vlan(adapter, vf, vlan, qos) :
igb_disable_port_vlan(adapter, vf);
}
static int igb_set_vf_vlan_msg(struct igb_adapter *adapter, u32 *msgbuf, u32 vf)
{
int add = (msgbuf[0] & E1000_VT_MSGINFO_MASK) >> E1000_VT_MSGINFO_SHIFT;
int vid = (msgbuf[1] & E1000_VLVF_VLANID_MASK);
if (adapter->vf_data[vf].pf_vlan)
return -1;
/* VLAN 0 is a special case, don't allow it to be removed */
if (!vid && !add)
return 0;
return igb_set_vf_vlan(adapter, vid, !!add, vf);
}
static inline void igb_vf_reset(struct igb_adapter *adapter, u32 vf)
{
struct vf_data_storage *vf_data = &adapter->vf_data[vf];
/* clear flags - except flag that indicates PF has set the MAC */
vf_data->flags &= IGB_VF_FLAG_PF_SET_MAC;
vf_data->last_nack = jiffies;
/* reset vlans for device */
igb_clear_vf_vfta(adapter, vf);
if (adapter->vf_data[vf].pf_vlan)
igb_ndo_set_vf_vlan(adapter->netdev, vf,
adapter->vf_data[vf].pf_vlan,
adapter->vf_data[vf].pf_qos);
else
igb_clear_vf_vfta(adapter, vf);
igb_set_vf_vlan(adapter, vf_data->pf_vlan, true, vf);
igb_set_vmvir(adapter, vf_data->pf_vlan |
(vf_data->pf_qos << VLAN_PRIO_SHIFT), vf);
igb_set_vmolr(adapter, vf, !vf_data->pf_vlan);
/* reset multicast table array for vf */
adapter->vf_data[vf].num_vf_mc_hashes = 0;
......@@ -6065,7 +6104,7 @@ static void igb_rcv_msg_from_vf(struct igb_adapter *adapter, u32 vf)
"VF %d attempted to override administratively set VLAN tag\nReload the VF driver to resume operations\n",
vf);
else
retval = igb_set_vf_vlan(adapter, msgbuf, vf);
retval = igb_set_vf_vlan_msg(adapter, msgbuf, vf);
break;
default:
dev_err(&pdev->dev, "Unhandled Msg %08x\n", msgbuf[0]);
......
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