diff options
author | Yury Kylulin <yury.kylulin@intel.com> | 2017-03-07 11:20:26 +0300 |
---|---|---|
committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2017-04-20 16:32:44 -0700 |
commit | 4827cc37796a02ece7097e01dad8e08f537ac815 (patch) | |
tree | 7c30187c0f626e54c8c09b6502949b24c272da97 /drivers/net/ethernet/intel/igbvf | |
parent | 83c21335c87622215f3daa59e670cf6467baa869 (diff) | |
download | linux-4827cc37796a02ece7097e01dad8e08f537ac815.tar.bz2 |
igb/igbvf: Add VF MAC filter request capabilities
Add functionality for the VF to request up to 3 additional MAC filters.
This is done using existing E1000_VF_SET_MAC_ADDR message, but with
additional message info - E1000_VF_MAC_FILTER_CLR to clear all unicast
MAC filters previously set for this VF and E1000_VF_MAC_FILTER_ADD to
add MAC filter.
Additional filters can be added only in case if administrator did not
set VF MAC explicitly and allowed to change default MAC to the VF.
Due to the limited number of RAR entries reserve at least 3 MAC filters
for the PF.
If SRIOV is supported by the NIC after this change RAR entries starting
from 1 to (RAR MAX ENTRIES - NUM SRIOV VFS) will be used for PF and VF
MAC filters.
Signed-off-by: Yury Kylulin <yury.kylulin@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Diffstat (limited to 'drivers/net/ethernet/intel/igbvf')
-rw-r--r-- | drivers/net/ethernet/intel/igbvf/igbvf.h | 2 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igbvf/mbx.h | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igbvf/netdev.c | 44 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igbvf/vf.c | 41 | ||||
-rw-r--r-- | drivers/net/ethernet/intel/igbvf/vf.h | 1 |
5 files changed, 90 insertions, 2 deletions
diff --git a/drivers/net/ethernet/intel/igbvf/igbvf.h b/drivers/net/ethernet/intel/igbvf/igbvf.h index 6f4290d6dc9f..2a53ed84d9fc 100644 --- a/drivers/net/ethernet/intel/igbvf/igbvf.h +++ b/drivers/net/ethernet/intel/igbvf/igbvf.h @@ -101,6 +101,8 @@ enum latency_range { #define IGBVF_MNG_VLAN_NONE (-1) +#define IGBVF_MAX_MAC_FILTERS 3 + /* Number of packet split data buffers (not including the header buffer) */ #define PS_PAGE_BUFFERS (MAX_PS_BUFFERS - 1) diff --git a/drivers/net/ethernet/intel/igbvf/mbx.h b/drivers/net/ethernet/intel/igbvf/mbx.h index f800bf8eedae..30d58c4a444e 100644 --- a/drivers/net/ethernet/intel/igbvf/mbx.h +++ b/drivers/net/ethernet/intel/igbvf/mbx.h @@ -62,6 +62,10 @@ #define E1000_VF_RESET 0x01 /* VF requests reset */ #define E1000_VF_SET_MAC_ADDR 0x02 /* VF requests PF to set MAC addr */ +/* VF requests PF to clear all unicast MAC filters */ +#define E1000_VF_MAC_FILTER_CLR (0x01 << E1000_VT_MSGINFO_SHIFT) +/* VF requests PF to add unicast MAC filter */ +#define E1000_VF_MAC_FILTER_ADD (0x02 << E1000_VT_MSGINFO_SHIFT) #define E1000_VF_SET_MULTICAST 0x03 /* VF requests PF to set MC addr */ #define E1000_VF_SET_VLAN 0x04 /* VF requests PF to set VLAN */ #define E1000_VF_SET_LPE 0x05 /* VF requests PF to set VMOLR.LPE */ diff --git a/drivers/net/ethernet/intel/igbvf/netdev.c b/drivers/net/ethernet/intel/igbvf/netdev.c index 839ba110f7fb..6029854b6a70 100644 --- a/drivers/net/ethernet/intel/igbvf/netdev.c +++ b/drivers/net/ethernet/intel/igbvf/netdev.c @@ -1433,12 +1433,52 @@ static void igbvf_set_multi(struct net_device *netdev) } /** + * igbvf_set_uni - Configure unicast MAC filters + * @netdev: network interface device structure + * + * This routine is responsible for configuring the hardware for proper + * unicast filters. + **/ +static int igbvf_set_uni(struct net_device *netdev) +{ + struct igbvf_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + + if (netdev_uc_count(netdev) > IGBVF_MAX_MAC_FILTERS) { + pr_err("Too many unicast filters - No Space\n"); + return -ENOSPC; + } + + /* Clear all unicast MAC filters */ + hw->mac.ops.set_uc_addr(hw, E1000_VF_MAC_FILTER_CLR, NULL); + + if (!netdev_uc_empty(netdev)) { + struct netdev_hw_addr *ha; + + /* Add MAC filters one by one */ + netdev_for_each_uc_addr(ha, netdev) { + hw->mac.ops.set_uc_addr(hw, E1000_VF_MAC_FILTER_ADD, + ha->addr); + udelay(200); + } + } + + return 0; +} + +static void igbvf_set_rx_mode(struct net_device *netdev) +{ + igbvf_set_multi(netdev); + igbvf_set_uni(netdev); +} + +/** * igbvf_configure - configure the hardware for Rx and Tx * @adapter: private board structure **/ static void igbvf_configure(struct igbvf_adapter *adapter) { - igbvf_set_multi(adapter->netdev); + igbvf_set_rx_mode(adapter->netdev); igbvf_restore_vlan(adapter); @@ -2636,7 +2676,7 @@ static const struct net_device_ops igbvf_netdev_ops = { .ndo_stop = igbvf_close, .ndo_start_xmit = igbvf_xmit_frame, .ndo_get_stats = igbvf_get_stats, - .ndo_set_rx_mode = igbvf_set_multi, + .ndo_set_rx_mode = igbvf_set_rx_mode, .ndo_set_mac_address = igbvf_set_mac, .ndo_change_mtu = igbvf_change_mtu, .ndo_do_ioctl = igbvf_ioctl, diff --git a/drivers/net/ethernet/intel/igbvf/vf.c b/drivers/net/ethernet/intel/igbvf/vf.c index 335ba6642145..528be116184e 100644 --- a/drivers/net/ethernet/intel/igbvf/vf.c +++ b/drivers/net/ethernet/intel/igbvf/vf.c @@ -36,6 +36,7 @@ static void e1000_update_mc_addr_list_vf(struct e1000_hw *hw, u8 *, u32, u32, u32); static void e1000_rar_set_vf(struct e1000_hw *, u8 *, u32); static s32 e1000_read_mac_addr_vf(struct e1000_hw *); +static s32 e1000_set_uc_addr_vf(struct e1000_hw *hw, u32 subcmd, u8 *addr); static s32 e1000_set_vfta_vf(struct e1000_hw *, u16, bool); /** @@ -66,6 +67,8 @@ static s32 e1000_init_mac_params_vf(struct e1000_hw *hw) mac->ops.rar_set = e1000_rar_set_vf; /* read mac address */ mac->ops.read_mac_addr = e1000_read_mac_addr_vf; + /* set mac filter */ + mac->ops.set_uc_addr = e1000_set_uc_addr_vf; /* set vlan filter table array */ mac->ops.set_vfta = e1000_set_vfta_vf; @@ -338,6 +341,44 @@ static s32 e1000_read_mac_addr_vf(struct e1000_hw *hw) } /** + * e1000_set_uc_addr_vf - Set or clear unicast filters + * @hw: pointer to the HW structure + * @sub_cmd: add or clear filters + * @addr: pointer to the filter MAC address + **/ +static s32 e1000_set_uc_addr_vf(struct e1000_hw *hw, u32 sub_cmd, u8 *addr) +{ + struct e1000_mbx_info *mbx = &hw->mbx; + u32 msgbuf[3], msgbuf_chk; + u8 *msg_addr = (u8 *)(&msgbuf[1]); + s32 ret_val; + + memset(msgbuf, 0, sizeof(msgbuf)); + msgbuf[0] |= sub_cmd; + msgbuf[0] |= E1000_VF_SET_MAC_ADDR; + msgbuf_chk = msgbuf[0]; + + if (addr) + memcpy(msg_addr, addr, ETH_ALEN); + + ret_val = mbx->ops.write_posted(hw, msgbuf, 3); + + if (!ret_val) + ret_val = mbx->ops.read_posted(hw, msgbuf, 3); + + msgbuf[0] &= ~E1000_VT_MSGTYPE_CTS; + + if (!ret_val) { + msgbuf[0] &= ~E1000_VT_MSGTYPE_CTS; + + if (msgbuf[0] == (msgbuf_chk | E1000_VT_MSGTYPE_NACK)) + return -ENOSPC; + } + + return ret_val; +} + +/** * e1000_check_for_link_vf - Check for link for a virtual interface * @hw: pointer to the HW structure * diff --git a/drivers/net/ethernet/intel/igbvf/vf.h b/drivers/net/ethernet/intel/igbvf/vf.h index f00a41d9a1ca..4cf78b0dec50 100644 --- a/drivers/net/ethernet/intel/igbvf/vf.h +++ b/drivers/net/ethernet/intel/igbvf/vf.h @@ -179,6 +179,7 @@ struct e1000_mac_operations { s32 (*get_bus_info)(struct e1000_hw *); s32 (*get_link_up_info)(struct e1000_hw *, u16 *, u16 *); void (*update_mc_addr_list)(struct e1000_hw *, u8 *, u32, u32, u32); + s32 (*set_uc_addr)(struct e1000_hw *, u32, u8 *); s32 (*reset_hw)(struct e1000_hw *); s32 (*init_hw)(struct e1000_hw *); s32 (*setup_link)(struct e1000_hw *); |