Commit 278e7d0b authored by Jacob Keller's avatar Jacob Keller Committed by Jeff Kirsher

i40e: store MAC/VLAN filters in a hash with the MAC Address as key

Replace the mac_filter_list with a static size hash table of 8bits. The
primary advantage of this is a decrease in latency of operations related
to searching for specific MAC filters, including .set_rx_mode. Using
a linked list resulted in several locations which were O(n^2). Using
a hash table should give us latency growth closer to O(n*log(n)).

Change-ID: I5330bd04053b880e670210933e35830b95948ebb
Signed-off-by: default avatarJacob Keller <jacob.e.keller@intel.com>
Tested-by: default avatarAndrew Bowers <andrewx.bowers@intel.com>
parent 290d2557
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include <linux/iommu.h> #include <linux/iommu.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/hashtable.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/in.h> #include <linux/in.h>
#include <linux/ip.h> #include <linux/ip.h>
...@@ -445,6 +446,20 @@ struct i40e_pf { ...@@ -445,6 +446,20 @@ struct i40e_pf {
u16 phy_led_val; u16 phy_led_val;
}; };
/**
* i40e_mac_to_hkey - Convert a 6-byte MAC Address to a u64 hash key
* @macaddr: the MAC Address as the base key
*
* Simply copies the address and returns it as a u64 for hashing
**/
static inline u64 i40e_addr_to_hkey(const u8 *macaddr)
{
u64 key = 0;
ether_addr_copy((u8 *)&key, macaddr);
return key;
}
enum i40e_filter_state { enum i40e_filter_state {
I40E_FILTER_INVALID = 0, /* Invalid state */ I40E_FILTER_INVALID = 0, /* Invalid state */
I40E_FILTER_NEW, /* New, not sent to FW yet */ I40E_FILTER_NEW, /* New, not sent to FW yet */
...@@ -454,7 +469,7 @@ enum i40e_filter_state { ...@@ -454,7 +469,7 @@ enum i40e_filter_state {
/* There is no 'removed' state; the filter struct is freed */ /* There is no 'removed' state; the filter struct is freed */
}; };
struct i40e_mac_filter { struct i40e_mac_filter {
struct list_head list; struct hlist_node hlist;
u8 macaddr[ETH_ALEN]; u8 macaddr[ETH_ALEN];
#define I40E_VLAN_ANY -1 #define I40E_VLAN_ANY -1
s16 vlan; s16 vlan;
...@@ -498,9 +513,10 @@ struct i40e_vsi { ...@@ -498,9 +513,10 @@ struct i40e_vsi {
#define I40E_VSI_FLAG_VEB_OWNER BIT(1) #define I40E_VSI_FLAG_VEB_OWNER BIT(1)
unsigned long flags; unsigned long flags;
/* Per VSI lock to protect elements/list (MAC filter) */ /* Per VSI lock to protect elements/hash (MAC filter) */
spinlock_t mac_filter_list_lock; spinlock_t mac_filter_hash_lock;
struct list_head mac_filter_list; /* Fixed size hash table with 2^8 buckets for MAC filters */
DECLARE_HASHTABLE(mac_filter_hash, 8);
/* VSI stats */ /* VSI stats */
struct rtnl_link_stats64 net_stats; struct rtnl_link_stats64 net_stats;
......
...@@ -134,7 +134,7 @@ static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid) ...@@ -134,7 +134,7 @@ static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid)
struct rtnl_link_stats64 *nstat; struct rtnl_link_stats64 *nstat;
struct i40e_mac_filter *f; struct i40e_mac_filter *f;
struct i40e_vsi *vsi; struct i40e_vsi *vsi;
int i; int i, bkt;
vsi = i40e_dbg_find_vsi(pf, seid); vsi = i40e_dbg_find_vsi(pf, seid);
if (!vsi) { if (!vsi) {
...@@ -166,7 +166,7 @@ static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid) ...@@ -166,7 +166,7 @@ static void i40e_dbg_dump_vsi_seid(struct i40e_pf *pf, int seid)
pf->hw.mac.addr, pf->hw.mac.addr,
pf->hw.mac.san_addr, pf->hw.mac.san_addr,
pf->hw.mac.port_addr); pf->hw.mac.port_addr);
list_for_each_entry(f, &vsi->mac_filter_list, list) { hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) {
dev_info(&pf->pdev->dev, dev_info(&pf->pdev->dev,
" mac_filter_hash: %pM vid=%d, state %s\n", " mac_filter_hash: %pM vid=%d, state %s\n",
f->macaddr, f->vlan, f->macaddr, f->vlan,
......
...@@ -1522,12 +1522,12 @@ void i40e_fcoe_config_netdev(struct net_device *netdev, struct i40e_vsi *vsi) ...@@ -1522,12 +1522,12 @@ void i40e_fcoe_config_netdev(struct net_device *netdev, struct i40e_vsi *vsi)
* same PCI function. * same PCI function.
*/ */
netdev->dev_port = 1; netdev->dev_port = 1;
spin_lock_bh(&vsi->mac_filter_list_lock); spin_lock_bh(&vsi->mac_filter_hash_lock);
i40e_add_filter(vsi, hw->mac.san_addr, 0); i40e_add_filter(vsi, hw->mac.san_addr, 0);
i40e_add_filter(vsi, (u8[6]) FC_FCOE_FLOGI_MAC, 0); i40e_add_filter(vsi, (u8[6]) FC_FCOE_FLOGI_MAC, 0);
i40e_add_filter(vsi, FIP_ALL_FCOE_MACS, 0); i40e_add_filter(vsi, FIP_ALL_FCOE_MACS, 0);
i40e_add_filter(vsi, FIP_ALL_ENODE_MACS, 0); i40e_add_filter(vsi, FIP_ALL_ENODE_MACS, 0);
spin_unlock_bh(&vsi->mac_filter_list_lock); spin_unlock_bh(&vsi->mac_filter_hash_lock);
/* use san mac */ /* use san mac */
ether_addr_copy(netdev->dev_addr, hw->mac.san_addr); ether_addr_copy(netdev->dev_addr, hw->mac.san_addr);
......
...@@ -1152,11 +1152,13 @@ static struct i40e_mac_filter *i40e_find_filter(struct i40e_vsi *vsi, ...@@ -1152,11 +1152,13 @@ static struct i40e_mac_filter *i40e_find_filter(struct i40e_vsi *vsi,
const u8 *macaddr, s16 vlan) const u8 *macaddr, s16 vlan)
{ {
struct i40e_mac_filter *f; struct i40e_mac_filter *f;
u64 key;
if (!vsi || !macaddr) if (!vsi || !macaddr)
return NULL; return NULL;
list_for_each_entry(f, &vsi->mac_filter_list, list) { key = i40e_addr_to_hkey(macaddr);
hash_for_each_possible(vsi->mac_filter_hash, f, hlist, key) {
if ((ether_addr_equal(macaddr, f->macaddr)) && if ((ether_addr_equal(macaddr, f->macaddr)) &&
(vlan == f->vlan)) (vlan == f->vlan))
return f; return f;
...@@ -1175,11 +1177,13 @@ static struct i40e_mac_filter *i40e_find_filter(struct i40e_vsi *vsi, ...@@ -1175,11 +1177,13 @@ static struct i40e_mac_filter *i40e_find_filter(struct i40e_vsi *vsi,
struct i40e_mac_filter *i40e_find_mac(struct i40e_vsi *vsi, const u8 *macaddr) struct i40e_mac_filter *i40e_find_mac(struct i40e_vsi *vsi, const u8 *macaddr)
{ {
struct i40e_mac_filter *f; struct i40e_mac_filter *f;
u64 key;
if (!vsi || !macaddr) if (!vsi || !macaddr)
return NULL; return NULL;
list_for_each_entry(f, &vsi->mac_filter_list, list) { key = i40e_addr_to_hkey(macaddr);
hash_for_each_possible(vsi->mac_filter_hash, f, hlist, key) {
if ((ether_addr_equal(macaddr, f->macaddr))) if ((ether_addr_equal(macaddr, f->macaddr)))
return f; return f;
} }
...@@ -1195,11 +1199,13 @@ struct i40e_mac_filter *i40e_find_mac(struct i40e_vsi *vsi, const u8 *macaddr) ...@@ -1195,11 +1199,13 @@ struct i40e_mac_filter *i40e_find_mac(struct i40e_vsi *vsi, const u8 *macaddr)
bool i40e_is_vsi_in_vlan(struct i40e_vsi *vsi) bool i40e_is_vsi_in_vlan(struct i40e_vsi *vsi)
{ {
struct i40e_mac_filter *f; struct i40e_mac_filter *f;
struct hlist_node *h;
int bkt;
/* Only -1 for all the filters denotes not in vlan mode /* Only -1 for all the filters denotes not in vlan mode
* so we have to go through all the list in order to make sure * so we have to go through all the list in order to make sure
*/ */
list_for_each_entry(f, &vsi->mac_filter_list, list) { hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist) {
if (f->vlan >= 0 || vsi->info.pvid) if (f->vlan >= 0 || vsi->info.pvid)
return true; return true;
} }
...@@ -1215,13 +1221,14 @@ bool i40e_is_vsi_in_vlan(struct i40e_vsi *vsi) ...@@ -1215,13 +1221,14 @@ bool i40e_is_vsi_in_vlan(struct i40e_vsi *vsi)
* *
* Returns ptr to the filter object or NULL when no memory available. * Returns ptr to the filter object or NULL when no memory available.
* *
* NOTE: This function is expected to be called with mac_filter_list_lock * NOTE: This function is expected to be called with mac_filter_hash_lock
* being held. * being held.
**/ **/
struct i40e_mac_filter *i40e_add_filter(struct i40e_vsi *vsi, struct i40e_mac_filter *i40e_add_filter(struct i40e_vsi *vsi,
const u8 *macaddr, s16 vlan) const u8 *macaddr, s16 vlan)
{ {
struct i40e_mac_filter *f; struct i40e_mac_filter *f;
u64 key;
if (!vsi || !macaddr) if (!vsi || !macaddr)
return NULL; return NULL;
...@@ -1249,8 +1256,10 @@ struct i40e_mac_filter *i40e_add_filter(struct i40e_vsi *vsi, ...@@ -1249,8 +1256,10 @@ struct i40e_mac_filter *i40e_add_filter(struct i40e_vsi *vsi,
f->state = I40E_FILTER_FAILED; f->state = I40E_FILTER_FAILED;
else else
f->state = I40E_FILTER_NEW; f->state = I40E_FILTER_NEW;
INIT_LIST_HEAD(&f->list); INIT_HLIST_NODE(&f->hlist);
list_add_tail(&f->list, &vsi->mac_filter_list);
key = i40e_addr_to_hkey(macaddr);
hash_add(vsi->mac_filter_hash, &f->hlist, key);
vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED; vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED;
vsi->back->flags |= I40E_FLAG_FILTER_SYNC; vsi->back->flags |= I40E_FLAG_FILTER_SYNC;
...@@ -1279,7 +1288,7 @@ struct i40e_mac_filter *i40e_add_filter(struct i40e_vsi *vsi, ...@@ -1279,7 +1288,7 @@ struct i40e_mac_filter *i40e_add_filter(struct i40e_vsi *vsi,
* the exact filter you will remove already, such as via i40e_find_filter or * the exact filter you will remove already, such as via i40e_find_filter or
* i40e_find_mac. * i40e_find_mac.
* *
* NOTE: This function is expected to be called with mac_filter_list_lock * NOTE: This function is expected to be called with mac_filter_hash_lock
* being held. * being held.
* ANOTHER NOTE: This function MUST be called from within the context of * ANOTHER NOTE: This function MUST be called from within the context of
* the "safe" variants of any list iterators, e.g. list_for_each_entry_safe() * the "safe" variants of any list iterators, e.g. list_for_each_entry_safe()
...@@ -1295,7 +1304,7 @@ static void __i40e_del_filter(struct i40e_vsi *vsi, struct i40e_mac_filter *f) ...@@ -1295,7 +1304,7 @@ static void __i40e_del_filter(struct i40e_vsi *vsi, struct i40e_mac_filter *f)
/* this one never got added by the FW. Just remove it, /* this one never got added by the FW. Just remove it,
* no need to sync anything. * no need to sync anything.
*/ */
list_del(&f->list); hash_del(&f->hlist);
kfree(f); kfree(f);
} else { } else {
f->state = I40E_FILTER_REMOVE; f->state = I40E_FILTER_REMOVE;
...@@ -1310,7 +1319,7 @@ static void __i40e_del_filter(struct i40e_vsi *vsi, struct i40e_mac_filter *f) ...@@ -1310,7 +1319,7 @@ static void __i40e_del_filter(struct i40e_vsi *vsi, struct i40e_mac_filter *f)
* @macaddr: the MAC address * @macaddr: the MAC address
* @vlan: the VLAN * @vlan: the VLAN
* *
* NOTE: This function is expected to be called with mac_filter_list_lock * NOTE: This function is expected to be called with mac_filter_hash_lock
* being held. * being held.
* ANOTHER NOTE: This function MUST be called from within the context of * ANOTHER NOTE: This function MUST be called from within the context of
* the "safe" variants of any list iterators, e.g. list_for_each_entry_safe() * the "safe" variants of any list iterators, e.g. list_for_each_entry_safe()
...@@ -1342,12 +1351,14 @@ struct i40e_mac_filter *i40e_put_mac_in_vlan(struct i40e_vsi *vsi, ...@@ -1342,12 +1351,14 @@ struct i40e_mac_filter *i40e_put_mac_in_vlan(struct i40e_vsi *vsi,
const u8 *macaddr) const u8 *macaddr)
{ {
struct i40e_mac_filter *f, *add = NULL; struct i40e_mac_filter *f, *add = NULL;
struct hlist_node *h;
int bkt;
if (vsi->info.pvid) if (vsi->info.pvid)
return i40e_add_filter(vsi, macaddr, return i40e_add_filter(vsi, macaddr,
le16_to_cpu(vsi->info.pvid)); le16_to_cpu(vsi->info.pvid));
list_for_each_entry(f, &vsi->mac_filter_list, list) { hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist) {
if (f->state == I40E_FILTER_REMOVE) if (f->state == I40E_FILTER_REMOVE)
continue; continue;
add = i40e_add_filter(vsi, macaddr, f->vlan); add = i40e_add_filter(vsi, macaddr, f->vlan);
...@@ -1369,12 +1380,14 @@ struct i40e_mac_filter *i40e_put_mac_in_vlan(struct i40e_vsi *vsi, ...@@ -1369,12 +1380,14 @@ struct i40e_mac_filter *i40e_put_mac_in_vlan(struct i40e_vsi *vsi,
**/ **/
int i40e_del_mac_all_vlan(struct i40e_vsi *vsi, const u8 *macaddr) int i40e_del_mac_all_vlan(struct i40e_vsi *vsi, const u8 *macaddr)
{ {
struct i40e_mac_filter *f, *ftmp; struct i40e_mac_filter *f;
struct hlist_node *h;
bool found = false; bool found = false;
int bkt;
WARN(!spin_is_locked(&vsi->mac_filter_list_lock), WARN(!spin_is_locked(&vsi->mac_filter_hash_lock),
"Missing mac_filter_list_lock\n"); "Missing mac_filter_hash_lock\n");
list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list) { hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist) {
if (ether_addr_equal(macaddr, f->macaddr)) { if (ether_addr_equal(macaddr, f->macaddr)) {
__i40e_del_filter(vsi, f); __i40e_del_filter(vsi, f);
found = true; found = true;
...@@ -1425,10 +1438,10 @@ static int i40e_set_mac(struct net_device *netdev, void *p) ...@@ -1425,10 +1438,10 @@ static int i40e_set_mac(struct net_device *netdev, void *p)
else else
netdev_info(netdev, "set new mac address %pM\n", addr->sa_data); netdev_info(netdev, "set new mac address %pM\n", addr->sa_data);
spin_lock_bh(&vsi->mac_filter_list_lock); spin_lock_bh(&vsi->mac_filter_hash_lock);
i40e_del_mac_all_vlan(vsi, netdev->dev_addr); i40e_del_mac_all_vlan(vsi, netdev->dev_addr);
i40e_put_mac_in_vlan(vsi, addr->sa_data); i40e_put_mac_in_vlan(vsi, addr->sa_data);
spin_unlock_bh(&vsi->mac_filter_list_lock); spin_unlock_bh(&vsi->mac_filter_hash_lock);
ether_addr_copy(netdev->dev_addr, addr->sa_data); ether_addr_copy(netdev->dev_addr, addr->sa_data);
if (vsi->type == I40E_VSI_MAIN) { if (vsi->type == I40E_VSI_MAIN) {
i40e_status ret; i40e_status ret;
...@@ -1650,12 +1663,12 @@ static void i40e_set_rx_mode(struct net_device *netdev) ...@@ -1650,12 +1663,12 @@ static void i40e_set_rx_mode(struct net_device *netdev)
struct i40e_netdev_priv *np = netdev_priv(netdev); struct i40e_netdev_priv *np = netdev_priv(netdev);
struct i40e_vsi *vsi = np->vsi; struct i40e_vsi *vsi = np->vsi;
spin_lock_bh(&vsi->mac_filter_list_lock); spin_lock_bh(&vsi->mac_filter_hash_lock);
__dev_uc_sync(netdev, i40e_addr_sync, i40e_addr_unsync); __dev_uc_sync(netdev, i40e_addr_sync, i40e_addr_unsync);
__dev_mc_sync(netdev, i40e_addr_sync, i40e_addr_unsync); __dev_mc_sync(netdev, i40e_addr_sync, i40e_addr_unsync);
spin_unlock_bh(&vsi->mac_filter_list_lock); spin_unlock_bh(&vsi->mac_filter_hash_lock);
/* check for other flag changes */ /* check for other flag changes */
if (vsi->current_netdev_flags != vsi->netdev->flags) { if (vsi->current_netdev_flags != vsi->netdev->flags) {
...@@ -1678,13 +1691,17 @@ static void i40e_set_rx_mode(struct net_device *netdev) ...@@ -1678,13 +1691,17 @@ static void i40e_set_rx_mode(struct net_device *netdev)
* MAC filter entries from list were slated to be removed from device. * MAC filter entries from list were slated to be removed from device.
**/ **/
static void i40e_undo_del_filter_entries(struct i40e_vsi *vsi, static void i40e_undo_del_filter_entries(struct i40e_vsi *vsi,
struct list_head *from) struct hlist_head *from)
{ {
struct i40e_mac_filter *f, *ftmp; struct i40e_mac_filter *f;
struct hlist_node *h;
hlist_for_each_entry_safe(f, h, from, hlist) {
u64 key = i40e_addr_to_hkey(f->macaddr);
list_for_each_entry_safe(f, ftmp, from, list) {
/* Move the element back into MAC filter list*/ /* Move the element back into MAC filter list*/
list_move_tail(&f->list, &vsi->mac_filter_list); hlist_del(&f->hlist);
hash_add(vsi->mac_filter_hash, &f->hlist, key);
} }
} }
...@@ -1713,7 +1730,9 @@ i40e_update_filter_state(int count, ...@@ -1713,7 +1730,9 @@ i40e_update_filter_state(int count,
/* Everything's good, mark all filters active. */ /* Everything's good, mark all filters active. */
for (i = 0; i < count ; i++) { for (i = 0; i < count ; i++) {
add_head->state = I40E_FILTER_ACTIVE; add_head->state = I40E_FILTER_ACTIVE;
add_head = list_next_entry(add_head, list); add_head = hlist_entry(add_head->hlist.next,
typeof(struct i40e_mac_filter),
hlist);
} }
} else if (aq_err == I40E_AQ_RC_ENOSPC) { } else if (aq_err == I40E_AQ_RC_ENOSPC) {
/* Device ran out of filter space. Check the return value /* Device ran out of filter space. Check the return value
...@@ -1727,14 +1746,18 @@ i40e_update_filter_state(int count, ...@@ -1727,14 +1746,18 @@ i40e_update_filter_state(int count,
add_head->state = I40E_FILTER_ACTIVE; add_head->state = I40E_FILTER_ACTIVE;
retval++; retval++;
} }
add_head = list_next_entry(add_head, list); add_head = hlist_entry(add_head->hlist.next,
typeof(struct i40e_mac_filter),
hlist);
} }
} else { } else {
/* Some other horrible thing happened, fail all filters */ /* Some other horrible thing happened, fail all filters */
retval = 0; retval = 0;
for (i = 0; i < count ; i++) { for (i = 0; i < count ; i++) {
add_head->state = I40E_FILTER_FAILED; add_head->state = I40E_FILTER_FAILED;
add_head = list_next_entry(add_head, list); add_head = hlist_entry(add_head->hlist.next,
typeof(struct i40e_mac_filter),
hlist);
} }
} }
return retval; return retval;
...@@ -1750,14 +1773,15 @@ i40e_update_filter_state(int count, ...@@ -1750,14 +1773,15 @@ i40e_update_filter_state(int count,
**/ **/
int i40e_sync_vsi_filters(struct i40e_vsi *vsi) int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
{ {
struct i40e_mac_filter *f, *ftmp, *add_head = NULL; struct i40e_mac_filter *f, *add_head = NULL;
struct list_head tmp_add_list, tmp_del_list; struct hlist_head tmp_add_list, tmp_del_list;
struct i40e_hw *hw = &vsi->back->hw; struct i40e_hw *hw = &vsi->back->hw;
bool promisc_changed = false; bool promisc_changed = false;
char vsi_name[16] = "PF"; char vsi_name[16] = "PF";
int filter_list_len = 0; int filter_list_len = 0;
u32 changed_flags = 0; u32 changed_flags = 0;
i40e_status aq_ret = 0; i40e_status aq_ret = 0;
struct hlist_node *h;
int retval = 0; int retval = 0;
struct i40e_pf *pf; struct i40e_pf *pf;
int num_add = 0; int num_add = 0;
...@@ -1766,6 +1790,7 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi) ...@@ -1766,6 +1790,7 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
u16 cmd_flags; u16 cmd_flags;
int list_size; int list_size;
int fcnt; int fcnt;
int bkt;
/* empty array typed pointers, kcalloc later */ /* empty array typed pointers, kcalloc later */
struct i40e_aqc_add_macvlan_element_data *add_list; struct i40e_aqc_add_macvlan_element_data *add_list;
...@@ -1780,8 +1805,8 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi) ...@@ -1780,8 +1805,8 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
vsi->current_netdev_flags = vsi->netdev->flags; vsi->current_netdev_flags = vsi->netdev->flags;
} }
INIT_LIST_HEAD(&tmp_add_list); INIT_HLIST_HEAD(&tmp_add_list);
INIT_LIST_HEAD(&tmp_del_list); INIT_HLIST_HEAD(&tmp_del_list);
if (vsi->type == I40E_VSI_SRIOV) if (vsi->type == I40E_VSI_SRIOV)
snprintf(vsi_name, sizeof(vsi_name) - 1, "VF %d", vsi->vf_id); snprintf(vsi_name, sizeof(vsi_name) - 1, "VF %d", vsi->vf_id);
...@@ -1791,24 +1816,25 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi) ...@@ -1791,24 +1816,25 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
if (vsi->flags & I40E_VSI_FLAG_FILTER_CHANGED) { if (vsi->flags & I40E_VSI_FLAG_FILTER_CHANGED) {
vsi->flags &= ~I40E_VSI_FLAG_FILTER_CHANGED; vsi->flags &= ~I40E_VSI_FLAG_FILTER_CHANGED;
spin_lock_bh(&vsi->mac_filter_list_lock); spin_lock_bh(&vsi->mac_filter_hash_lock);
/* Create a list of filters to delete. */ /* Create a list of filters to delete. */
list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list) { hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist) {
if (f->state == I40E_FILTER_REMOVE) { if (f->state == I40E_FILTER_REMOVE) {
/* Move the element into temporary del_list */ /* Move the element into temporary del_list */
list_move_tail(&f->list, &tmp_del_list); hash_del(&f->hlist);
hlist_add_head(&f->hlist, &tmp_del_list);
vsi->active_filters--; vsi->active_filters--;
} }
if (f->state == I40E_FILTER_NEW) { if (f->state == I40E_FILTER_NEW) {
/* Move the element into temporary add_list */ hash_del(&f->hlist);
list_move_tail(&f->list, &tmp_add_list); hlist_add_head(&f->hlist, &tmp_add_list);
} }
} }
spin_unlock_bh(&vsi->mac_filter_list_lock); spin_unlock_bh(&vsi->mac_filter_hash_lock);
} }
/* Now process 'del_list' outside the lock */ /* Now process 'del_list' outside the lock */
if (!list_empty(&tmp_del_list)) { if (!hlist_empty(&tmp_del_list)) {
filter_list_len = hw->aq.asq_buf_size / filter_list_len = hw->aq.asq_buf_size /
sizeof(struct i40e_aqc_remove_macvlan_element_data); sizeof(struct i40e_aqc_remove_macvlan_element_data);
list_size = filter_list_len * list_size = filter_list_len *
...@@ -1816,14 +1842,14 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi) ...@@ -1816,14 +1842,14 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
del_list = kzalloc(list_size, GFP_ATOMIC); del_list = kzalloc(list_size, GFP_ATOMIC);
if (!del_list) { if (!del_list) {
/* Undo VSI's MAC filter entry element updates */ /* Undo VSI's MAC filter entry element updates */
spin_lock_bh(&vsi->mac_filter_list_lock); spin_lock_bh(&vsi->mac_filter_hash_lock);
i40e_undo_del_filter_entries(vsi, &tmp_del_list); i40e_undo_del_filter_entries(vsi, &tmp_del_list);
spin_unlock_bh(&vsi->mac_filter_list_lock); spin_unlock_bh(&vsi->mac_filter_hash_lock);
retval = -ENOMEM; retval = -ENOMEM;
goto out; goto out;
} }
list_for_each_entry_safe(f, ftmp, &tmp_del_list, list) { hlist_for_each_entry_safe(f, h, &tmp_del_list, hlist) {
cmd_flags = 0; cmd_flags = 0;
/* add to delete list */ /* add to delete list */
...@@ -1864,7 +1890,7 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi) ...@@ -1864,7 +1890,7 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
/* Release memory for MAC filter entries which were /* Release memory for MAC filter entries which were
* synced up with HW. * synced up with HW.
*/ */
list_del(&f->list); hlist_del(&f->hlist);
kfree(f); kfree(f);
} }
...@@ -1891,7 +1917,7 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi) ...@@ -1891,7 +1917,7 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
del_list = NULL; del_list = NULL;
} }
if (!list_empty(&tmp_add_list)) { if (!hlist_empty(&tmp_add_list)) {
/* Do all the adds now. */ /* Do all the adds now. */
filter_list_len = hw->aq.asq_buf_size / filter_list_len = hw->aq.asq_buf_size /
sizeof(struct i40e_aqc_add_macvlan_element_data); sizeof(struct i40e_aqc_add_macvlan_element_data);
...@@ -1903,7 +1929,7 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi) ...@@ -1903,7 +1929,7 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
goto out; goto out;
} }
num_add = 0; num_add = 0;
list_for_each_entry(f, &tmp_add_list, list) { hlist_for_each_entry(f, &tmp_add_list, hlist) {
if (test_bit(__I40E_FILTER_OVERFLOW_PROMISC, if (test_bit(__I40E_FILTER_OVERFLOW_PROMISC,
&vsi->state)) { &vsi->state)) {
f->state = I40E_FILTER_FAILED; f->state = I40E_FILTER_FAILED;
...@@ -1974,11 +2000,14 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi) ...@@ -1974,11 +2000,14 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
/* Now move all of the filters from the temp add list back to /* Now move all of the filters from the temp add list back to
* the VSI's list. * the VSI's list.
*/ */
spin_lock_bh(&vsi->mac_filter_list_lock); spin_lock_bh(&vsi->mac_filter_hash_lock);
list_for_each_entry_safe(f, ftmp, &tmp_add_list, list) { hlist_for_each_entry_safe(f, h, &tmp_add_list, hlist) {
list_move_tail(&f->list, &vsi->mac_filter_list); u64 key = i40e_addr_to_hkey(f->macaddr);
hlist_del(&f->hlist);
hash_add(vsi->mac_filter_hash, &f->hlist, key);
} }
spin_unlock_bh(&vsi->mac_filter_list_lock); spin_unlock_bh(&vsi->mac_filter_hash_lock);
kfree(add_list); kfree(add_list);
add_list = NULL; add_list = NULL;
} }
...@@ -1990,12 +2019,12 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi) ...@@ -1990,12 +2019,12 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
/* See if we have any failed filters. We can't drop out of /* See if we have any failed filters. We can't drop out of
* promiscuous until these have all been deleted. * promiscuous until these have all been deleted.
*/ */
spin_lock_bh(&vsi->mac_filter_list_lock); spin_lock_bh(&vsi->mac_filter_hash_lock);
list_for_each_entry(f, &vsi->mac_filter_list, list) { hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) {
if (f->state == I40E_FILTER_FAILED) if (f->state == I40E_FILTER_FAILED)
failed_count++; failed_count++;
} }
spin_unlock_bh(&vsi->mac_filter_list_lock); spin_unlock_bh(&vsi->mac_filter_hash_lock);
if (!failed_count) { if (!failed_count) {
dev_info(&pf->pdev->dev, dev_info(&pf->pdev->dev,
"filter logjam cleared on %s, leaving overflow promiscuous mode\n", "filter logjam cleared on %s, leaving overflow promiscuous mode\n",
...@@ -2277,10 +2306,12 @@ static void i40e_vlan_rx_register(struct net_device *netdev, u32 features) ...@@ -2277,10 +2306,12 @@ static void i40e_vlan_rx_register(struct net_device *netdev, u32 features)
**/ **/
int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid) int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid)
{ {
struct i40e_mac_filter *f, *ftmp, *add_f, *del_f; struct i40e_mac_filter *f, *add_f, *del_f;
struct hlist_node *h;
int bkt;
/* Locked once because all functions invoked below iterates list*/ /* Locked once because all functions invoked below iterates list*/
spin_lock_bh(&vsi->mac_filter_list_lock); spin_lock_bh(&vsi->mac_filter_hash_lock);
if (vsi->netdev) { if (vsi->netdev) {
add_f = i40e_add_filter(vsi, vsi->netdev->dev_addr, vid); add_f = i40e_add_filter(vsi, vsi->netdev->dev_addr, vid);
...@@ -2288,12 +2319,12 @@ int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid) ...@@ -2288,12 +2319,12 @@ int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid)
dev_info(&vsi->back->pdev->dev, dev_info(&vsi->back->pdev->dev,
"Could not add vlan filter %d for %pM\n", "Could not add vlan filter %d for %pM\n",
vid, vsi->netdev->dev_addr); vid, vsi->netdev->dev_addr);
spin_unlock_bh(&vsi->mac_filter_list_lock); spin_unlock_bh(&vsi->mac_filter_hash_lock);
return -ENOMEM; return -ENOMEM;
} }
} }
list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list) { hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist) {
if (f->state == I40E_FILTER_REMOVE) if (f->state == I40E_FILTER_REMOVE)
continue; continue;
add_f = i40e_add_filter(vsi, f->macaddr, vid); add_f = i40e_add_filter(vsi, f->macaddr, vid);
...@@ -2301,7 +2332,7 @@ int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid) ...@@ -2301,7 +2332,7 @@ int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid)
dev_info(&vsi->back->pdev->dev, dev_info(&vsi->back->pdev->dev,
"Could not add vlan filter %d for %pM\n", "Could not add vlan filter %d for %pM\n",
vid, f->macaddr); vid, f->macaddr);
spin_unlock_bh(&vsi->mac_filter_list_lock); spin_unlock_bh(&vsi->mac_filter_hash_lock);
return -ENOMEM; return -ENOMEM;
} }
} }
...@@ -2321,7 +2352,7 @@ int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid) ...@@ -2321,7 +2352,7 @@ int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid)
dev_info(&vsi->back->pdev->dev, dev_info(&vsi->back->pdev->dev,
"Could not add filter 0 for %pM\n", "Could not add filter 0 for %pM\n",
vsi->netdev->dev_addr); vsi->netdev->dev_addr);
spin_unlock_bh(&vsi->mac_filter_list_lock); spin_unlock_bh(&vsi->mac_filter_hash_lock);
return -ENOMEM; return -ENOMEM;
} }
} }
...@@ -2329,7 +2360,7 @@ int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid) ...@@ -2329,7 +2360,7 @@ int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid)
/* Do not assume that I40E_VLAN_ANY should be reset to VLAN 0 */ /* Do not assume that I40E_VLAN_ANY should be reset to VLAN 0 */
if (vid > 0 && !vsi->info.pvid) { if (vid > 0 && !vsi->info.pvid) {
list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list) { hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist) {
if (f->state == I40E_FILTER_REMOVE) if (f->state == I40E_FILTER_REMOVE)
continue; continue;
del_f = i40e_find_filter(vsi, f->macaddr, del_f = i40e_find_filter(vsi, f->macaddr,
...@@ -2342,13 +2373,13 @@ int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid) ...@@ -2342,13 +2373,13 @@ int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid)
dev_info(&vsi->back->pdev->dev, dev_info(&vsi->back->pdev->dev,
"Could not add filter 0 for %pM\n", "Could not add filter 0 for %pM\n",
f->macaddr); f->macaddr);
spin_unlock_bh(&vsi->mac_filter_list_lock); spin_unlock_bh(&vsi->mac_filter_hash_lock);
return -ENOMEM; return -ENOMEM;
} }
} }
} }
spin_unlock_bh(&vsi->mac_filter_list_lock); spin_unlock_bh(&vsi->mac_filter_hash_lock);
/* schedule our worker thread which will take care of /* schedule our worker thread which will take care of
* applying the new filter changes * applying the new filter changes
...@@ -2367,16 +2398,18 @@ int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid) ...@@ -2367,16 +2398,18 @@ int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid)
int i40e_vsi_kill_vlan(struct i40e_vsi *vsi, s16 vid) int i40e_vsi_kill_vlan(struct i40e_vsi *vsi, s16 vid)
{ {
struct net_device *netdev = vsi->netdev; struct net_device *netdev = vsi->netdev;
struct i40e_mac_filter *f, *ftmp, *add_f; struct i40e_mac_filter *f, *add_f;
struct hlist_node *h;
int filter_count = 0; int filter_count = 0;
int bkt;
/* Locked once because all functions invoked below iterates list */ /* Locked once because all functions invoked below iterates list */
spin_lock_bh(&vsi->mac_filter_list_lock); spin_lock_bh(&vsi->mac_filter_hash_lock);
if (vsi->netdev) if (vsi->netdev)
i40e_del_filter(vsi, netdev->dev_addr, vid); i40e_del_filter(vsi, netdev->dev_addr, vid);
list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list) { hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist) {
if (f->vlan == vid) if (f->vlan == vid)
__i40e_del_filter(vsi, f); __i40e_del_filter(vsi, f);
} }
...@@ -2386,7 +2419,7 @@ int i40e_vsi_kill_vlan(struct i40e_vsi *vsi, s16 vid) ...@@ -2386,7 +2419,7 @@ int i40e_vsi_kill_vlan(struct i40e_vsi *vsi, s16 vid)
* be replaced with -1. This signifies that we should from now * be replaced with -1. This signifies that we should from now
* on accept any traffic (with any tag present, or untagged) * on accept any traffic (with any tag present, or untagged)
*/ */
list_for_each_entry(f, &vsi->mac_filter_list, list) { hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) {
if (vsi->netdev) { if (vsi->netdev) {
if (f->vlan && if (f->vlan &&
ether_addr_equal(netdev->dev_addr, f->macaddr)) ether_addr_equal(netdev->dev_addr, f->macaddr))
...@@ -2404,13 +2437,13 @@ int i40e_vsi_kill_vlan(struct i40e_vsi *vsi, s16 vid) ...@@ -2404,13 +2437,13 @@ int i40e_vsi_kill_vlan(struct i40e_vsi *vsi, s16 vid)
dev_info(&vsi->back->pdev->dev, dev_info(&vsi->back->pdev->dev,
"Could not add filter %d for %pM\n", "Could not add filter %d for %pM\n",
I40E_VLAN_ANY, netdev->dev_addr); I40E_VLAN_ANY, netdev->dev_addr);
spin_unlock_bh(&vsi->mac_filter_list_lock); spin_unlock_bh(&vsi->mac_filter_hash_lock);
return -ENOMEM; return -ENOMEM;
} }
} }
if (!filter_count) { if (!filter_count) {
list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list) { hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist) {
if (!f->vlan) if (!f->vlan)
__i40e_del_filter(vsi, f); __i40e_del_filter(vsi, f);
add_f = i40e_add_filter(vsi, f->macaddr, I40E_VLAN_ANY); add_f = i40e_add_filter(vsi, f->macaddr, I40E_VLAN_ANY);
...@@ -2418,13 +2451,13 @@ int i40e_vsi_kill_vlan(struct i40e_vsi *vsi, s16 vid) ...@@ -2418,13 +2451,13 @@ int i40e_vsi_kill_vlan(struct i40e_vsi *vsi, s16 vid)
dev_info(&vsi->back->pdev->dev, dev_info(&vsi->back->pdev->dev,
"Could not add filter %d for %pM\n", "Could not add filter %d for %pM\n",
I40E_VLAN_ANY, f->macaddr); I40E_VLAN_ANY, f->macaddr);
spin_unlock_bh(&vsi->mac_filter_list_lock); spin_unlock_bh(&vsi->mac_filter_hash_lock);
return -ENOMEM; return -ENOMEM;
} }
} }
} }
spin_unlock_bh(&vsi->mac_filter_list_lock); spin_unlock_bh(&vsi->mac_filter_hash_lock);
/* schedule our worker thread which will take care of /* schedule our worker thread which will take care of
* applying the new filter changes * applying the new filter changes
...@@ -7302,7 +7335,7 @@ static int i40e_vsi_mem_alloc(struct i40e_pf *pf, enum i40e_vsi_type type) ...@@ -7302,7 +7335,7 @@ static int i40e_vsi_mem_alloc(struct i40e_pf *pf, enum i40e_vsi_type type)
pf->rss_table_size : 64; pf->rss_table_size : 64;
vsi->netdev_registered = false; vsi->netdev_registered = false;
vsi->work_limit = I40E_DEFAULT_IRQ_WORK; vsi->work_limit = I40E_DEFAULT_IRQ_WORK;
INIT_LIST_HEAD(&vsi->mac_filter_list); hash_init(vsi->mac_filter_hash);
vsi->irqs_ready = false; vsi->irqs_ready = false;
ret = i40e_set_num_rings_in_vsi(vsi); ret = i40e_set_num_rings_in_vsi(vsi);
...@@ -7317,7 +7350,7 @@ static int i40e_vsi_mem_alloc(struct i40e_pf *pf, enum i40e_vsi_type type) ...@@ -7317,7 +7350,7 @@ static int i40e_vsi_mem_alloc(struct i40e_pf *pf, enum i40e_vsi_type type)
i40e_vsi_setup_irqhandler(vsi, i40e_msix_clean_rings); i40e_vsi_setup_irqhandler(vsi, i40e_msix_clean_rings);
/* Initialize VSI lock */ /* Initialize VSI lock */
spin_lock_init(&vsi->mac_filter_list_lock); spin_lock_init(&vsi->mac_filter_hash_lock);
pf->vsi[vsi_idx] = vsi; pf->vsi[vsi_idx] = vsi;
ret = vsi_idx; ret = vsi_idx;
goto unlock_pf; goto unlock_pf;
...@@ -9102,18 +9135,18 @@ static int i40e_config_netdev(struct i40e_vsi *vsi) ...@@ -9102,18 +9135,18 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
if (vsi->type == I40E_VSI_MAIN) { if (vsi->type == I40E_VSI_MAIN) {
SET_NETDEV_DEV(netdev, &pf->pdev->dev); SET_NETDEV_DEV(netdev, &pf->pdev->dev);
ether_addr_copy(mac_addr, hw->mac.perm_addr); ether_addr_copy(mac_addr, hw->mac.perm_addr);
spin_lock_bh(&vsi->mac_filter_list_lock); spin_lock_bh(&vsi->mac_filter_hash_lock);
i40e_add_filter(vsi, mac_addr, I40E_VLAN_ANY); i40e_add_filter(vsi, mac_addr, I40E_VLAN_ANY);
spin_unlock_bh(&vsi->mac_filter_list_lock); spin_unlock_bh(&vsi->mac_filter_hash_lock);
} else { } else {
/* relate the VSI_VMDQ name to the VSI_MAIN name */ /* relate the VSI_VMDQ name to the VSI_MAIN name */
snprintf(netdev->name, IFNAMSIZ, "%sv%%d", snprintf(netdev->name, IFNAMSIZ, "%sv%%d",
pf->vsi[pf->lan_vsi]->netdev->name); pf->vsi[pf->lan_vsi]->netdev->name);
random_ether_addr(mac_addr); random_ether_addr(mac_addr);
spin_lock_bh(&vsi->mac_filter_list_lock); spin_lock_bh(&vsi->mac_filter_hash_lock);
i40e_add_filter(vsi, mac_addr, I40E_VLAN_ANY); i40e_add_filter(vsi, mac_addr, I40E_VLAN_ANY);
spin_unlock_bh(&vsi->mac_filter_list_lock); spin_unlock_bh(&vsi->mac_filter_hash_lock);
} }
ether_addr_copy(netdev->dev_addr, mac_addr); ether_addr_copy(netdev->dev_addr, mac_addr);
...@@ -9202,7 +9235,9 @@ static int i40e_add_vsi(struct i40e_vsi *vsi) ...@@ -9202,7 +9235,9 @@ static int i40e_add_vsi(struct i40e_vsi *vsi)
struct i40e_pf *pf = vsi->back; struct i40e_pf *pf = vsi->back;
struct i40e_hw *hw = &pf->hw; struct i40e_hw *hw = &pf->hw;
struct i40e_vsi_context ctxt; struct i40e_vsi_context ctxt;
struct i40e_mac_filter *f, *ftmp; struct i40e_mac_filter *f;
struct hlist_node *h;
int bkt;
u8 enabled_tc = 0x1; /* TC0 enabled */ u8 enabled_tc = 0x1; /* TC0 enabled */
int f_count = 0; int f_count = 0;
...@@ -9401,13 +9436,13 @@ static int i40e_add_vsi(struct i40e_vsi *vsi) ...@@ -9401,13 +9436,13 @@ static int i40e_add_vsi(struct i40e_vsi *vsi)
vsi->active_filters = 0; vsi->active_filters = 0;
clear_bit(__I40E_FILTER_OVERFLOW_PROMISC, &vsi->state); clear_bit(__I40E_FILTER_OVERFLOW_PROMISC, &vsi->state);
spin_lock_bh(&vsi->mac_filter_list_lock); spin_lock_bh(&vsi->mac_filter_hash_lock);
/* If macvlan filters already exist, force them to get loaded */ /* If macvlan filters already exist, force them to get loaded */
list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list) { hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist) {
f->state = I40E_FILTER_NEW; f->state = I40E_FILTER_NEW;
f_count++; f_count++;
} }
spin_unlock_bh(&vsi->mac_filter_list_lock); spin_unlock_bh(&vsi->mac_filter_hash_lock);
if (f_count) { if (f_count) {
vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED; vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED;
...@@ -9437,11 +9472,12 @@ static int i40e_add_vsi(struct i40e_vsi *vsi) ...@@ -9437,11 +9472,12 @@ static int i40e_add_vsi(struct i40e_vsi *vsi)
**/ **/
int i40e_vsi_release(struct i40e_vsi *vsi) int i40e_vsi_release(struct i40e_vsi *vsi)
{ {
struct i40e_mac_filter *f, *ftmp; struct i40e_mac_filter *f;
struct hlist_node *h;
struct i40e_veb *veb = NULL; struct i40e_veb *veb = NULL;
struct i40e_pf *pf; struct i40e_pf *pf;
u16 uplink_seid; u16 uplink_seid;
int i, n; int i, n, bkt;
pf = vsi->back; pf = vsi->back;
...@@ -9471,7 +9507,7 @@ int i40e_vsi_release(struct i40e_vsi *vsi) ...@@ -9471,7 +9507,7 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
i40e_vsi_disable_irq(vsi); i40e_vsi_disable_irq(vsi);
} }
spin_lock_bh(&vsi->mac_filter_list_lock); spin_lock_bh(&vsi->mac_filter_hash_lock);
/* clear the sync flag on all filters */ /* clear the sync flag on all filters */
if (vsi->netdev) { if (vsi->netdev) {
...@@ -9480,10 +9516,10 @@ int i40e_vsi_release(struct i40e_vsi *vsi) ...@@ -9480,10 +9516,10 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
} }
/* make sure any remaining filters are marked for deletion */ /* make sure any remaining filters are marked for deletion */
list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list) hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist)
__i40e_del_filter(vsi, f); __i40e_del_filter(vsi, f);
spin_unlock_bh(&vsi->mac_filter_list_lock); spin_unlock_bh(&vsi->mac_filter_hash_lock);
i40e_sync_vsi_filters(vsi); i40e_sync_vsi_filters(vsi);
......
...@@ -686,7 +686,7 @@ static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type) ...@@ -686,7 +686,7 @@ static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type)
if (vf->port_vlan_id) if (vf->port_vlan_id)
i40e_vsi_add_pvid(vsi, vf->port_vlan_id); i40e_vsi_add_pvid(vsi, vf->port_vlan_id);
spin_lock_bh(&vsi->mac_filter_list_lock); spin_lock_bh(&vsi->mac_filter_hash_lock);
if (is_valid_ether_addr(vf->default_lan_addr.addr)) { if (is_valid_ether_addr(vf->default_lan_addr.addr)) {
f = i40e_add_filter(vsi, vf->default_lan_addr.addr, f = i40e_add_filter(vsi, vf->default_lan_addr.addr,
vf->port_vlan_id ? vf->port_vlan_id ?
...@@ -696,7 +696,7 @@ static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type) ...@@ -696,7 +696,7 @@ static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type)
"Could not add MAC filter %pM for VF %d\n", "Could not add MAC filter %pM for VF %d\n",
vf->default_lan_addr.addr, vf->vf_id); vf->default_lan_addr.addr, vf->vf_id);
} }
spin_unlock_bh(&vsi->mac_filter_list_lock); spin_unlock_bh(&vsi->mac_filter_hash_lock);
i40e_write_rx_ctl(&pf->hw, I40E_VFQF_HENA1(0, vf->vf_id), i40e_write_rx_ctl(&pf->hw, I40E_VFQF_HENA1(0, vf->vf_id),
(u32)hena); (u32)hena);
i40e_write_rx_ctl(&pf->hw, I40E_VFQF_HENA1(1, vf->vf_id), i40e_write_rx_ctl(&pf->hw, I40E_VFQF_HENA1(1, vf->vf_id),
...@@ -1449,9 +1449,9 @@ static void i40e_vc_reset_vf_msg(struct i40e_vf *vf) ...@@ -1449,9 +1449,9 @@ static void i40e_vc_reset_vf_msg(struct i40e_vf *vf)
static inline int i40e_getnum_vf_vsi_vlan_filters(struct i40e_vsi *vsi) static inline int i40e_getnum_vf_vsi_vlan_filters(struct i40e_vsi *vsi)
{ {
struct i40e_mac_filter *f; struct i40e_mac_filter *f;
int num_vlans = 0; int num_vlans = 0, bkt;
list_for_each_entry(f, &vsi->mac_filter_list, list) { hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) {
if (f->vlan >= 0 && f->vlan <= I40E_MAX_VLANID) if (f->vlan >= 0 && f->vlan <= I40E_MAX_VLANID)
num_vlans++; num_vlans++;
} }
...@@ -1481,6 +1481,7 @@ static int i40e_vc_config_promiscuous_mode_msg(struct i40e_vf *vf, ...@@ -1481,6 +1481,7 @@ static int i40e_vc_config_promiscuous_mode_msg(struct i40e_vf *vf,
struct i40e_vsi *vsi; struct i40e_vsi *vsi;
bool alluni = false; bool alluni = false;
int aq_err = 0; int aq_err = 0;
int bkt;
vsi = i40e_find_vsi_from_id(pf, info->vsi_id); vsi = i40e_find_vsi_from_id(pf, info->vsi_id);
if (!test_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states) || if (!test_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states) ||
...@@ -1507,7 +1508,7 @@ static int i40e_vc_config_promiscuous_mode_msg(struct i40e_vf *vf, ...@@ -1507,7 +1508,7 @@ static int i40e_vc_config_promiscuous_mode_msg(struct i40e_vf *vf,
vf->port_vlan_id, vf->port_vlan_id,
NULL); NULL);
} else if (i40e_getnum_vf_vsi_vlan_filters(vsi)) { } else if (i40e_getnum_vf_vsi_vlan_filters(vsi)) {
list_for_each_entry(f, &vsi->mac_filter_list, list) { hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) {
if (f->vlan < 0 || f->vlan > I40E_MAX_VLANID) if (f->vlan < 0 || f->vlan > I40E_MAX_VLANID)
continue; continue;
aq_ret = i40e_aq_set_vsi_mc_promisc_on_vlan(hw, aq_ret = i40e_aq_set_vsi_mc_promisc_on_vlan(hw,
...@@ -1557,7 +1558,7 @@ static int i40e_vc_config_promiscuous_mode_msg(struct i40e_vf *vf, ...@@ -1557,7 +1558,7 @@ static int i40e_vc_config_promiscuous_mode_msg(struct i40e_vf *vf,
vf->port_vlan_id, vf->port_vlan_id,
NULL); NULL);
} else if (i40e_getnum_vf_vsi_vlan_filters(vsi)) { } else if (i40e_getnum_vf_vsi_vlan_filters(vsi)) {
list_for_each_entry(f, &vsi->mac_filter_list, list) { hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) {
aq_ret = 0; aq_ret = 0;
if (f->vlan >= 0 && f->vlan <= I40E_MAX_VLANID) { if (f->vlan >= 0 && f->vlan <= I40E_MAX_VLANID) {
aq_ret = aq_ret =
...@@ -1927,7 +1928,7 @@ static int i40e_vc_add_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) ...@@ -1927,7 +1928,7 @@ static int i40e_vc_add_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
/* Lock once, because all function inside for loop accesses VSI's /* Lock once, because all function inside for loop accesses VSI's
* MAC filter list which needs to be protected using same lock. * MAC filter list which needs to be protected using same lock.
*/ */
spin_lock_bh(&vsi->mac_filter_list_lock); spin_lock_bh(&vsi->mac_filter_hash_lock);
/* add new addresses to the list */ /* add new addresses to the list */
for (i = 0; i < al->num_elements; i++) { for (i = 0; i < al->num_elements; i++) {
...@@ -1946,13 +1947,13 @@ static int i40e_vc_add_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) ...@@ -1946,13 +1947,13 @@ static int i40e_vc_add_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
"Unable to add MAC filter %pM for VF %d\n", "Unable to add MAC filter %pM for VF %d\n",
al->list[i].addr, vf->vf_id); al->list[i].addr, vf->vf_id);
ret = I40E_ERR_PARAM; ret = I40E_ERR_PARAM;
spin_unlock_bh(&vsi->mac_filter_list_lock); spin_unlock_bh(&vsi->mac_filter_hash_lock);
goto error_param; goto error_param;
} else { } else {
vf->num_mac++; vf->num_mac++;
} }
} }
spin_unlock_bh(&vsi->mac_filter_list_lock); spin_unlock_bh(&vsi->mac_filter_hash_lock);
/* program the updated filter list */ /* program the updated filter list */
ret = i40e_sync_vsi_filters(vsi); ret = i40e_sync_vsi_filters(vsi);
...@@ -2001,18 +2002,18 @@ static int i40e_vc_del_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) ...@@ -2001,18 +2002,18 @@ static int i40e_vc_del_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen)
} }
vsi = pf->vsi[vf->lan_vsi_idx]; vsi = pf->vsi[vf->lan_vsi_idx];
spin_lock_bh(&vsi->mac_filter_list_lock); spin_lock_bh(&vsi->mac_filter_hash_lock);
/* delete addresses from the list */ /* delete addresses from the list */
for (i = 0; i < al->num_elements; i++) for (i = 0; i < al->num_elements; i++)
if (i40e_del_mac_all_vlan(vsi, al->list[i].addr)) { if (i40e_del_mac_all_vlan(vsi, al->list[i].addr)) {
ret = I40E_ERR_INVALID_MAC_ADDR; ret = I40E_ERR_INVALID_MAC_ADDR;
spin_unlock_bh(&vsi->mac_filter_list_lock); spin_unlock_bh(&vsi->mac_filter_hash_lock);
goto error_param; goto error_param;
} else { } else {
vf->num_mac--; vf->num_mac--;
} }
spin_unlock_bh(&vsi->mac_filter_list_lock); spin_unlock_bh(&vsi->mac_filter_hash_lock);
/* program the updated filter list */ /* program the updated filter list */
ret = i40e_sync_vsi_filters(vsi); ret = i40e_sync_vsi_filters(vsi);
...@@ -2687,6 +2688,7 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac) ...@@ -2687,6 +2688,7 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
struct i40e_mac_filter *f; struct i40e_mac_filter *f;
struct i40e_vf *vf; struct i40e_vf *vf;
int ret = 0; int ret = 0;
int bkt;
/* validate the request */ /* validate the request */
if (vf_id >= pf->num_alloc_vfs) { if (vf_id >= pf->num_alloc_vfs) {
...@@ -2713,9 +2715,9 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac) ...@@ -2713,9 +2715,9 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
} }
/* Lock once because below invoked function add/del_filter requires /* Lock once because below invoked function add/del_filter requires
* mac_filter_list_lock to be held * mac_filter_hash_lock to be held
*/ */
spin_lock_bh(&vsi->mac_filter_list_lock); spin_lock_bh(&vsi->mac_filter_hash_lock);
/* delete the temporary mac address */ /* delete the temporary mac address */
if (!is_zero_ether_addr(vf->default_lan_addr.addr)) if (!is_zero_ether_addr(vf->default_lan_addr.addr))
...@@ -2725,10 +2727,10 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac) ...@@ -2725,10 +2727,10 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac)
/* Delete all the filters for this VSI - we're going to kill it /* Delete all the filters for this VSI - we're going to kill it
* anyway. * anyway.
*/ */
list_for_each_entry(f, &vsi->mac_filter_list, list) hash_for_each(vsi->mac_filter_hash, bkt, f, hlist)
i40e_del_filter(vsi, f->macaddr, f->vlan); i40e_del_filter(vsi, f->macaddr, f->vlan);
spin_unlock_bh(&vsi->mac_filter_list_lock); spin_unlock_bh(&vsi->mac_filter_hash_lock);
dev_info(&pf->pdev->dev, "Setting MAC %pM on VF %d\n", mac, vf_id); dev_info(&pf->pdev->dev, "Setting MAC %pM on VF %d\n", mac, vf_id);
/* program mac filter */ /* program mac filter */
...@@ -2800,9 +2802,9 @@ int i40e_ndo_set_vf_port_vlan(struct net_device *netdev, int vf_id, ...@@ -2800,9 +2802,9 @@ int i40e_ndo_set_vf_port_vlan(struct net_device *netdev, int vf_id,
/* duplicate request, so just return success */ /* duplicate request, so just return success */
goto error_pvid; goto error_pvid;
spin_lock_bh(&vsi->mac_filter_list_lock); spin_lock_bh(&vsi->mac_filter_hash_lock);
is_vsi_in_vlan = i40e_is_vsi_in_vlan(vsi); is_vsi_in_vlan = i40e_is_vsi_in_vlan(vsi);
spin_unlock_bh(&vsi->mac_filter_list_lock); spin_unlock_bh(&vsi->mac_filter_hash_lock);
if (le16_to_cpu(vsi->info.pvid) == 0 && is_vsi_in_vlan) { if (le16_to_cpu(vsi->info.pvid) == 0 && is_vsi_in_vlan) {
dev_err(&pf->pdev->dev, dev_err(&pf->pdev->dev,
......
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