Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec...
[linux-2.6-block.git] / drivers / net / ethernet / intel / i40e / i40e_main.c
index d0b3a1bb82cac9ec9fbb05abc63d2a7f44edb45b..b2f76d24000d0cdaf70faa618a2e248aad096ee4 100644 (file)
@@ -41,7 +41,7 @@ static const char i40e_driver_string[] =
 
 #define DRV_VERSION_MAJOR 1
 #define DRV_VERSION_MINOR 6
-#define DRV_VERSION_BUILD 11
+#define DRV_VERSION_BUILD 25
 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \
             __stringify(DRV_VERSION_MINOR) "." \
             __stringify(DRV_VERSION_BUILD)    DRV_KERN
@@ -57,8 +57,6 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit);
 static int i40e_setup_misc_vector(struct i40e_pf *pf);
 static void i40e_determine_queue_usage(struct i40e_pf *pf);
 static int i40e_setup_pf_filter_control(struct i40e_pf *pf);
-static void i40e_fill_rss_lut(struct i40e_pf *pf, u8 *lut,
-                             u16 rss_table_size, u16 rss_size);
 static void i40e_fdir_sb_setup(struct i40e_pf *pf);
 static int i40e_veb_get_bw_info(struct i40e_veb *veb);
 
@@ -88,6 +86,8 @@ static const struct pci_device_id i40e_pci_tbl[] = {
        {PCI_VDEVICE(INTEL, I40E_DEV_ID_SFP_I_X722), 0},
        {PCI_VDEVICE(INTEL, I40E_DEV_ID_20G_KR2), 0},
        {PCI_VDEVICE(INTEL, I40E_DEV_ID_20G_KR2_A), 0},
+       {PCI_VDEVICE(INTEL, I40E_DEV_ID_25G_B), 0},
+       {PCI_VDEVICE(INTEL, I40E_DEV_ID_25G_SFP28), 0},
        /* required last entry */
        {0, }
 };
@@ -95,8 +95,8 @@ MODULE_DEVICE_TABLE(pci, i40e_pci_tbl);
 
 #define I40E_MAX_VF_COUNT 128
 static int debug = -1;
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
+module_param(debug, uint, 0);
+MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all), Debug mask (0x8XXXXXXX)");
 
 MODULE_AUTHOR("Intel Corporation, <e1000-devel@lists.sourceforge.net>");
 MODULE_DESCRIPTION("Intel(R) Ethernet Connection XL710 Network Driver");
@@ -288,8 +288,7 @@ struct i40e_vsi *i40e_find_vsi_from_id(struct i40e_pf *pf, u16 id)
 void i40e_service_event_schedule(struct i40e_pf *pf)
 {
        if (!test_bit(__I40E_DOWN, &pf->state) &&
-           !test_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state) &&
-           !test_and_set_bit(__I40E_SERVICE_SCHED, &pf->state))
+           !test_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state))
                queue_work(i40e_wq, &pf->service_task);
 }
 
@@ -410,15 +409,11 @@ struct rtnl_link_stats64 *i40e_get_vsi_stats_struct(struct i40e_vsi *vsi)
  * Returns the address of the device statistics structure.
  * The statistics are actually updated from the service task.
  **/
-#ifdef I40E_FCOE
-struct rtnl_link_stats64 *i40e_get_netdev_stats_struct(
-                                            struct net_device *netdev,
-                                            struct rtnl_link_stats64 *stats)
-#else
-static struct rtnl_link_stats64 *i40e_get_netdev_stats_struct(
-                                            struct net_device *netdev,
-                                            struct rtnl_link_stats64 *stats)
+#ifndef I40E_FCOE
+static
 #endif
+void i40e_get_netdev_stats_struct(struct net_device *netdev,
+                                 struct rtnl_link_stats64 *stats)
 {
        struct i40e_netdev_priv *np = netdev_priv(netdev);
        struct i40e_ring *tx_ring, *rx_ring;
@@ -427,10 +422,10 @@ static struct rtnl_link_stats64 *i40e_get_netdev_stats_struct(
        int i;
 
        if (test_bit(__I40E_DOWN, &vsi->state))
-               return stats;
+               return;
 
        if (!vsi->tx_rings)
-               return stats;
+               return;
 
        rcu_read_lock();
        for (i = 0; i < vsi->num_queue_pairs; i++) {
@@ -470,8 +465,6 @@ static struct rtnl_link_stats64 *i40e_get_netdev_stats_struct(
        stats->rx_dropped       = vsi_stats->rx_dropped;
        stats->rx_crc_errors    = vsi_stats->rx_crc_errors;
        stats->rx_length_errors = vsi_stats->rx_length_errors;
-
-       return stats;
 }
 
 /**
@@ -527,6 +520,7 @@ void i40e_pf_reset_stats(struct i40e_pf *pf)
                        pf->veb[i]->stat_offsets_loaded = false;
                }
        }
+       pf->hw_csum_rx_error = 0;
 }
 
 /**
@@ -1146,25 +1140,22 @@ void i40e_update_stats(struct i40e_vsi *vsi)
  * @vsi: the VSI to be searched
  * @macaddr: the MAC address
  * @vlan: the vlan
- * @is_vf: make sure its a VF filter, else doesn't matter
- * @is_netdev: make sure its a netdev filter, else doesn't matter
  *
  * Returns ptr to the filter object or NULL
  **/
 static struct i40e_mac_filter *i40e_find_filter(struct i40e_vsi *vsi,
-                                               u8 *macaddr, s16 vlan,
-                                               bool is_vf, bool is_netdev)
+                                               const u8 *macaddr, s16 vlan)
 {
        struct i40e_mac_filter *f;
+       u64 key;
 
        if (!vsi || !macaddr)
                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)) &&
-                   (vlan == f->vlan)    &&
-                   (!is_vf || f->is_vf) &&
-                   (!is_netdev || f->is_netdev))
+                   (vlan == f->vlan))
                        return f;
        }
        return NULL;
@@ -1174,24 +1165,21 @@ static struct i40e_mac_filter *i40e_find_filter(struct i40e_vsi *vsi,
  * i40e_find_mac - Find a mac addr in the macvlan filters list
  * @vsi: the VSI to be searched
  * @macaddr: the MAC address we are searching for
- * @is_vf: make sure its a VF filter, else doesn't matter
- * @is_netdev: make sure its a netdev filter, else doesn't matter
  *
  * Returns the first filter with the provided MAC address or NULL if
  * MAC address was not found
  **/
-struct i40e_mac_filter *i40e_find_mac(struct i40e_vsi *vsi, u8 *macaddr,
-                                     bool is_vf, bool is_netdev)
+struct i40e_mac_filter *i40e_find_mac(struct i40e_vsi *vsi, const u8 *macaddr)
 {
        struct i40e_mac_filter *f;
+       u64 key;
 
        if (!vsi || !macaddr)
                return NULL;
 
-       list_for_each_entry(f, &vsi->mac_filter_list, list) {
-               if ((ether_addr_equal(macaddr, f->macaddr)) &&
-                   (!is_vf || f->is_vf) &&
-                   (!is_netdev || f->is_netdev))
+       key = i40e_addr_to_hkey(macaddr);
+       hash_for_each_possible(vsi->mac_filter_hash, f, hlist, key) {
+               if ((ether_addr_equal(macaddr, f->macaddr)))
                        return f;
        }
        return NULL;
@@ -1205,86 +1193,132 @@ struct i40e_mac_filter *i40e_find_mac(struct i40e_vsi *vsi, u8 *macaddr,
  **/
 bool i40e_is_vsi_in_vlan(struct i40e_vsi *vsi)
 {
-       struct i40e_mac_filter *f;
+       /* If we have a PVID, always operate in VLAN mode */
+       if (vsi->info.pvid)
+               return true;
 
-       /* 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
+       /* We need to operate in VLAN mode whenever we have any filters with
+        * a VLAN other than I40E_VLAN_ALL. We could check the table each
+        * time, incurring search cost repeatedly. However, we can notice two
+        * things:
+        *
+        * 1) the only place where we can gain a VLAN filter is in
+        *    i40e_add_filter.
+        *
+        * 2) the only place where filters are actually removed is in
+        *    i40e_sync_filters_subtask.
+        *
+        * Thus, we can simply use a boolean value, has_vlan_filters which we
+        * will set to true when we add a VLAN filter in i40e_add_filter. Then
+        * we have to perform the full search after deleting filters in
+        * i40e_sync_filters_subtask, but we already have to search
+        * filters here and can perform the check at the same time. This
+        * results in avoiding embedding a loop for VLAN mode inside another
+        * loop over all the filters, and should maintain correctness as noted
+        * above.
         */
-       list_for_each_entry(f, &vsi->mac_filter_list, list) {
-               if (f->vlan >= 0 || vsi->info.pvid)
-                       return true;
-       }
-
-       return false;
+       return vsi->has_vlan_filter;
 }
 
 /**
- * i40e_put_mac_in_vlan - Make macvlan filters from macaddrs and vlans
- * @vsi: the VSI to be searched
- * @macaddr: the mac address to be filtered
- * @is_vf: true if it is a VF
- * @is_netdev: true if it is a netdev
+ * i40e_correct_mac_vlan_filters - Correct non-VLAN filters if necessary
+ * @vsi: the VSI to configure
+ * @tmp_add_list: list of filters ready to be added
+ * @tmp_del_list: list of filters ready to be deleted
+ * @vlan_filters: the number of active VLAN filters
  *
- * Goes through all the macvlan filters and adds a
- * macvlan filter for each unique vlan that already exists
+ * Update VLAN=0 and VLAN=-1 (I40E_VLAN_ANY) filters properly so that they
+ * behave as expected. If we have any active VLAN filters remaining or about
+ * to be added then we need to update non-VLAN filters to be marked as VLAN=0
+ * so that they only match against untagged traffic. If we no longer have any
+ * active VLAN filters, we need to make all non-VLAN filters marked as VLAN=-1
+ * so that they match against both tagged and untagged traffic. In this way,
+ * we ensure that we correctly receive the desired traffic. This ensures that
+ * when we have an active VLAN we will receive only untagged traffic and
+ * traffic matching active VLANs. If we have no active VLANs then we will
+ * operate in non-VLAN mode and receive all traffic, tagged or untagged.
  *
- * Returns first filter found on success, else NULL
- **/
-struct i40e_mac_filter *i40e_put_mac_in_vlan(struct i40e_vsi *vsi, u8 *macaddr,
-                                            bool is_vf, bool is_netdev)
+ * Finally, in a similar fashion, this function also corrects filters when
+ * there is an active PVID assigned to this VSI.
+ *
+ * In case of memory allocation failure return -ENOMEM. Otherwise, return 0.
+ *
+ * This function is only expected to be called from within
+ * i40e_sync_vsi_filters.
+ *
+ * NOTE: This function expects to be called while under the
+ * mac_filter_hash_lock
+ */
+static int i40e_correct_mac_vlan_filters(struct i40e_vsi *vsi,
+                                        struct hlist_head *tmp_add_list,
+                                        struct hlist_head *tmp_del_list,
+                                        int vlan_filters)
 {
-       struct i40e_mac_filter *f;
+       struct i40e_mac_filter *f, *add_head;
+       struct hlist_node *h;
+       int bkt, new_vlan;
 
-       list_for_each_entry(f, &vsi->mac_filter_list, list) {
-               if (vsi->info.pvid)
-                       f->vlan = le16_to_cpu(vsi->info.pvid);
-               if (!i40e_find_filter(vsi, macaddr, f->vlan,
-                                     is_vf, is_netdev)) {
-                       if (!i40e_add_filter(vsi, macaddr, f->vlan,
-                                            is_vf, is_netdev))
-                               return NULL;
-               }
-       }
+       /* To determine if a particular filter needs to be replaced we
+        * have the three following conditions:
+        *
+        * a) if we have a PVID assigned, then all filters which are
+        *    not marked as VLAN=PVID must be replaced with filters that
+        *    are.
+        * b) otherwise, if we have any active VLANS, all filters
+        *    which are marked as VLAN=-1 must be replaced with
+        *    filters marked as VLAN=0
+        * c) finally, if we do not have any active VLANS, all filters
+        *    which are marked as VLAN=0 must be replaced with filters
+        *    marked as VLAN=-1
+        */
 
-       return list_first_entry_or_null(&vsi->mac_filter_list,
-                                       struct i40e_mac_filter, list);
-}
+       /* Update the filters about to be added in place */
+       hlist_for_each_entry(f, tmp_add_list, hlist) {
+               if (vsi->info.pvid && f->vlan != vsi->info.pvid)
+                       f->vlan = vsi->info.pvid;
+               else if (vlan_filters && f->vlan == I40E_VLAN_ANY)
+                       f->vlan = 0;
+               else if (!vlan_filters && f->vlan == 0)
+                       f->vlan = I40E_VLAN_ANY;
+       }
+
+       /* Update the remaining active filters */
+       hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist) {
+               /* Combine the checks for whether a filter needs to be changed
+                * and then determine the new VLAN inside the if block, in
+                * order to avoid duplicating code for adding the new filter
+                * then deleting the old filter.
+                */
+               if ((vsi->info.pvid && f->vlan != vsi->info.pvid) ||
+                   (vlan_filters && f->vlan == I40E_VLAN_ANY) ||
+                   (!vlan_filters && f->vlan == 0)) {
+                       /* Determine the new vlan we will be adding */
+                       if (vsi->info.pvid)
+                               new_vlan = vsi->info.pvid;
+                       else if (vlan_filters)
+                               new_vlan = 0;
+                       else
+                               new_vlan = I40E_VLAN_ANY;
 
-/**
- * i40e_del_mac_all_vlan - Remove a MAC filter from all VLANS
- * @vsi: the VSI to be searched
- * @macaddr: the mac address to be removed
- * @is_vf: true if it is a VF
- * @is_netdev: true if it is a netdev
- *
- * Removes a given MAC address from a VSI, regardless of VLAN
- *
- * Returns 0 for success, or error
- **/
-int i40e_del_mac_all_vlan(struct i40e_vsi *vsi, u8 *macaddr,
-                         bool is_vf, bool is_netdev)
-{
-       struct i40e_mac_filter *f = NULL;
-       int changed = 0;
+                       /* Create the new filter */
+                       add_head = i40e_add_filter(vsi, f->macaddr, new_vlan);
+                       if (!add_head)
+                               return -ENOMEM;
 
-       WARN(!spin_is_locked(&vsi->mac_filter_list_lock),
-            "Missing mac_filter_list_lock\n");
-       list_for_each_entry(f, &vsi->mac_filter_list, list) {
-               if ((ether_addr_equal(macaddr, f->macaddr)) &&
-                   (is_vf == f->is_vf) &&
-                   (is_netdev == f->is_netdev)) {
-                       f->counter--;
-                       changed = 1;
-                       if (f->counter == 0)
-                               f->state = I40E_FILTER_REMOVE;
+                       /* Put the replacement filter into the add list */
+                       hash_del(&add_head->hlist);
+                       hlist_add_head(&add_head->hlist, tmp_add_list);
+
+                       /* Put the original filter into the delete list */
+                       f->state = I40E_FILTER_REMOVE;
+                       hash_del(&f->hlist);
+                       hlist_add_head(&f->hlist, tmp_del_list);
                }
        }
-       if (changed) {
-               vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED;
-               vsi->back->flags |= I40E_FLAG_FILTER_SYNC;
-               return 0;
-       }
-       return -ENOENT;
+
+       vsi->has_vlan_filter = !!vlan_filters;
+
+       return 0;
 }
 
 /**
@@ -1316,7 +1350,7 @@ static void i40e_rm_default_mac_filter(struct i40e_vsi *vsi, u8 *macaddr)
        element.vlan_tag = 0;
        /* ...and some firmware does it this way. */
        element.flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH |
-                       I40E_AQC_MACVLAN_ADD_IGNORE_VLAN;
+                       I40E_AQC_MACVLAN_DEL_IGNORE_VLAN;
        i40e_aq_remove_macvlan(&pf->hw, vsi->seid, &element, 1, NULL);
 }
 
@@ -1325,36 +1359,32 @@ static void i40e_rm_default_mac_filter(struct i40e_vsi *vsi, u8 *macaddr)
  * @vsi: the VSI to be searched
  * @macaddr: the MAC address
  * @vlan: the vlan
- * @is_vf: make sure its a VF filter, else doesn't matter
- * @is_netdev: make sure its a netdev filter, else doesn't matter
  *
  * 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.
  **/
 struct i40e_mac_filter *i40e_add_filter(struct i40e_vsi *vsi,
-                                       u8 *macaddr, s16 vlan,
-                                       bool is_vf, bool is_netdev)
+                                       const u8 *macaddr, s16 vlan)
 {
        struct i40e_mac_filter *f;
-       int changed = false;
+       u64 key;
 
        if (!vsi || !macaddr)
                return NULL;
 
-       /* Do not allow broadcast filter to be added since broadcast filter
-        * is added as part of add VSI for any newly created VSI except
-        * FDIR VSI
-        */
-       if (is_broadcast_ether_addr(macaddr))
-               return NULL;
-
-       f = i40e_find_filter(vsi, macaddr, vlan, is_vf, is_netdev);
+       f = i40e_find_filter(vsi, macaddr, vlan);
        if (!f) {
                f = kzalloc(sizeof(*f), GFP_ATOMIC);
                if (!f)
-                       goto add_filter_out;
+                       return NULL;
+
+               /* Update the boolean indicating if we need to function in
+                * VLAN mode.
+                */
+               if (vlan >= 0)
+                       vsi->has_vlan_filter = true;
 
                ether_addr_copy(f->macaddr, macaddr);
                f->vlan = vlan;
@@ -1366,100 +1396,148 @@ struct i40e_mac_filter *i40e_add_filter(struct i40e_vsi *vsi,
                        f->state = I40E_FILTER_FAILED;
                else
                        f->state = I40E_FILTER_NEW;
-               changed = true;
-               INIT_LIST_HEAD(&f->list);
-               list_add_tail(&f->list, &vsi->mac_filter_list);
-       }
+               INIT_HLIST_NODE(&f->hlist);
 
-       /* increment counter and add a new flag if needed */
-       if (is_vf) {
-               if (!f->is_vf) {
-                       f->is_vf = true;
-                       f->counter++;
-               }
-       } else if (is_netdev) {
-               if (!f->is_netdev) {
-                       f->is_netdev = true;
-                       f->counter++;
-               }
-       } else {
-               f->counter++;
-       }
+               key = i40e_addr_to_hkey(macaddr);
+               hash_add(vsi->mac_filter_hash, &f->hlist, key);
 
-       if (changed) {
                vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED;
                vsi->back->flags |= I40E_FLAG_FILTER_SYNC;
        }
 
-add_filter_out:
+       /* If we're asked to add a filter that has been marked for removal, it
+        * is safe to simply restore it to active state. __i40e_del_filter
+        * will have simply deleted any filters which were previously marked
+        * NEW or FAILED, so if it is currently marked REMOVE it must have
+        * previously been ACTIVE. Since we haven't yet run the sync filters
+        * task, just restore this filter to the ACTIVE state so that the
+        * sync task leaves it in place
+        */
+       if (f->state == I40E_FILTER_REMOVE)
+               f->state = I40E_FILTER_ACTIVE;
+
        return f;
 }
 
 /**
- * i40e_del_filter - Remove a mac/vlan filter from the VSI
+ * __i40e_del_filter - Remove a specific filter from the VSI
+ * @vsi: VSI to remove from
+ * @f: the filter to remove from the list
+ *
+ * This function should be called instead of i40e_del_filter only if you know
+ * the exact filter you will remove already, such as via i40e_find_filter or
+ * i40e_find_mac.
+ *
+ * NOTE: This function is expected to be called with mac_filter_hash_lock
+ * being held.
+ * 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()
+ * instead of list_for_each_entry().
+ **/
+static void __i40e_del_filter(struct i40e_vsi *vsi, struct i40e_mac_filter *f)
+{
+       if (!f)
+               return;
+
+       if ((f->state == I40E_FILTER_FAILED) ||
+           (f->state == I40E_FILTER_NEW)) {
+               /* this one never got added by the FW. Just remove it,
+                * no need to sync anything.
+                */
+               hash_del(&f->hlist);
+               kfree(f);
+       } else {
+               f->state = I40E_FILTER_REMOVE;
+               vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED;
+               vsi->back->flags |= I40E_FLAG_FILTER_SYNC;
+       }
+}
+
+/**
+ * i40e_del_filter - Remove a MAC/VLAN filter from the VSI
  * @vsi: the VSI to be searched
  * @macaddr: the MAC address
- * @vlan: the vlan
- * @is_vf: make sure it's a VF filter, else doesn't matter
- * @is_netdev: make sure it's a netdev filter, else doesn't matter
+ * @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.
  * 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()
  * instead of list_for_each_entry().
  **/
-void i40e_del_filter(struct i40e_vsi *vsi,
-                    u8 *macaddr, s16 vlan,
-                    bool is_vf, bool is_netdev)
+void i40e_del_filter(struct i40e_vsi *vsi, const u8 *macaddr, s16 vlan)
 {
        struct i40e_mac_filter *f;
 
        if (!vsi || !macaddr)
                return;
 
-       f = i40e_find_filter(vsi, macaddr, vlan, is_vf, is_netdev);
-       if (!f || f->counter == 0)
-               return;
+       f = i40e_find_filter(vsi, macaddr, vlan);
+       __i40e_del_filter(vsi, f);
+}
 
-       if (is_vf) {
-               if (f->is_vf) {
-                       f->is_vf = false;
-                       f->counter--;
-               }
-       } else if (is_netdev) {
-               if (f->is_netdev) {
-                       f->is_netdev = false;
-                       f->counter--;
-               }
-       } else {
-               /* make sure we don't remove a filter in use by VF or netdev */
-               int min_f = 0;
+/**
+ * i40e_put_mac_in_vlan - Make macvlan filters from macaddrs and vlans
+ * @vsi: the VSI to be searched
+ * @macaddr: the mac address to be filtered
+ *
+ * Goes through all the macvlan filters and adds a macvlan filter for each
+ * unique vlan that already exists. If a PVID has been assigned, instead only
+ * add the macaddr to that VLAN.
+ *
+ * Returns last filter added on success, else NULL
+ **/
+struct i40e_mac_filter *i40e_put_mac_in_vlan(struct i40e_vsi *vsi,
+                                            const u8 *macaddr)
+{
+       struct i40e_mac_filter *f, *add = NULL;
+       struct hlist_node *h;
+       int bkt;
 
-               min_f += (f->is_vf ? 1 : 0);
-               min_f += (f->is_netdev ? 1 : 0);
+       if (vsi->info.pvid)
+               return i40e_add_filter(vsi, macaddr,
+                                      le16_to_cpu(vsi->info.pvid));
 
-               if (f->counter > min_f)
-                       f->counter--;
+       hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist) {
+               if (f->state == I40E_FILTER_REMOVE)
+                       continue;
+               add = i40e_add_filter(vsi, macaddr, f->vlan);
+               if (!add)
+                       return NULL;
        }
 
-       /* counter == 0 tells sync_filters_subtask to
-        * remove the filter from the firmware's list
-        */
-       if (f->counter == 0) {
-               if ((f->state == I40E_FILTER_FAILED) ||
-                   (f->state == I40E_FILTER_NEW)) {
-                       /* this one never got added by the FW. Just remove it,
-                        * no need to sync anything.
-                        */
-                       list_del(&f->list);
-                       kfree(f);
-               } else {
-                       f->state = I40E_FILTER_REMOVE;
-                       vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED;
-                       vsi->back->flags |= I40E_FLAG_FILTER_SYNC;
+       return add;
+}
+
+/**
+ * i40e_del_mac_all_vlan - Remove a MAC filter from all VLANS
+ * @vsi: the VSI to be searched
+ * @macaddr: the mac address to be removed
+ *
+ * Removes a given MAC address from a VSI, regardless of VLAN
+ *
+ * Returns 0 for success, or error
+ **/
+int i40e_del_mac_all_vlan(struct i40e_vsi *vsi, const u8 *macaddr)
+{
+       struct i40e_mac_filter *f;
+       struct hlist_node *h;
+       bool found = false;
+       int bkt;
+
+       WARN(!spin_is_locked(&vsi->mac_filter_hash_lock),
+            "Missing mac_filter_hash_lock\n");
+       hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist) {
+               if (ether_addr_equal(macaddr, f->macaddr)) {
+                       __i40e_del_filter(vsi, f);
+                       found = true;
                }
        }
+
+       if (found)
+               return 0;
+       else
+               return -ENOENT;
 }
 
 /**
@@ -1500,10 +1578,10 @@ static int i40e_set_mac(struct net_device *netdev, void *p)
        else
                netdev_info(netdev, "set new mac address %pM\n", addr->sa_data);
 
-       spin_lock_bh(&vsi->mac_filter_list_lock);
-       i40e_del_mac_all_vlan(vsi, netdev->dev_addr, false, true);
-       i40e_put_mac_in_vlan(vsi, addr->sa_data, false, true);
-       spin_unlock_bh(&vsi->mac_filter_list_lock);
+       spin_lock_bh(&vsi->mac_filter_hash_lock);
+       i40e_del_mac_all_vlan(vsi, netdev->dev_addr);
+       i40e_put_mac_in_vlan(vsi, addr->sa_data);
+       spin_unlock_bh(&vsi->mac_filter_hash_lock);
        ether_addr_copy(netdev->dev_addr, addr->sa_data);
        if (vsi->type == I40E_VSI_MAIN) {
                i40e_status ret;
@@ -1666,6 +1744,52 @@ static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi,
        ctxt->info.valid_sections |= cpu_to_le16(sections);
 }
 
+/**
+ * i40e_addr_sync - Callback for dev_(mc|uc)_sync to add address
+ * @netdev: the netdevice
+ * @addr: address to add
+ *
+ * Called by __dev_(mc|uc)_sync when an address needs to be added. We call
+ * __dev_(uc|mc)_sync from .set_rx_mode and guarantee to hold the hash lock.
+ */
+static int i40e_addr_sync(struct net_device *netdev, const u8 *addr)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_vsi *vsi = np->vsi;
+       struct i40e_mac_filter *f;
+
+       if (i40e_is_vsi_in_vlan(vsi))
+               f = i40e_put_mac_in_vlan(vsi, addr);
+       else
+               f = i40e_add_filter(vsi, addr, I40E_VLAN_ANY);
+
+       if (f)
+               return 0;
+       else
+               return -ENOMEM;
+}
+
+/**
+ * i40e_addr_unsync - Callback for dev_(mc|uc)_sync to remove address
+ * @netdev: the netdevice
+ * @addr: address to add
+ *
+ * Called by __dev_(mc|uc)_sync when an address needs to be removed. We call
+ * __dev_(uc|mc)_sync from .set_rx_mode and guarantee to hold the hash lock.
+ */
+static int i40e_addr_unsync(struct net_device *netdev, const u8 *addr)
+{
+       struct i40e_netdev_priv *np = netdev_priv(netdev);
+       struct i40e_vsi *vsi = np->vsi;
+
+       if (i40e_is_vsi_in_vlan(vsi))
+               i40e_del_mac_all_vlan(vsi, addr);
+       else
+               i40e_del_filter(vsi, addr, I40E_VLAN_ANY);
+
+       return 0;
+}
+
 /**
  * i40e_set_rx_mode - NDO callback to set the netdev filters
  * @netdev: network interface device structure
@@ -1677,62 +1801,14 @@ static void i40e_set_rx_mode(struct net_device *netdev)
 #endif
 {
        struct i40e_netdev_priv *np = netdev_priv(netdev);
-       struct i40e_mac_filter *f, *ftmp;
        struct i40e_vsi *vsi = np->vsi;
-       struct netdev_hw_addr *uca;
-       struct netdev_hw_addr *mca;
-       struct netdev_hw_addr *ha;
-
-       spin_lock_bh(&vsi->mac_filter_list_lock);
-
-       /* add addr if not already in the filter list */
-       netdev_for_each_uc_addr(uca, netdev) {
-               if (!i40e_find_mac(vsi, uca->addr, false, true)) {
-                       if (i40e_is_vsi_in_vlan(vsi))
-                               i40e_put_mac_in_vlan(vsi, uca->addr,
-                                                    false, true);
-                       else
-                               i40e_add_filter(vsi, uca->addr, I40E_VLAN_ANY,
-                                               false, true);
-               }
-       }
 
-       netdev_for_each_mc_addr(mca, netdev) {
-               if (!i40e_find_mac(vsi, mca->addr, false, true)) {
-                       if (i40e_is_vsi_in_vlan(vsi))
-                               i40e_put_mac_in_vlan(vsi, mca->addr,
-                                                    false, true);
-                       else
-                               i40e_add_filter(vsi, mca->addr, I40E_VLAN_ANY,
-                                               false, true);
-               }
-       }
+       spin_lock_bh(&vsi->mac_filter_hash_lock);
 
-       /* remove filter if not in netdev list */
-       list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list) {
+       __dev_uc_sync(netdev, i40e_addr_sync, i40e_addr_unsync);
+       __dev_mc_sync(netdev, i40e_addr_sync, i40e_addr_unsync);
 
-               if (!f->is_netdev)
-                       continue;
-
-               netdev_for_each_mc_addr(mca, netdev)
-                       if (ether_addr_equal(mca->addr, f->macaddr))
-                               goto bottom_of_search_loop;
-
-               netdev_for_each_uc_addr(uca, netdev)
-                       if (ether_addr_equal(uca->addr, f->macaddr))
-                               goto bottom_of_search_loop;
-
-               for_each_dev_addr(netdev, ha)
-                       if (ether_addr_equal(ha->addr, f->macaddr))
-                               goto bottom_of_search_loop;
-
-               /* f->macaddr wasn't found in uc, mc, or ha list so delete it */
-               i40e_del_filter(vsi, f->macaddr, I40E_VLAN_ANY, false, true);
-
-bottom_of_search_loop:
-               continue;
-       }
-       spin_unlock_bh(&vsi->mac_filter_list_lock);
+       spin_unlock_bh(&vsi->mac_filter_hash_lock);
 
        /* check for other flag changes */
        if (vsi->current_netdev_flags != vsi->netdev->flags) {
@@ -1747,21 +1823,26 @@ bottom_of_search_loop:
 }
 
 /**
- * i40e_undo_del_filter_entries - Undo the changes made to MAC filter entries
- * @vsi: pointer to vsi struct
+ * i40e_undo_filter_entries - Undo the changes made to MAC filter entries
+ * @vsi: Pointer to VSI struct
  * @from: Pointer to list which contains MAC filter entries - changes to
  *        those entries needs to be undone.
  *
- * MAC filter entries from list were slated to be removed from device.
+ * MAC filter entries from list were slated to be sent to firmware, either for
+ * addition or deletion.
  **/
-static void i40e_undo_del_filter_entries(struct i40e_vsi *vsi,
-                                        struct list_head *from)
+static void i40e_undo_filter_entries(struct i40e_vsi *vsi,
+                                    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*/
-               list_move_tail(&f->list, &vsi->mac_filter_list);
+               hlist_del(&f->hlist);
+               hash_add(vsi->mac_filter_hash, &f->hlist, key);
        }
 }
 
@@ -1771,7 +1852,6 @@ static void i40e_undo_del_filter_entries(struct i40e_vsi *vsi,
  * @count: Number of filters added
  * @add_list: return data from fw
  * @head: pointer to first filter in current batch
- * @aq_err: status from fw
  *
  * MAC filter entries from list were slated to be added to device. Returns
  * number of successful filters. Note that 0 does NOT mean success!
@@ -1779,44 +1859,145 @@ static void i40e_undo_del_filter_entries(struct i40e_vsi *vsi,
 static int
 i40e_update_filter_state(int count,
                         struct i40e_aqc_add_macvlan_element_data *add_list,
-                        struct i40e_mac_filter *add_head, int aq_err)
+                        struct i40e_mac_filter *add_head)
 {
        int retval = 0;
        int i;
 
-
-       if (!aq_err) {
-               retval = count;
-               /* Everything's good, mark all filters active. */
-               for (i = 0; i < count ; i++) {
-                       add_head->state = I40E_FILTER_ACTIVE;
-                       add_head = list_next_entry(add_head, list);
-               }
-       } else if (aq_err == I40E_AQ_RC_ENOSPC) {
-               /* Device ran out of filter space. Check the return value
-                * for each filter to see which ones are active.
+       for (i = 0; i < count; i++) {
+               /* Always check status of each filter. We don't need to check
+                * the firmware return status because we pre-set the filter
+                * status to I40E_AQC_MM_ERR_NO_RES when sending the filter
+                * request to the adminq. Thus, if it no longer matches then
+                * we know the filter is active.
                 */
-               for (i = 0; i < count ; i++) {
-                       if (add_list[i].match_method ==
-                           I40E_AQC_MM_ERR_NO_RES) {
-                               add_head->state = I40E_FILTER_FAILED;
-                       } else {
-                               add_head->state = I40E_FILTER_ACTIVE;
-                               retval++;
-                       }
-                       add_head = list_next_entry(add_head, list);
-               }
-       } else {
-               /* Some other horrible thing happened, fail all filters */
-               retval = 0;
-               for (i = 0; i < count ; i++) {
+               if (add_list[i].match_method == I40E_AQC_MM_ERR_NO_RES) {
                        add_head->state = I40E_FILTER_FAILED;
-                       add_head = list_next_entry(add_head, list);
+               } else {
+                       add_head->state = I40E_FILTER_ACTIVE;
+                       retval++;
                }
+
+               add_head = hlist_entry(add_head->hlist.next,
+                                      typeof(struct i40e_mac_filter),
+                                      hlist);
        }
+
        return retval;
 }
 
+/**
+ * i40e_aqc_del_filters - Request firmware to delete a set of filters
+ * @vsi: ptr to the VSI
+ * @vsi_name: name to display in messages
+ * @list: the list of filters to send to firmware
+ * @num_del: the number of filters to delete
+ * @retval: Set to -EIO on failure to delete
+ *
+ * Send a request to firmware via AdminQ to delete a set of filters. Uses
+ * *retval instead of a return value so that success does not force ret_val to
+ * be set to 0. This ensures that a sequence of calls to this function
+ * preserve the previous value of *retval on successful delete.
+ */
+static
+void i40e_aqc_del_filters(struct i40e_vsi *vsi, const char *vsi_name,
+                         struct i40e_aqc_remove_macvlan_element_data *list,
+                         int num_del, int *retval)
+{
+       struct i40e_hw *hw = &vsi->back->hw;
+       i40e_status aq_ret;
+       int aq_err;
+
+       aq_ret = i40e_aq_remove_macvlan(hw, vsi->seid, list, num_del, NULL);
+       aq_err = hw->aq.asq_last_status;
+
+       /* Explicitly ignore and do not report when firmware returns ENOENT */
+       if (aq_ret && !(aq_err == I40E_AQ_RC_ENOENT)) {
+               *retval = -EIO;
+               dev_info(&vsi->back->pdev->dev,
+                        "ignoring delete macvlan error on %s, err %s, aq_err %s\n",
+                        vsi_name, i40e_stat_str(hw, aq_ret),
+                        i40e_aq_str(hw, aq_err));
+       }
+}
+
+/**
+ * i40e_aqc_add_filters - Request firmware to add a set of filters
+ * @vsi: ptr to the VSI
+ * @vsi_name: name to display in messages
+ * @list: the list of filters to send to firmware
+ * @add_head: Position in the add hlist
+ * @num_add: the number of filters to add
+ * @promisc_change: set to true on exit if promiscuous mode was forced on
+ *
+ * Send a request to firmware via AdminQ to add a chunk of filters. Will set
+ * promisc_changed to true if the firmware has run out of space for more
+ * filters.
+ */
+static
+void i40e_aqc_add_filters(struct i40e_vsi *vsi, const char *vsi_name,
+                         struct i40e_aqc_add_macvlan_element_data *list,
+                         struct i40e_mac_filter *add_head,
+                         int num_add, bool *promisc_changed)
+{
+       struct i40e_hw *hw = &vsi->back->hw;
+       int aq_err, fcnt;
+
+       i40e_aq_add_macvlan(hw, vsi->seid, list, num_add, NULL);
+       aq_err = hw->aq.asq_last_status;
+       fcnt = i40e_update_filter_state(num_add, list, add_head);
+
+       if (fcnt != num_add) {
+               *promisc_changed = true;
+               set_bit(__I40E_FILTER_OVERFLOW_PROMISC, &vsi->state);
+               dev_warn(&vsi->back->pdev->dev,
+                        "Error %s adding RX filters on %s, promiscuous mode forced on\n",
+                        i40e_aq_str(hw, aq_err),
+                        vsi_name);
+       }
+}
+
+/**
+ * i40e_aqc_broadcast_filter - Set promiscuous broadcast flags
+ * @vsi: pointer to the VSI
+ * @f: filter data
+ *
+ * This function sets or clears the promiscuous broadcast flags for VLAN
+ * filters in order to properly receive broadcast frames. Assumes that only
+ * broadcast filters are passed.
+ **/
+static
+void i40e_aqc_broadcast_filter(struct i40e_vsi *vsi, const char *vsi_name,
+                              struct i40e_mac_filter *f)
+{
+       bool enable = f->state == I40E_FILTER_NEW;
+       struct i40e_hw *hw = &vsi->back->hw;
+       i40e_status aq_ret;
+
+       if (f->vlan == I40E_VLAN_ANY) {
+               aq_ret = i40e_aq_set_vsi_broadcast(hw,
+                                                  vsi->seid,
+                                                  enable,
+                                                  NULL);
+       } else {
+               aq_ret = i40e_aq_set_vsi_bc_promisc_on_vlan(hw,
+                                                           vsi->seid,
+                                                           enable,
+                                                           f->vlan,
+                                                           NULL);
+       }
+
+       if (aq_ret) {
+               dev_warn(&vsi->back->pdev->dev,
+                        "Error %s setting broadcast promiscuous mode on %s\n",
+                        i40e_aq_str(hw, hw->aq.asq_last_status),
+                        vsi_name);
+               f->state = I40E_FILTER_FAILED;
+       } else if (enable) {
+               f->state = I40E_FILTER_ACTIVE;
+       }
+}
+
 /**
  * i40e_sync_vsi_filters - Update the VSI filter list to the HW
  * @vsi: ptr to the VSI
@@ -1827,22 +2008,24 @@ i40e_update_filter_state(int count,
  **/
 int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
 {
-       struct i40e_mac_filter *f, *ftmp, *add_head = NULL;
-       struct list_head tmp_add_list, tmp_del_list;
+       struct hlist_head tmp_add_list, tmp_del_list;
+       struct i40e_mac_filter *f, *add_head = NULL;
        struct i40e_hw *hw = &vsi->back->hw;
+       unsigned int failed_filters = 0;
+       unsigned int vlan_filters = 0;
        bool promisc_changed = false;
        char vsi_name[16] = "PF";
        int filter_list_len = 0;
-       u32 changed_flags = 0;
        i40e_status aq_ret = 0;
-       int retval = 0;
+       u32 changed_flags = 0;
+       struct hlist_node *h;
        struct i40e_pf *pf;
        int num_add = 0;
        int num_del = 0;
-       int aq_err = 0;
+       int retval = 0;
        u16 cmd_flags;
        int list_size;
-       int fcnt;
+       int bkt;
 
        /* empty array typed pointers, kcalloc later */
        struct i40e_aqc_add_macvlan_element_data *add_list;
@@ -1857,8 +2040,8 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
                vsi->current_netdev_flags = vsi->netdev->flags;
        }
 
-       INIT_LIST_HEAD(&tmp_add_list);
-       INIT_LIST_HEAD(&tmp_del_list);
+       INIT_HLIST_HEAD(&tmp_add_list);
+       INIT_HLIST_HEAD(&tmp_del_list);
 
        if (vsi->type == I40E_VSI_SRIOV)
                snprintf(vsi_name, sizeof(vsi_name) - 1, "VF %d", vsi->vf_id);
@@ -1868,48 +2051,69 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
        if (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. */
-               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) {
-                               WARN_ON(f->counter != 0);
                                /* Move the element into temporary del_list */
-                               list_move_tail(&f->list, &tmp_del_list);
-                               vsi->active_filters--;
+                               hash_del(&f->hlist);
+                               hlist_add_head(&f->hlist, &tmp_del_list);
+
+                               /* Avoid counting removed filters */
+                               continue;
                        }
                        if (f->state == I40E_FILTER_NEW) {
-                               WARN_ON(f->counter == 0);
-                               /* Move the element into temporary add_list */
-                               list_move_tail(&f->list, &tmp_add_list);
+                               hash_del(&f->hlist);
+                               hlist_add_head(&f->hlist, &tmp_add_list);
                        }
+
+                       /* Count the number of active (current and new) VLAN
+                        * filters we have now. Does not count filters which
+                        * are marked for deletion.
+                        */
+                       if (f->vlan > 0)
+                               vlan_filters++;
                }
-               spin_unlock_bh(&vsi->mac_filter_list_lock);
+
+               retval = i40e_correct_mac_vlan_filters(vsi,
+                                                      &tmp_add_list,
+                                                      &tmp_del_list,
+                                                      vlan_filters);
+               if (retval)
+                       goto err_no_memory_locked;
+
+               spin_unlock_bh(&vsi->mac_filter_hash_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 /
                            sizeof(struct i40e_aqc_remove_macvlan_element_data);
                list_size = filter_list_len *
                            sizeof(struct i40e_aqc_remove_macvlan_element_data);
                del_list = kzalloc(list_size, GFP_ATOMIC);
-               if (!del_list) {
-                       /* Undo VSI's MAC filter entry element updates */
-                       spin_lock_bh(&vsi->mac_filter_list_lock);
-                       i40e_undo_del_filter_entries(vsi, &tmp_del_list);
-                       spin_unlock_bh(&vsi->mac_filter_list_lock);
-                       retval = -ENOMEM;
-                       goto out;
-               }
+               if (!del_list)
+                       goto err_no_memory;
 
-               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;
 
+                       /* handle broadcast filters by updating the broadcast
+                        * promiscuous flag instead of deleting a MAC filter.
+                        */
+                       if (is_broadcast_ether_addr(f->macaddr)) {
+                               i40e_aqc_broadcast_filter(vsi, vsi_name, f);
+
+                               hlist_del(&f->hlist);
+                               kfree(f);
+                               continue;
+                       }
+
                        /* add to delete list */
                        ether_addr_copy(del_list[num_del].mac_addr, f->macaddr);
                        if (f->vlan == I40E_VLAN_ANY) {
                                del_list[num_del].vlan_tag = 0;
-                               cmd_flags |= I40E_AQC_MACVLAN_ADD_IGNORE_VLAN;
+                               cmd_flags |= I40E_AQC_MACVLAN_DEL_IGNORE_VLAN;
                        } else {
                                del_list[num_del].vlan_tag =
                                        cpu_to_le16((u16)(f->vlan));
@@ -1921,73 +2125,57 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
 
                        /* flush a full buffer */
                        if (num_del == filter_list_len) {
-                               aq_ret = i40e_aq_remove_macvlan(hw, vsi->seid,
-                                                               del_list,
-                                                               num_del, NULL);
-                               aq_err = hw->aq.asq_last_status;
-                               num_del = 0;
+                               i40e_aqc_del_filters(vsi, vsi_name, del_list,
+                                                    num_del, &retval);
                                memset(del_list, 0, list_size);
-
-                               /* Explicitly ignore and do not report when
-                                * firmware returns ENOENT.
-                                */
-                               if (aq_ret && !(aq_err == I40E_AQ_RC_ENOENT)) {
-                                       retval = -EIO;
-                                       dev_info(&pf->pdev->dev,
-                                                "ignoring delete macvlan error on %s, err %s, aq_err %s\n",
-                                                vsi_name,
-                                                i40e_stat_str(hw, aq_ret),
-                                                i40e_aq_str(hw, aq_err));
-                               }
+                               num_del = 0;
                        }
                        /* Release memory for MAC filter entries which were
                         * synced up with HW.
                         */
-                       list_del(&f->list);
+                       hlist_del(&f->hlist);
                        kfree(f);
                }
 
                if (num_del) {
-                       aq_ret = i40e_aq_remove_macvlan(hw, vsi->seid, del_list,
-                                                       num_del, NULL);
-                       aq_err = hw->aq.asq_last_status;
-                       num_del = 0;
-
-                       /* Explicitly ignore and do not report when firmware
-                        * returns ENOENT.
-                        */
-                       if (aq_ret && !(aq_err == I40E_AQ_RC_ENOENT)) {
-                               retval = -EIO;
-                               dev_info(&pf->pdev->dev,
-                                        "ignoring delete macvlan error on %s, err %s aq_err %s\n",
-                                        vsi_name,
-                                        i40e_stat_str(hw, aq_ret),
-                                        i40e_aq_str(hw, aq_err));
-                       }
+                       i40e_aqc_del_filters(vsi, vsi_name, del_list,
+                                            num_del, &retval);
                }
 
                kfree(del_list);
                del_list = NULL;
        }
 
-       if (!list_empty(&tmp_add_list)) {
+       if (!hlist_empty(&tmp_add_list)) {
                /* Do all the adds now. */
                filter_list_len = hw->aq.asq_buf_size /
                               sizeof(struct i40e_aqc_add_macvlan_element_data);
                list_size = filter_list_len *
                               sizeof(struct i40e_aqc_add_macvlan_element_data);
                add_list = kzalloc(list_size, GFP_ATOMIC);
-               if (!add_list) {
-                       retval = -ENOMEM;
-                       goto out;
-               }
+               if (!add_list)
+                       goto err_no_memory;
+
                num_add = 0;
-               list_for_each_entry(f, &tmp_add_list, list) {
+               hlist_for_each_entry_safe(f, h, &tmp_add_list, hlist) {
                        if (test_bit(__I40E_FILTER_OVERFLOW_PROMISC,
                                     &vsi->state)) {
                                f->state = I40E_FILTER_FAILED;
                                continue;
                        }
+
+                       /* handle broadcast filters by updating the broadcast
+                        * promiscuous flag instead of adding a MAC filter.
+                        */
+                       if (is_broadcast_ether_addr(f->macaddr)) {
+                               u64 key = i40e_addr_to_hkey(f->macaddr);
+                               i40e_aqc_broadcast_filter(vsi, vsi_name, f);
+
+                               hlist_del(&f->hlist);
+                               hash_add(vsi->mac_filter_hash, &f->hlist, key);
+                               continue;
+                       }
+
                        /* add to add array */
                        if (num_add == 0)
                                add_head = f;
@@ -2001,88 +2189,70 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
                                        cpu_to_le16((u16)(f->vlan));
                        }
                        add_list[num_add].queue_number = 0;
+                       /* set invalid match method for later detection */
+                       add_list[num_add].match_method = I40E_AQC_MM_ERR_NO_RES;
                        cmd_flags |= I40E_AQC_MACVLAN_ADD_PERFECT_MATCH;
                        add_list[num_add].flags = cpu_to_le16(cmd_flags);
                        num_add++;
 
                        /* flush a full buffer */
                        if (num_add == filter_list_len) {
-                               aq_ret = i40e_aq_add_macvlan(hw, vsi->seid,
-                                                            add_list, num_add,
-                                                            NULL);
-                               aq_err = hw->aq.asq_last_status;
-                               fcnt = i40e_update_filter_state(num_add,
-                                                               add_list,
-                                                               add_head,
-                                                               aq_ret);
-                               vsi->active_filters += fcnt;
-
-                               if (fcnt != num_add) {
-                                       promisc_changed = true;
-                                       set_bit(__I40E_FILTER_OVERFLOW_PROMISC,
-                                               &vsi->state);
-                                       vsi->promisc_threshold =
-                                               (vsi->active_filters * 3) / 4;
-                                       dev_warn(&pf->pdev->dev,
-                                                "Error %s adding RX filters on %s, promiscuous mode forced on\n",
-                                                i40e_aq_str(hw, aq_err),
-                                                vsi_name);
-                               }
+                               i40e_aqc_add_filters(vsi, vsi_name, add_list,
+                                                    add_head, num_add,
+                                                    &promisc_changed);
                                memset(add_list, 0, list_size);
                                num_add = 0;
                        }
                }
                if (num_add) {
-                       aq_ret = i40e_aq_add_macvlan(hw, vsi->seid,
-                                                    add_list, num_add, NULL);
-                       aq_err = hw->aq.asq_last_status;
-                       fcnt = i40e_update_filter_state(num_add, add_list,
-                                                       add_head, aq_ret);
-                       vsi->active_filters += fcnt;
-                       if (fcnt != num_add) {
-                               promisc_changed = true;
-                               set_bit(__I40E_FILTER_OVERFLOW_PROMISC,
-                                       &vsi->state);
-                               vsi->promisc_threshold =
-                                               (vsi->active_filters * 3) / 4;
-                               dev_warn(&pf->pdev->dev,
-                                        "Error %s adding RX filters on %s, promiscuous mode forced on\n",
-                                        i40e_aq_str(hw, aq_err), vsi_name);
-                       }
+                       i40e_aqc_add_filters(vsi, vsi_name, add_list, add_head,
+                                            num_add, &promisc_changed);
                }
                /* Now move all of the filters from the temp add list back to
                 * the VSI's list.
                 */
-               spin_lock_bh(&vsi->mac_filter_list_lock);
-               list_for_each_entry_safe(f, ftmp, &tmp_add_list, list) {
-                       list_move_tail(&f->list, &vsi->mac_filter_list);
+               spin_lock_bh(&vsi->mac_filter_hash_lock);
+               hlist_for_each_entry_safe(f, h, &tmp_add_list, hlist) {
+                       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);
                add_list = NULL;
        }
 
-       /* Check to see if we can drop out of overflow promiscuous mode. */
+       /* Determine the number of active and failed filters. */
+       spin_lock_bh(&vsi->mac_filter_hash_lock);
+       vsi->active_filters = 0;
+       hash_for_each(vsi->mac_filter_hash, bkt, f, hlist) {
+               if (f->state == I40E_FILTER_ACTIVE)
+                       vsi->active_filters++;
+               else if (f->state == I40E_FILTER_FAILED)
+                       failed_filters++;
+       }
+       spin_unlock_bh(&vsi->mac_filter_hash_lock);
+
+       /* If promiscuous mode has changed, we need to calculate a new
+        * threshold for when we are safe to exit
+        */
+       if (promisc_changed)
+               vsi->promisc_threshold = (vsi->active_filters * 3) / 4;
+
+       /* Check if we are able to exit overflow promiscuous mode. We can
+        * safely exit if we didn't just enter, we no longer have any failed
+        * filters, and we have reduced filters below the threshold value.
+        */
        if (test_bit(__I40E_FILTER_OVERFLOW_PROMISC, &vsi->state) &&
+           !promisc_changed && !failed_filters &&
            (vsi->active_filters < vsi->promisc_threshold)) {
-               int failed_count = 0;
-               /* See if we have any failed filters. We can't drop out of
-                * promiscuous until these have all been deleted.
-                */
-               spin_lock_bh(&vsi->mac_filter_list_lock);
-               list_for_each_entry(f, &vsi->mac_filter_list, list) {
-                       if (f->state == I40E_FILTER_FAILED)
-                               failed_count++;
-               }
-               spin_unlock_bh(&vsi->mac_filter_list_lock);
-               if (!failed_count) {
-                       dev_info(&pf->pdev->dev,
-                                "filter logjam cleared on %s, leaving overflow promiscuous mode\n",
-                                vsi_name);
-                       clear_bit(__I40E_FILTER_OVERFLOW_PROMISC, &vsi->state);
-                       promisc_changed = true;
-                       vsi->promisc_threshold = 0;
-               }
+               dev_info(&pf->pdev->dev,
+                        "filter logjam cleared on %s, leaving overflow promiscuous mode\n",
+                        vsi_name);
+               clear_bit(__I40E_FILTER_OVERFLOW_PROMISC, &vsi->state);
+               promisc_changed = true;
+               vsi->promisc_threshold = 0;
        }
 
        /* if the VF is not trusted do not do promisc */
@@ -2202,6 +2372,18 @@ out:
 
        clear_bit(__I40E_CONFIG_BUSY, &vsi->state);
        return retval;
+
+err_no_memory:
+       /* Restore elements on the temporary add and delete lists */
+       spin_lock_bh(&vsi->mac_filter_hash_lock);
+err_no_memory_locked:
+       i40e_undo_filter_entries(vsi, &tmp_del_list);
+       i40e_undo_filter_entries(vsi, &tmp_add_list);
+       spin_unlock_bh(&vsi->mac_filter_hash_lock);
+
+       vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED;
+       clear_bit(__I40E_CONFIG_BUSY, &vsi->state);
+       return -ENOMEM;
 }
 
 /**
@@ -2240,13 +2422,8 @@ static void i40e_sync_filters_subtask(struct i40e_pf *pf)
 static int i40e_change_mtu(struct net_device *netdev, int new_mtu)
 {
        struct i40e_netdev_priv *np = netdev_priv(netdev);
-       int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;
        struct i40e_vsi *vsi = np->vsi;
 
-       /* MTU < 68 is an error and causes problems on some kernels */
-       if ((new_mtu < 68) || (max_frame > I40E_MAX_RXBUFFER))
-               return -EINVAL;
-
        netdev_info(netdev, "changing MTU from %d to %d\n",
                    netdev->mtu, new_mtu);
        netdev->mtu = new_mtu;
@@ -2355,88 +2532,54 @@ static void i40e_vlan_rx_register(struct net_device *netdev, u32 features)
 }
 
 /**
- * i40e_vsi_add_vlan - Add vsi membership for given vlan
+ * i40e_add_vlan_all_mac - Add a MAC/VLAN filter for each existing MAC address
  * @vsi: the vsi being configured
  * @vid: vlan id to be added (0 = untagged only , -1 = any)
+ *
+ * This is a helper function for adding a new MAC/VLAN filter with the
+ * specified VLAN for each existing MAC address already in the hash table.
+ * This function does *not* perform any accounting to update filters based on
+ * VLAN mode.
+ *
+ * NOTE: this function expects to be called while under the
+ * mac_filter_hash_lock
  **/
-int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid)
+int i40e_add_vlan_all_mac(struct i40e_vsi *vsi, s16 vid)
 {
-       struct i40e_mac_filter *f, *ftmp, *add_f;
-       bool is_netdev, is_vf;
-
-       is_vf = (vsi->type == I40E_VSI_SRIOV);
-       is_netdev = !!(vsi->netdev);
+       struct i40e_mac_filter *f, *add_f;
+       struct hlist_node *h;
+       int bkt;
 
-       /* Locked once because all functions invoked below iterates list*/
-       spin_lock_bh(&vsi->mac_filter_list_lock);
-
-       if (is_netdev) {
-               add_f = i40e_add_filter(vsi, vsi->netdev->dev_addr, vid,
-                                       is_vf, is_netdev);
-               if (!add_f) {
-                       dev_info(&vsi->back->pdev->dev,
-                                "Could not add vlan filter %d for %pM\n",
-                                vid, vsi->netdev->dev_addr);
-                       spin_unlock_bh(&vsi->mac_filter_list_lock);
-                       return -ENOMEM;
-               }
-       }
-
-       list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list) {
-               add_f = i40e_add_filter(vsi, f->macaddr, vid, is_vf, is_netdev);
+       hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist) {
+               if (f->state == I40E_FILTER_REMOVE)
+                       continue;
+               add_f = i40e_add_filter(vsi, f->macaddr, vid);
                if (!add_f) {
                        dev_info(&vsi->back->pdev->dev,
                                 "Could not add vlan filter %d for %pM\n",
                                 vid, f->macaddr);
-                       spin_unlock_bh(&vsi->mac_filter_list_lock);
                        return -ENOMEM;
                }
        }
 
-       /* Now if we add a vlan tag, make sure to check if it is the first
-        * tag (i.e. a "tag" -1 does exist) and if so replace the -1 "tag"
-        * with 0, so we now accept untagged and specified tagged traffic
-        * (and not all tags along with untagged)
-        */
-       if (vid > 0) {
-               if (is_netdev && i40e_find_filter(vsi, vsi->netdev->dev_addr,
-                                                 I40E_VLAN_ANY,
-                                                 is_vf, is_netdev)) {
-                       i40e_del_filter(vsi, vsi->netdev->dev_addr,
-                                       I40E_VLAN_ANY, is_vf, is_netdev);
-                       add_f = i40e_add_filter(vsi, vsi->netdev->dev_addr, 0,
-                                               is_vf, is_netdev);
-                       if (!add_f) {
-                               dev_info(&vsi->back->pdev->dev,
-                                        "Could not add filter 0 for %pM\n",
-                                        vsi->netdev->dev_addr);
-                               spin_unlock_bh(&vsi->mac_filter_list_lock);
-                               return -ENOMEM;
-                       }
-               }
-       }
+       return 0;
+}
 
-       /* Do not assume that I40E_VLAN_ANY should be reset to VLAN 0 */
-       if (vid > 0 && !vsi->info.pvid) {
-               list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list) {
-                       if (!i40e_find_filter(vsi, f->macaddr, I40E_VLAN_ANY,
-                                             is_vf, is_netdev))
-                               continue;
-                       i40e_del_filter(vsi, f->macaddr, I40E_VLAN_ANY,
-                                       is_vf, is_netdev);
-                       add_f = i40e_add_filter(vsi, f->macaddr,
-                                               0, is_vf, is_netdev);
-                       if (!add_f) {
-                               dev_info(&vsi->back->pdev->dev,
-                                        "Could not add filter 0 for %pM\n",
-                                       f->macaddr);
-                               spin_unlock_bh(&vsi->mac_filter_list_lock);
-                               return -ENOMEM;
-                       }
-               }
-       }
+/**
+ * i40e_vsi_add_vlan - Add VSI membership for given VLAN
+ * @vsi: the VSI being configured
+ * @vid: VLAN id to be added (0 = untagged only , -1 = any)
+ **/
+int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid)
+{
+       int err;
 
-       spin_unlock_bh(&vsi->mac_filter_list_lock);
+       /* Locked once because all functions invoked below iterates list*/
+       spin_lock_bh(&vsi->mac_filter_hash_lock);
+       err = i40e_add_vlan_all_mac(vsi, vid);
+       spin_unlock_bh(&vsi->mac_filter_hash_lock);
+       if (err)
+               return err;
 
        /* schedule our worker thread which will take care of
         * applying the new filter changes
@@ -2446,82 +2589,45 @@ int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid)
 }
 
 /**
- * i40e_vsi_kill_vlan - Remove vsi membership for given vlan
+ * i40e_rm_vlan_all_mac - Remove MAC/VLAN pair for all MAC with the given VLAN
  * @vsi: the vsi being configured
  * @vid: vlan id to be removed (0 = untagged only , -1 = any)
  *
- * Return: 0 on success or negative otherwise
- **/
-int i40e_vsi_kill_vlan(struct i40e_vsi *vsi, s16 vid)
+ * This function should be used to remove all VLAN filters which match the
+ * given VID. It does not schedule the service event and does not take the
+ * mac_filter_hash_lock so it may be combined with other operations under
+ * a single invocation of the mac_filter_hash_lock.
+ *
+ * NOTE: this function expects to be called while under the
+ * mac_filter_hash_lock
+ */
+void i40e_rm_vlan_all_mac(struct i40e_vsi *vsi, s16 vid)
 {
-       struct net_device *netdev = vsi->netdev;
-       struct i40e_mac_filter *f, *ftmp, *add_f;
-       bool is_vf, is_netdev;
-       int filter_count = 0;
-
-       is_vf = (vsi->type == I40E_VSI_SRIOV);
-       is_netdev = !!(netdev);
-
-       /* Locked once because all functions invoked below iterates list */
-       spin_lock_bh(&vsi->mac_filter_list_lock);
-
-       if (is_netdev)
-               i40e_del_filter(vsi, netdev->dev_addr, vid, is_vf, is_netdev);
-
-       list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list)
-               i40e_del_filter(vsi, f->macaddr, vid, is_vf, is_netdev);
-
-       /* go through all the filters for this VSI and if there is only
-        * vid == 0 it means there are no other filters, so vid 0 must
-        * be replaced with -1. This signifies that we should from now
-        * on accept any traffic (with any tag present, or untagged)
-        */
-       list_for_each_entry(f, &vsi->mac_filter_list, list) {
-               if (is_netdev) {
-                       if (f->vlan &&
-                           ether_addr_equal(netdev->dev_addr, f->macaddr))
-                               filter_count++;
-               }
-
-               if (f->vlan)
-                       filter_count++;
-       }
+       struct i40e_mac_filter *f;
+       struct hlist_node *h;
+       int bkt;
 
-       if (!filter_count && is_netdev) {
-               i40e_del_filter(vsi, netdev->dev_addr, 0, is_vf, is_netdev);
-               f = i40e_add_filter(vsi, netdev->dev_addr, I40E_VLAN_ANY,
-                                   is_vf, is_netdev);
-               if (!f) {
-                       dev_info(&vsi->back->pdev->dev,
-                                "Could not add filter %d for %pM\n",
-                                I40E_VLAN_ANY, netdev->dev_addr);
-                       spin_unlock_bh(&vsi->mac_filter_list_lock);
-                       return -ENOMEM;
-               }
-       }
-
-       if (!filter_count) {
-               list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list) {
-                       i40e_del_filter(vsi, f->macaddr, 0, is_vf, is_netdev);
-                       add_f = i40e_add_filter(vsi, f->macaddr, I40E_VLAN_ANY,
-                                               is_vf, is_netdev);
-                       if (!add_f) {
-                               dev_info(&vsi->back->pdev->dev,
-                                        "Could not add filter %d for %pM\n",
-                                        I40E_VLAN_ANY, f->macaddr);
-                               spin_unlock_bh(&vsi->mac_filter_list_lock);
-                               return -ENOMEM;
-                       }
-               }
+       hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist) {
+               if (f->vlan == vid)
+                       __i40e_del_filter(vsi, f);
        }
+}
 
-       spin_unlock_bh(&vsi->mac_filter_list_lock);
+/**
+ * i40e_vsi_kill_vlan - Remove VSI membership for given VLAN
+ * @vsi: the VSI being configured
+ * @vid: VLAN id to be removed (0 = untagged only , -1 = any)
+ **/
+void i40e_vsi_kill_vlan(struct i40e_vsi *vsi, s16 vid)
+{
+       spin_lock_bh(&vsi->mac_filter_hash_lock);
+       i40e_rm_vlan_all_mac(vsi, vid);
+       spin_unlock_bh(&vsi->mac_filter_hash_lock);
 
        /* schedule our worker thread which will take care of
         * applying the new filter changes
         */
        i40e_service_event_schedule(vsi->back);
-       return 0;
 }
 
 /**
@@ -2543,7 +2649,7 @@ static int i40e_vlan_rx_add_vid(struct net_device *netdev,
        struct i40e_vsi *vsi = np->vsi;
        int ret = 0;
 
-       if (vid > 4095)
+       if (vid >= VLAN_N_VID)
                return -EINVAL;
 
        /* If the network stack called us with vid = 0 then
@@ -2555,7 +2661,7 @@ static int i40e_vlan_rx_add_vid(struct net_device *netdev,
        if (vid)
                ret = i40e_vsi_add_vlan(vsi, vid);
 
-       if (!ret && (vid < VLAN_N_VID))
+       if (!ret)
                set_bit(vid, vsi->active_vlans);
 
        return ret;
@@ -3322,6 +3428,33 @@ static irqreturn_t i40e_msix_clean_rings(int irq, void *data)
        return IRQ_HANDLED;
 }
 
+/**
+ * i40e_irq_affinity_notify - Callback for affinity changes
+ * @notify: context as to what irq was changed
+ * @mask: the new affinity mask
+ *
+ * This is a callback function used by the irq_set_affinity_notifier function
+ * so that we may register to receive changes to the irq affinity masks.
+ **/
+static void i40e_irq_affinity_notify(struct irq_affinity_notify *notify,
+                                    const cpumask_t *mask)
+{
+       struct i40e_q_vector *q_vector =
+               container_of(notify, struct i40e_q_vector, affinity_notify);
+
+       q_vector->affinity_mask = *mask;
+}
+
+/**
+ * i40e_irq_affinity_release - Callback for affinity notifier release
+ * @ref: internal core kernel usage
+ *
+ * This is a callback function used by the irq_set_affinity_notifier function
+ * to inform the current notification subscriber that they will no longer
+ * receive notifications.
+ **/
+static void i40e_irq_affinity_release(struct kref *ref) {}
+
 /**
  * i40e_vsi_request_irq_msix - Initialize MSI-X interrupts
  * @vsi: the VSI being configured
@@ -3337,10 +3470,13 @@ static int i40e_vsi_request_irq_msix(struct i40e_vsi *vsi, char *basename)
        int rx_int_idx = 0;
        int tx_int_idx = 0;
        int vector, err;
+       int irq_num;
 
        for (vector = 0; vector < q_vectors; vector++) {
                struct i40e_q_vector *q_vector = vsi->q_vectors[vector];
 
+               irq_num = pf->msix_entries[base + vector].vector;
+
                if (q_vector->tx.ring && q_vector->rx.ring) {
                        snprintf(q_vector->name, sizeof(q_vector->name) - 1,
                                 "%s-%s-%d", basename, "TxRx", rx_int_idx++);
@@ -3355,7 +3491,7 @@ static int i40e_vsi_request_irq_msix(struct i40e_vsi *vsi, char *basename)
                        /* skip this unused q_vector */
                        continue;
                }
-               err = request_irq(pf->msix_entries[base + vector].vector,
+               err = request_irq(irq_num,
                                  vsi->irq_handler,
                                  0,
                                  q_vector->name,
@@ -3365,9 +3501,13 @@ static int i40e_vsi_request_irq_msix(struct i40e_vsi *vsi, char *basename)
                                 "MSIX request_irq failed, error: %d\n", err);
                        goto free_queue_irqs;
                }
+
+               /* register for affinity change notifications */
+               q_vector->affinity_notify.notify = i40e_irq_affinity_notify;
+               q_vector->affinity_notify.release = i40e_irq_affinity_release;
+               irq_set_affinity_notifier(irq_num, &q_vector->affinity_notify);
                /* assign the mask for this irq */
-               irq_set_affinity_hint(pf->msix_entries[base + vector].vector,
-                                     &q_vector->affinity_mask);
+               irq_set_affinity_hint(irq_num, &q_vector->affinity_mask);
        }
 
        vsi->irqs_ready = true;
@@ -3376,10 +3516,10 @@ static int i40e_vsi_request_irq_msix(struct i40e_vsi *vsi, char *basename)
 free_queue_irqs:
        while (vector) {
                vector--;
-               irq_set_affinity_hint(pf->msix_entries[base + vector].vector,
-                                     NULL);
-               free_irq(pf->msix_entries[base + vector].vector,
-                        &(vsi->q_vectors[vector]));
+               irq_num = pf->msix_entries[base + vector].vector;
+               irq_set_affinity_notifier(irq_num, NULL);
+               irq_set_affinity_hint(irq_num, NULL);
+               free_irq(irq_num, &vsi->q_vectors[vector]);
        }
        return err;
 }
@@ -3481,7 +3621,7 @@ static irqreturn_t i40e_intr(int irq, void *data)
            (ena_mask & I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK)) {
                ena_mask &= ~I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK;
                icr0 &= ~I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK;
-               dev_info(&pf->pdev->dev, "cleared PE_CRITERR\n");
+               dev_dbg(&pf->pdev->dev, "cleared PE_CRITERR\n");
        }
 
        /* only q0 is used in MSI/Legacy mode, and none are used in MSIX */
@@ -3974,29 +4114,35 @@ static int i40e_vsi_control_rx(struct i40e_vsi *vsi, bool enable)
 }
 
 /**
- * i40e_vsi_control_rings - Start or stop a VSI's rings
+ * i40e_vsi_start_rings - Start a VSI's rings
  * @vsi: the VSI being configured
- * @enable: start or stop the rings
  **/
-int i40e_vsi_control_rings(struct i40e_vsi *vsi, bool request)
+int i40e_vsi_start_rings(struct i40e_vsi *vsi)
 {
        int ret = 0;
 
        /* do rx first for enable and last for disable */
-       if (request) {
-               ret = i40e_vsi_control_rx(vsi, request);
-               if (ret)
-                       return ret;
-               ret = i40e_vsi_control_tx(vsi, request);
-       } else {
-               /* Ignore return value, we need to shutdown whatever we can */
-               i40e_vsi_control_tx(vsi, request);
-               i40e_vsi_control_rx(vsi, request);
-       }
+       ret = i40e_vsi_control_rx(vsi, true);
+       if (ret)
+               return ret;
+       ret = i40e_vsi_control_tx(vsi, true);
 
        return ret;
 }
 
+/**
+ * i40e_vsi_stop_rings - Stop a VSI's rings
+ * @vsi: the VSI being configured
+ **/
+void i40e_vsi_stop_rings(struct i40e_vsi *vsi)
+{
+       /* do rx first for enable and last for disable
+        * Ignore return value, we need to shutdown whatever we can
+        */
+       i40e_vsi_control_tx(vsi, false);
+       i40e_vsi_control_rx(vsi, false);
+}
+
 /**
  * i40e_vsi_free_irq - Free the irq association with the OS
  * @vsi: the VSI being configured
@@ -4018,19 +4164,23 @@ static void i40e_vsi_free_irq(struct i40e_vsi *vsi)
 
                vsi->irqs_ready = false;
                for (i = 0; i < vsi->num_q_vectors; i++) {
-                       u16 vector = i + base;
+                       int irq_num;
+                       u16 vector;
+
+                       vector = i + base;
+                       irq_num = pf->msix_entries[vector].vector;
 
                        /* free only the irqs that were actually requested */
                        if (!vsi->q_vectors[i] ||
                            !vsi->q_vectors[i]->num_ringpairs)
                                continue;
 
+                       /* clear the affinity notifier in the IRQ descriptor */
+                       irq_set_affinity_notifier(irq_num, NULL);
                        /* clear the affinity_mask in the IRQ descriptor */
-                       irq_set_affinity_hint(pf->msix_entries[vector].vector,
-                                             NULL);
-                       synchronize_irq(pf->msix_entries[vector].vector);
-                       free_irq(pf->msix_entries[vector].vector,
-                                vsi->q_vectors[i]);
+                       irq_set_affinity_hint(irq_num, NULL);
+                       synchronize_irq(irq_num);
+                       free_irq(irq_num, vsi->q_vectors[i]);
 
                        /* Tear down the interrupt queue link list
                         *
@@ -4616,7 +4766,7 @@ static u8 i40e_dcb_get_enabled_tc(struct i40e_dcbx_config *dcbcfg)
 static u8 i40e_pf_get_num_tc(struct i40e_pf *pf)
 {
        struct i40e_hw *hw = &pf->hw;
-       u8 i, enabled_tc;
+       u8 i, enabled_tc = 1;
        u8 num_tc = 0;
        struct i40e_dcbx_config *dcbcfg = &hw->local_dcbx_config;
 
@@ -4634,8 +4784,6 @@ static u8 i40e_pf_get_num_tc(struct i40e_pf *pf)
        else
                return 1; /* Only TC0 */
 
-       /* At least have TC0 */
-       enabled_tc = (enabled_tc ? enabled_tc : 0x1);
        for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
                if (enabled_tc & BIT(i))
                        num_tc++;
@@ -4643,29 +4791,6 @@ static u8 i40e_pf_get_num_tc(struct i40e_pf *pf)
        return num_tc;
 }
 
-/**
- * i40e_pf_get_default_tc - Get bitmap for first enabled TC
- * @pf: PF being queried
- *
- * Return a bitmap for first enabled traffic class for this PF.
- **/
-static u8 i40e_pf_get_default_tc(struct i40e_pf *pf)
-{
-       u8 enabled_tc = pf->hw.func_caps.enabled_tcmap;
-       u8 i = 0;
-
-       if (!enabled_tc)
-               return 0x1; /* TC0 */
-
-       /* Find the first enabled TC */
-       for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
-               if (enabled_tc & BIT(i))
-                       break;
-       }
-
-       return BIT(i);
-}
-
 /**
  * i40e_pf_get_pf_tc_map - Get bitmap for enabled traffic classes
  * @pf: PF being queried
@@ -4676,7 +4801,7 @@ static u8 i40e_pf_get_tc_map(struct i40e_pf *pf)
 {
        /* If DCB is not enabled for this PF then just return default TC */
        if (!(pf->flags & I40E_FLAG_DCB_ENABLED))
-               return i40e_pf_get_default_tc(pf);
+               return I40E_DEFAULT_TRAFFIC_CLASS;
 
        /* SFP mode we want PF to be enabled for all TCs */
        if (!(pf->flags & I40E_FLAG_MFP_ENABLED))
@@ -4686,7 +4811,7 @@ static u8 i40e_pf_get_tc_map(struct i40e_pf *pf)
        if (pf->hw.func_caps.iscsi)
                return i40e_get_iscsi_tc_map(pf);
        else
-               return i40e_pf_get_default_tc(pf);
+               return I40E_DEFAULT_TRAFFIC_CLASS;
 }
 
 /**
@@ -5032,7 +5157,7 @@ static void i40e_dcb_reconfigure(struct i40e_pf *pf)
                if (v == pf->lan_vsi)
                        tc_map = i40e_pf_get_tc_map(pf);
                else
-                       tc_map = i40e_pf_get_default_tc(pf);
+                       tc_map = I40E_DEFAULT_TRAFFIC_CLASS;
 #ifdef I40E_FCOE
                if (pf->vsi[v]->type == I40E_VSI_FCOE)
                        tc_map = i40e_get_fcoe_tc_map(pf);
@@ -5142,12 +5267,16 @@ out:
  */
 void i40e_print_link_message(struct i40e_vsi *vsi, bool isup)
 {
+       enum i40e_aq_link_speed new_speed;
        char *speed = "Unknown";
        char *fc = "Unknown";
 
-       if (vsi->current_isup == isup)
+       new_speed = vsi->back->hw.phy.link_info.link_speed;
+
+       if ((vsi->current_isup == isup) && (vsi->current_speed == new_speed))
                return;
        vsi->current_isup = isup;
+       vsi->current_speed = new_speed;
        if (!isup) {
                netdev_info(vsi->netdev, "NIC Link is Down\n");
                return;
@@ -5169,6 +5298,9 @@ void i40e_print_link_message(struct i40e_vsi *vsi, bool isup)
        case I40E_LINK_SPEED_20GB:
                speed = "20 G";
                break;
+       case I40E_LINK_SPEED_25GB:
+               speed = "25 G";
+               break;
        case I40E_LINK_SPEED_10GB:
                speed = "10 G";
                break;
@@ -5216,7 +5348,7 @@ static int i40e_up_complete(struct i40e_vsi *vsi)
                i40e_configure_msi_and_legacy(vsi);
 
        /* start rings */
-       err = i40e_vsi_control_rings(vsi, true);
+       err = i40e_vsi_start_rings(vsi);
        if (err)
                return err;
 
@@ -5245,7 +5377,7 @@ static int i40e_up_complete(struct i40e_vsi *vsi)
                /* reset fd counters */
                pf->fd_add_err = pf->fd_atr_cnt = 0;
                if (pf->fd_tcp_rule > 0) {
-                       pf->flags &= ~I40E_FLAG_FD_ATR_ENABLED;
+                       pf->auto_disable_flags |= I40E_FLAG_FD_ATR_ENABLED;
                        if (I40E_DEBUG_FD & pf->hw.debug_mask)
                                dev_info(&pf->pdev->dev, "Forcing ATR off, sideband rules for TCP/IPv4 exist\n");
                        pf->fd_tcp_rule = 0;
@@ -5313,7 +5445,7 @@ void i40e_down(struct i40e_vsi *vsi)
                netif_tx_disable(vsi->netdev);
        }
        i40e_vsi_disable_irq(vsi);
-       i40e_vsi_control_rings(vsi, false);
+       i40e_vsi_stop_rings(vsi);
        i40e_napi_disable_all(vsi);
 
        for (i = 0; i < vsi->num_queue_pairs; i++) {
@@ -5720,7 +5852,7 @@ static int i40e_handle_lldp_event(struct i40e_pf *pf,
        u8 type;
 
        /* Not DCB capable or capability disabled */
-       if (!(pf->flags & I40E_FLAG_DCB_ENABLED))
+       if (!(pf->flags & I40E_FLAG_DCB_CAPABLE))
                return ret;
 
        /* Ignore if event is not for Nearest Bridge */
@@ -5858,19 +5990,6 @@ static void i40e_handle_lan_overflow_event(struct i40e_pf *pf,
        }
 }
 
-/**
- * i40e_service_event_complete - Finish up the service event
- * @pf: board private structure
- **/
-static void i40e_service_event_complete(struct i40e_pf *pf)
-{
-       WARN_ON(!test_bit(__I40E_SERVICE_SCHED, &pf->state));
-
-       /* flush memory to make sure state is correct before next watchog */
-       smp_mb__before_atomic();
-       clear_bit(__I40E_SERVICE_SCHED, &pf->state);
-}
-
 /**
  * i40e_get_cur_guaranteed_fd_count - Get the consumed guaranteed FD filters
  * @pf: board private structure
@@ -5942,13 +6061,17 @@ void i40e_fdir_check_and_reenable(struct i40e_pf *pf)
                                dev_info(&pf->pdev->dev, "FD Sideband/ntuple is being enabled since we have space in the table now\n");
                }
        }
-       /* Wait for some more space to be available to turn on ATR */
+
+       /* Wait for some more space to be available to turn on ATR. We also
+        * must check that no existing ntuple rules for TCP are in effect
+        */
        if (fcnt_prog < (fcnt_avail - I40E_FDIR_BUFFER_HEAD_ROOM * 2)) {
                if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
-                   (pf->auto_disable_flags & I40E_FLAG_FD_ATR_ENABLED)) {
+                   (pf->auto_disable_flags & I40E_FLAG_FD_ATR_ENABLED) &&
+                   (pf->fd_tcp_rule == 0)) {
                        pf->auto_disable_flags &= ~I40E_FLAG_FD_ATR_ENABLED;
                        if (I40E_DEBUG_FD & pf->hw.debug_mask)
-                               dev_info(&pf->pdev->dev, "ATR is being enabled since we have space in the table now\n");
+                               dev_info(&pf->pdev->dev, "ATR is being enabled since we have space in the table and there are no conflicting ntuple rules\n");
                }
        }
 
@@ -5979,9 +6102,6 @@ static void i40e_fdir_flush_and_replay(struct i40e_pf *pf)
        int fd_room;
        int reg;
 
-       if (!(pf->flags & (I40E_FLAG_FD_SB_ENABLED | I40E_FLAG_FD_ATR_ENABLED)))
-               return;
-
        if (!time_after(jiffies, pf->fd_flush_timestamp +
                                 (I40E_MIN_FD_FLUSH_INTERVAL * HZ)))
                return;
@@ -6001,7 +6121,7 @@ static void i40e_fdir_flush_and_replay(struct i40e_pf *pf)
        }
 
        pf->fd_flush_timestamp = jiffies;
-       pf->flags &= ~I40E_FLAG_FD_ATR_ENABLED;
+       pf->auto_disable_flags |= I40E_FLAG_FD_ATR_ENABLED;
        /* flush all filters */
        wr32(&pf->hw, I40E_PFQF_CTL_1,
             I40E_PFQF_CTL_1_CLEARFDTABLE_MASK);
@@ -6021,7 +6141,7 @@ static void i40e_fdir_flush_and_replay(struct i40e_pf *pf)
                /* replay sideband filters */
                i40e_fdir_filter_restore(pf->vsi[pf->lan_vsi]);
                if (!disable_atr)
-                       pf->flags |= I40E_FLAG_FD_ATR_ENABLED;
+                       pf->auto_disable_flags &= ~I40E_FLAG_FD_ATR_ENABLED;
                clear_bit(__I40E_FD_FLUSH_REQUESTED, &pf->state);
                if (I40E_DEBUG_FD & pf->hw.debug_mask)
                        dev_info(&pf->pdev->dev, "FD Filter table flushed and FD-SB replayed.\n");
@@ -6055,9 +6175,6 @@ static void i40e_fdir_reinit_subtask(struct i40e_pf *pf)
        if (test_bit(__I40E_DOWN, &pf->state))
                return;
 
-       if (!(pf->flags & (I40E_FLAG_FD_SB_ENABLED | I40E_FLAG_FD_ATR_ENABLED)))
-               return;
-
        if (test_bit(__I40E_FD_FLUSH_REQUESTED, &pf->state))
                i40e_fdir_flush_and_replay(pf);
 
@@ -6698,7 +6815,6 @@ static int i40e_vsi_clear(struct i40e_vsi *vsi);
 static void i40e_fdir_sb_setup(struct i40e_pf *pf)
 {
        struct i40e_vsi *vsi;
-       int i;
 
        /* quick workaround for an NVM issue that leaves a critical register
         * uninitialized
@@ -6709,6 +6825,7 @@ static void i40e_fdir_sb_setup(struct i40e_pf *pf)
                        0xeacb7d61, 0xaa4f05b6, 0x9c5c89ed, 0xfc425ddb,
                        0xa4654832, 0xfc7461d4, 0x8f827619, 0xf5c63c21,
                        0x95b3a76d};
+               int i;
 
                for (i = 0; i <= I40E_GLQF_HKEY_MAX_INDEX; i++)
                        wr32(&pf->hw, I40E_GLQF_HKEY(i), hkey[i]);
@@ -6718,13 +6835,7 @@ static void i40e_fdir_sb_setup(struct i40e_pf *pf)
                return;
 
        /* find existing VSI and see if it needs configuring */
-       vsi = NULL;
-       for (i = 0; i < pf->num_alloc_vsi; i++) {
-               if (pf->vsi[i] && pf->vsi[i]->type == I40E_VSI_FDIR) {
-                       vsi = pf->vsi[i];
-                       break;
-               }
-       }
+       vsi = i40e_find_vsi_by_type(pf, I40E_VSI_FDIR);
 
        /* create a new VSI if none exists */
        if (!vsi) {
@@ -6746,15 +6857,12 @@ static void i40e_fdir_sb_setup(struct i40e_pf *pf)
  **/
 static void i40e_fdir_teardown(struct i40e_pf *pf)
 {
-       int i;
+       struct i40e_vsi *vsi;
 
        i40e_fdir_filter_exit(pf);
-       for (i = 0; i < pf->num_alloc_vsi; i++) {
-               if (pf->vsi[i] && pf->vsi[i]->type == I40E_VSI_FDIR) {
-                       i40e_vsi_release(pf->vsi[i]);
-                       break;
-               }
-       }
+       vsi = i40e_find_vsi_by_type(pf, I40E_VSI_FDIR);
+       if (vsi)
+               i40e_vsi_release(vsi);
 }
 
 /**
@@ -7157,9 +7265,9 @@ static void i40e_sync_udp_filters_subtask(struct i40e_pf *pf)
                        pf->pending_udp_bitmap &= ~BIT_ULL(i);
                        port = pf->udp_ports[i].index;
                        if (port)
-                               ret = i40e_aq_add_udp_tunnel(hw, ntohs(port),
-                                                    pf->udp_ports[i].type,
-                                                    NULL, NULL);
+                               ret = i40e_aq_add_udp_tunnel(hw, port,
+                                                       pf->udp_ports[i].type,
+                                                       NULL, NULL);
                        else
                                ret = i40e_aq_del_udp_tunnel(hw, i, NULL);
 
@@ -7191,10 +7299,12 @@ static void i40e_service_task(struct work_struct *work)
 
        /* don't bother with service tasks if a reset is in progress */
        if (test_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state)) {
-               i40e_service_event_complete(pf);
                return;
        }
 
+       if (test_and_set_bit(__I40E_SERVICE_SCHED, &pf->state))
+               return;
+
        i40e_detect_recover_hung(pf);
        i40e_sync_filters_subtask(pf);
        i40e_reset_subtask(pf);
@@ -7207,7 +7317,9 @@ static void i40e_service_task(struct work_struct *work)
        i40e_sync_udp_filters_subtask(pf);
        i40e_clean_adminq_subtask(pf);
 
-       i40e_service_event_complete(pf);
+       /* flush memory to make sure state is correct before next watchdog */
+       smp_mb__before_atomic();
+       clear_bit(__I40E_SERVICE_SCHED, &pf->state);
 
        /* If the tasks have taken longer than one timer cycle or there
         * is more work to be done, reschedule the service task now
@@ -7382,7 +7494,7 @@ static int i40e_vsi_mem_alloc(struct i40e_pf *pf, enum i40e_vsi_type type)
                                pf->rss_table_size : 64;
        vsi->netdev_registered = false;
        vsi->work_limit = I40E_DEFAULT_IRQ_WORK;
-       INIT_LIST_HEAD(&vsi->mac_filter_list);
+       hash_init(vsi->mac_filter_hash);
        vsi->irqs_ready = false;
 
        ret = i40e_set_num_rings_in_vsi(vsi);
@@ -7397,7 +7509,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);
 
        /* Initialize VSI lock */
-       spin_lock_init(&vsi->mac_filter_list_lock);
+       spin_lock_init(&vsi->mac_filter_hash_lock);
        pf->vsi[vsi_idx] = vsi;
        ret = vsi_idx;
        goto unlock_pf;
@@ -7646,7 +7758,6 @@ static int i40e_init_msix(struct i40e_pf *pf)
                        vectors_left--;
                } else {
                        pf->num_fdsb_msix = 0;
-                       pf->flags &= ~I40E_FLAG_FD_SB_ENABLED;
                }
        }
 
@@ -7666,6 +7777,8 @@ static int i40e_init_msix(struct i40e_pf *pf)
 #endif
        /* can we reserve enough for iWARP? */
        if (pf->flags & I40E_FLAG_IWARP_ENABLED) {
+               iwarp_requested = pf->num_iwarp_msix;
+
                if (!vectors_left)
                        pf->num_iwarp_msix = 0;
                else if (vectors_left < pf->num_iwarp_msix)
@@ -7679,18 +7792,23 @@ static int i40e_init_msix(struct i40e_pf *pf)
                int vmdq_vecs_wanted = pf->num_vmdq_vsis * pf->num_vmdq_qps;
                int vmdq_vecs = min_t(int, vectors_left, vmdq_vecs_wanted);
 
-               /* if we're short on vectors for what's desired, we limit
-                * the queues per vmdq.  If this is still more than are
-                * available, the user will need to change the number of
-                * queues/vectors used by the PF later with the ethtool
-                * channels command
-                */
-               if (vmdq_vecs < vmdq_vecs_wanted)
-                       pf->num_vmdq_qps = 1;
-               pf->num_vmdq_msix = pf->num_vmdq_qps;
+               if (!vectors_left) {
+                       pf->num_vmdq_msix = 0;
+                       pf->num_vmdq_qps = 0;
+               } else {
+                       /* if we're short on vectors for what's desired, we limit
+                        * the queues per vmdq.  If this is still more than are
+                        * available, the user will need to change the number of
+                        * queues/vectors used by the PF later with the ethtool
+                        * channels command
+                        */
+                       if (vmdq_vecs < vmdq_vecs_wanted)
+                               pf->num_vmdq_qps = 1;
+                       pf->num_vmdq_msix = pf->num_vmdq_qps;
 
-               v_budget += vmdq_vecs;
-               vectors_left -= vmdq_vecs;
+                       v_budget += vmdq_vecs;
+                       vectors_left -= vmdq_vecs;
+               }
        }
 
        pf->msix_entries = kcalloc(v_budget, sizeof(struct msix_entry),
@@ -7702,25 +7820,11 @@ static int i40e_init_msix(struct i40e_pf *pf)
                pf->msix_entries[i].entry = i;
        v_actual = i40e_reserve_msix_vectors(pf, v_budget);
 
-       if (v_actual != v_budget) {
-               /* If we have limited resources, we will start with no vectors
-                * for the special features and then allocate vectors to some
-                * of these features based on the policy and at the end disable
-                * the features that did not get any vectors.
-                */
-               iwarp_requested = pf->num_iwarp_msix;
-               pf->num_iwarp_msix = 0;
-#ifdef I40E_FCOE
-               pf->num_fcoe_qps = 0;
-               pf->num_fcoe_msix = 0;
-#endif
-               pf->num_vmdq_msix = 0;
-       }
-
        if (v_actual < I40E_MIN_MSIX) {
                pf->flags &= ~I40E_FLAG_MSIX_ENABLED;
                kfree(pf->msix_entries);
                pf->msix_entries = NULL;
+               pci_disable_msix(pf->pdev);
                return -ENODEV;
 
        } else if (v_actual == I40E_MIN_MSIX) {
@@ -7730,9 +7834,16 @@ static int i40e_init_msix(struct i40e_pf *pf)
                pf->num_lan_qps = 1;
                pf->num_lan_msix = 1;
 
-       } else if (v_actual != v_budget) {
+       } else if (!vectors_left) {
+               /* If we have limited resources, we will start with no vectors
+                * for the special features and then allocate vectors to some
+                * of these features based on the policy and at the end disable
+                * the features that did not get any vectors.
+                */
                int vec;
 
+               dev_info(&pf->pdev->dev,
+                        "MSI-X vector limit reached, attempting to redistribute vectors\n");
                /* reserve the misc vector */
                vec = v_actual - 1;
 
@@ -7740,7 +7851,10 @@ static int i40e_init_msix(struct i40e_pf *pf)
                pf->num_vmdq_msix = 1;    /* force VMDqs to only one vector */
                pf->num_vmdq_vsis = 1;
                pf->num_vmdq_qps = 1;
-               pf->flags &= ~I40E_FLAG_FD_SB_ENABLED;
+#ifdef I40E_FCOE
+               pf->num_fcoe_qps = 0;
+               pf->num_fcoe_msix = 0;
+#endif
 
                /* partition out the remaining vectors */
                switch (vec) {
@@ -7772,9 +7886,14 @@ static int i40e_init_msix(struct i40e_pf *pf)
                                pf->num_vmdq_vsis = min_t(int, (vec / 2),
                                                  I40E_DEFAULT_NUM_VMDQ_VSI);
                        }
+                       if (pf->flags & I40E_FLAG_FD_SB_ENABLED) {
+                               pf->num_fdsb_msix = 1;
+                               vec--;
+                       }
                        pf->num_lan_msix = min_t(int,
                               (vec - (pf->num_iwarp_msix + pf->num_vmdq_vsis)),
                                                              pf->num_lan_msix);
+                       pf->num_lan_qps = pf->num_lan_msix;
 #ifdef I40E_FCOE
                        /* give one vector to FCoE */
                        if (pf->flags & I40E_FLAG_FCOE_ENABLED) {
@@ -7786,6 +7905,11 @@ static int i40e_init_msix(struct i40e_pf *pf)
                }
        }
 
+       if ((pf->flags & I40E_FLAG_FD_SB_ENABLED) &&
+           (pf->num_fdsb_msix == 0)) {
+               dev_info(&pf->pdev->dev, "Sideband Flowdir disabled, not enough MSI-X vectors\n");
+               pf->flags &= ~I40E_FLAG_FD_SB_ENABLED;
+       }
        if ((pf->flags & I40E_FLAG_VMDQ_ENABLED) &&
            (pf->num_vmdq_msix == 0)) {
                dev_info(&pf->pdev->dev, "VMDq disabled, not enough MSI-X vectors\n");
@@ -7804,6 +7928,13 @@ static int i40e_init_msix(struct i40e_pf *pf)
                pf->flags &= ~I40E_FLAG_FCOE_ENABLED;
        }
 #endif
+       i40e_debug(&pf->hw, I40E_DEBUG_INIT,
+                  "MSI-X vector distribution: PF %d, VMDq %d, FDSB %d, iWARP %d\n",
+                  pf->num_lan_msix,
+                  pf->num_vmdq_msix * pf->num_vmdq_vsis,
+                  pf->num_fdsb_msix,
+                  pf->num_iwarp_msix);
+
        return v_actual;
 }
 
@@ -7990,72 +8121,34 @@ static int i40e_setup_misc_vector(struct i40e_pf *pf)
 static int i40e_config_rss_aq(struct i40e_vsi *vsi, const u8 *seed,
                              u8 *lut, u16 lut_size)
 {
-       struct i40e_aqc_get_set_rss_key_data rss_key;
        struct i40e_pf *pf = vsi->back;
        struct i40e_hw *hw = &pf->hw;
-       bool pf_lut = false;
-       u8 *rss_lut;
-       int ret, i;
-
-       memcpy(&rss_key, seed, sizeof(rss_key));
-
-       rss_lut = kzalloc(pf->rss_table_size, GFP_KERNEL);
-       if (!rss_lut)
-               return -ENOMEM;
-
-       /* Populate the LUT with max no. of queues in round robin fashion */
-       for (i = 0; i < vsi->rss_table_size; i++)
-               rss_lut[i] = i % vsi->rss_size;
+       int ret = 0;
 
-       ret = i40e_aq_set_rss_key(hw, vsi->id, &rss_key);
-       if (ret) {
-               dev_info(&pf->pdev->dev,
-                        "Cannot set RSS key, err %s aq_err %s\n",
-                        i40e_stat_str(&pf->hw, ret),
-                        i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status));
-               goto config_rss_aq_out;
+       if (seed) {
+               struct i40e_aqc_get_set_rss_key_data *seed_dw =
+                       (struct i40e_aqc_get_set_rss_key_data *)seed;
+               ret = i40e_aq_set_rss_key(hw, vsi->id, seed_dw);
+               if (ret) {
+                       dev_info(&pf->pdev->dev,
+                                "Cannot set RSS key, err %s aq_err %s\n",
+                                i40e_stat_str(hw, ret),
+                                i40e_aq_str(hw, hw->aq.asq_last_status));
+                       return ret;
+               }
        }
+       if (lut) {
+               bool pf_lut = vsi->type == I40E_VSI_MAIN ? true : false;
 
-       if (vsi->type == I40E_VSI_MAIN)
-               pf_lut = true;
-
-       ret = i40e_aq_set_rss_lut(hw, vsi->id, pf_lut, rss_lut,
-                                 vsi->rss_table_size);
-       if (ret)
-               dev_info(&pf->pdev->dev,
-                        "Cannot set RSS lut, err %s aq_err %s\n",
-                        i40e_stat_str(&pf->hw, ret),
-                        i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status));
-
-config_rss_aq_out:
-       kfree(rss_lut);
-       return ret;
-}
-
-/**
- * i40e_vsi_config_rss - Prepare for VSI(VMDq) RSS if used
- * @vsi: VSI structure
- **/
-static int i40e_vsi_config_rss(struct i40e_vsi *vsi)
-{
-       u8 seed[I40E_HKEY_ARRAY_SIZE];
-       struct i40e_pf *pf = vsi->back;
-       u8 *lut;
-       int ret;
-
-       if (!(pf->flags & I40E_FLAG_RSS_AQ_CAPABLE))
-               return 0;
-
-       lut = kzalloc(vsi->rss_table_size, GFP_KERNEL);
-       if (!lut)
-               return -ENOMEM;
-
-       i40e_fill_rss_lut(pf, lut, vsi->rss_table_size, vsi->rss_size);
-       netdev_rss_key_fill((void *)seed, I40E_HKEY_ARRAY_SIZE);
-       vsi->rss_size = min_t(int, pf->alloc_rss_size, vsi->num_queue_pairs);
-       ret = i40e_config_rss_aq(vsi, seed, lut, vsi->rss_table_size);
-       kfree(lut);
-
+               ret = i40e_aq_set_rss_lut(hw, vsi->id, pf_lut, lut, lut_size);
+               if (ret) {
+                       dev_info(&pf->pdev->dev,
+                                "Cannot set RSS lut, err %s aq_err %s\n",
+                                i40e_stat_str(hw, ret),
+                                i40e_aq_str(hw, hw->aq.asq_last_status));
+                       return ret;
+               }
+       }
        return ret;
 }
 
@@ -8105,6 +8198,46 @@ static int i40e_get_rss_aq(struct i40e_vsi *vsi, const u8 *seed,
        return ret;
 }
 
+/**
+ * i40e_vsi_config_rss - Prepare for VSI(VMDq) RSS if used
+ * @vsi: VSI structure
+ **/
+static int i40e_vsi_config_rss(struct i40e_vsi *vsi)
+{
+       u8 seed[I40E_HKEY_ARRAY_SIZE];
+       struct i40e_pf *pf = vsi->back;
+       u8 *lut;
+       int ret;
+
+       if (!(pf->flags & I40E_FLAG_RSS_AQ_CAPABLE))
+               return 0;
+
+       if (!vsi->rss_size)
+               vsi->rss_size = min_t(int, pf->alloc_rss_size,
+                                     vsi->num_queue_pairs);
+       if (!vsi->rss_size)
+               return -EINVAL;
+
+       lut = kzalloc(vsi->rss_table_size, GFP_KERNEL);
+       if (!lut)
+               return -ENOMEM;
+       /* Use the user configured hash keys and lookup table if there is one,
+        * otherwise use default
+        */
+       if (vsi->rss_lut_user)
+               memcpy(lut, vsi->rss_lut_user, vsi->rss_table_size);
+       else
+               i40e_fill_rss_lut(pf, lut, vsi->rss_table_size, vsi->rss_size);
+       if (vsi->rss_hkey_user)
+               memcpy(seed, vsi->rss_hkey_user, I40E_HKEY_ARRAY_SIZE);
+       else
+               netdev_rss_key_fill((void *)seed, I40E_HKEY_ARRAY_SIZE);
+       ret = i40e_config_rss_aq(vsi, seed, lut, vsi->rss_table_size);
+       kfree(lut);
+
+       return ret;
+}
+
 /**
  * i40e_config_rss_reg - Configure RSS keys and lut by writing registers
  * @vsi: Pointer to vsi structure
@@ -8243,8 +8376,8 @@ int i40e_get_rss(struct i40e_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size)
  * @rss_table_size: Lookup table size
  * @rss_size: Range of queue number for hashing
  */
-static void i40e_fill_rss_lut(struct i40e_pf *pf, u8 *lut,
-                             u16 rss_table_size, u16 rss_size)
+void i40e_fill_rss_lut(struct i40e_pf *pf, u8 *lut,
+                      u16 rss_table_size, u16 rss_size)
 {
        u16 i;
 
@@ -8285,6 +8418,8 @@ static int i40e_pf_config_rss(struct i40e_pf *pf)
        if (!vsi->rss_size)
                vsi->rss_size = min_t(int, pf->alloc_rss_size,
                                      vsi->num_queue_pairs);
+       if (!vsi->rss_size)
+               return -EINVAL;
 
        lut = kzalloc(vsi->rss_table_size, GFP_KERNEL);
        if (!lut)
@@ -8350,8 +8485,8 @@ int i40e_reconfig_rss_queues(struct i40e_pf *pf, int queue_count)
 
                i40e_pf_config_rss(pf);
        }
-       dev_info(&pf->pdev->dev, "RSS count/HW max RSS count:  %d/%d\n",
-                pf->alloc_rss_size, pf->rss_size_max);
+       dev_info(&pf->pdev->dev, "User requested queue count/HW max RSS count:  %d/%d\n",
+                vsi->req_queue_pairs, pf->rss_size_max);
        return pf->alloc_rss_size;
 }
 
@@ -8494,15 +8629,6 @@ static int i40e_sw_init(struct i40e_pf *pf)
        int err = 0;
        int size;
 
-       pf->msg_enable = netif_msg_init(I40E_DEFAULT_MSG_ENABLE,
-                               (NETIF_MSG_DRV|NETIF_MSG_PROBE|NETIF_MSG_LINK));
-       if (debug != -1 && debug != I40E_DEFAULT_MSG_ENABLE) {
-               if (I40E_DEBUG_USER & debug)
-                       pf->hw.debug_mask = debug;
-               pf->msg_enable = netif_msg_init((debug & ~I40E_DEBUG_USER),
-                                               I40E_DEFAULT_MSG_ENABLE);
-       }
-
        /* Set default capability flags */
        pf->flags = I40E_FLAG_RX_CSUM_ENABLED |
                    I40E_FLAG_MSI_ENABLED     |
@@ -8609,9 +8735,9 @@ static int i40e_sw_init(struct i40e_pf *pf)
                             I40E_FLAG_WB_ON_ITR_CAPABLE |
                             I40E_FLAG_MULTIPLE_TCP_UDP_RSS_PCTYPE |
                             I40E_FLAG_NO_PCI_LINK_CHECK |
-                            I40E_FLAG_100M_SGMII_CAPABLE |
                             I40E_FLAG_USE_SET_LLDP_MIB |
-                            I40E_FLAG_GENEVE_OFFLOAD_CAPABLE;
+                            I40E_FLAG_GENEVE_OFFLOAD_CAPABLE |
+                            I40E_FLAG_PTP_L4_CAPABLE;
        } else if ((pf->hw.aq.api_maj_ver > 1) ||
                   ((pf->hw.aq.api_maj_ver == 1) &&
                    (pf->hw.aq.api_min_ver > 4))) {
@@ -8684,17 +8810,39 @@ bool i40e_set_ntuple(struct i40e_pf *pf, netdev_features_t features)
                /* reset fd counters */
                pf->fd_add_err = pf->fd_atr_cnt = pf->fd_tcp_rule = 0;
                pf->fdir_pf_active_filters = 0;
-               pf->flags |= I40E_FLAG_FD_ATR_ENABLED;
-               if (I40E_DEBUG_FD & pf->hw.debug_mask)
-                       dev_info(&pf->pdev->dev, "ATR re-enabled.\n");
                /* if ATR was auto disabled it can be re-enabled. */
                if ((pf->flags & I40E_FLAG_FD_ATR_ENABLED) &&
-                   (pf->auto_disable_flags & I40E_FLAG_FD_ATR_ENABLED))
+                   (pf->auto_disable_flags & I40E_FLAG_FD_ATR_ENABLED)) {
                        pf->auto_disable_flags &= ~I40E_FLAG_FD_ATR_ENABLED;
+                       if (I40E_DEBUG_FD & pf->hw.debug_mask)
+                               dev_info(&pf->pdev->dev, "ATR re-enabled.\n");
+               }
        }
        return need_reset;
 }
 
+/**
+ * i40e_clear_rss_lut - clear the rx hash lookup table
+ * @vsi: the VSI being configured
+ **/
+static void i40e_clear_rss_lut(struct i40e_vsi *vsi)
+{
+       struct i40e_pf *pf = vsi->back;
+       struct i40e_hw *hw = &pf->hw;
+       u16 vf_id = vsi->vf_id;
+       u8 i;
+
+       if (vsi->type == I40E_VSI_MAIN) {
+               for (i = 0; i <= I40E_PFQF_HLUT_MAX_INDEX; i++)
+                       wr32(hw, I40E_PFQF_HLUT(i), 0);
+       } else if (vsi->type == I40E_VSI_SRIOV) {
+               for (i = 0; i <= I40E_VFQF_HLUT_MAX_INDEX; i++)
+                       i40e_write_rx_ctl(hw, I40E_VFQF_HLUT1(i, vf_id), 0);
+       } else {
+               dev_err(&pf->pdev->dev, "Cannot set RSS LUT - invalid VSI type\n");
+       }
+}
+
 /**
  * i40e_set_features - set the netdev feature flags
  * @netdev: ptr to the netdev being adjusted
@@ -8708,6 +8856,12 @@ static int i40e_set_features(struct net_device *netdev,
        struct i40e_pf *pf = vsi->back;
        bool need_reset;
 
+       if (features & NETIF_F_RXHASH && !(netdev->features & NETIF_F_RXHASH))
+               i40e_pf_config_rss(pf);
+       else if (!(features & NETIF_F_RXHASH) &&
+                netdev->features & NETIF_F_RXHASH)
+               i40e_clear_rss_lut(vsi);
+
        if (features & NETIF_F_HW_VLAN_CTAG_RX)
                i40e_vlan_stripping_enable(vsi);
        else
@@ -9012,13 +9166,9 @@ static int i40e_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
                return 0;
 
        return ndo_dflt_bridge_getlink(skb, pid, seq, dev, veb->bridge_mode,
-                                      nlflags, 0, 0, filter_mask, NULL);
+                                      0, 0, nlflags, filter_mask, NULL);
 }
 
-/* Hardware supports L4 tunnel length of 128B (=2^7) which includes
- * inner mac plus all inner ethertypes.
- */
-#define I40E_MAX_TUNNEL_HDR_LEN 128
 /**
  * i40e_features_check - Validate encapsulated packet conforms to limits
  * @skb: skb buff
@@ -9029,12 +9179,52 @@ static netdev_features_t i40e_features_check(struct sk_buff *skb,
                                             struct net_device *dev,
                                             netdev_features_t features)
 {
-       if (skb->encapsulation &&
-           ((skb_inner_network_header(skb) - skb_transport_header(skb)) >
-            I40E_MAX_TUNNEL_HDR_LEN))
-               return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
+       size_t len;
+
+       /* No point in doing any of this if neither checksum nor GSO are
+        * being requested for this frame.  We can rule out both by just
+        * checking for CHECKSUM_PARTIAL
+        */
+       if (skb->ip_summed != CHECKSUM_PARTIAL)
+               return features;
+
+       /* We cannot support GSO if the MSS is going to be less than
+        * 64 bytes.  If it is then we need to drop support for GSO.
+        */
+       if (skb_is_gso(skb) && (skb_shinfo(skb)->gso_size < 64))
+               features &= ~NETIF_F_GSO_MASK;
+
+       /* MACLEN can support at most 63 words */
+       len = skb_network_header(skb) - skb->data;
+       if (len & ~(63 * 2))
+               goto out_err;
+
+       /* IPLEN and EIPLEN can support at most 127 dwords */
+       len = skb_transport_header(skb) - skb_network_header(skb);
+       if (len & ~(127 * 4))
+               goto out_err;
+
+       if (skb->encapsulation) {
+               /* L4TUNLEN can support 127 words */
+               len = skb_inner_network_header(skb) - skb_transport_header(skb);
+               if (len & ~(127 * 2))
+                       goto out_err;
+
+               /* IPLEN can support at most 127 dwords */
+               len = skb_inner_transport_header(skb) -
+                     skb_inner_network_header(skb);
+               if (len & ~(127 * 4))
+                       goto out_err;
+       }
+
+       /* No need to validate L4LEN as TCP is the only protocol with a
+        * a flexible value and we support all possible values supported
+        * by TCP, which is at most 15 dwords
+        */
 
        return features;
+out_err:
+       return features & ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK);
 }
 
 static const struct net_device_ops i40e_netdev_ops = {
@@ -9087,6 +9277,7 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
        struct i40e_hw *hw = &pf->hw;
        struct i40e_netdev_priv *np;
        struct net_device *netdev;
+       u8 broadcast[ETH_ALEN];
        u8 mac_addr[ETH_ALEN];
        int etherdev_size;
 
@@ -9147,20 +9338,38 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
                 * which must be replaced by a normal filter.
                 */
                i40e_rm_default_mac_filter(vsi, mac_addr);
-               spin_lock_bh(&vsi->mac_filter_list_lock);
-               i40e_add_filter(vsi, mac_addr, I40E_VLAN_ANY, false, true);
-               spin_unlock_bh(&vsi->mac_filter_list_lock);
+               spin_lock_bh(&vsi->mac_filter_hash_lock);
+               i40e_add_filter(vsi, mac_addr, I40E_VLAN_ANY);
+               spin_unlock_bh(&vsi->mac_filter_hash_lock);
        } else {
                /* relate the VSI_VMDQ name to the VSI_MAIN name */
                snprintf(netdev->name, IFNAMSIZ, "%sv%%d",
                         pf->vsi[pf->lan_vsi]->netdev->name);
                random_ether_addr(mac_addr);
 
-               spin_lock_bh(&vsi->mac_filter_list_lock);
-               i40e_add_filter(vsi, mac_addr, I40E_VLAN_ANY, false, false);
-               spin_unlock_bh(&vsi->mac_filter_list_lock);
+               spin_lock_bh(&vsi->mac_filter_hash_lock);
+               i40e_add_filter(vsi, mac_addr, I40E_VLAN_ANY);
+               spin_unlock_bh(&vsi->mac_filter_hash_lock);
        }
 
+       /* Add the broadcast filter so that we initially will receive
+        * broadcast packets. Note that when a new VLAN is first added the
+        * driver will convert all filters marked I40E_VLAN_ANY into VLAN
+        * specific filters as part of transitioning into "vlan" operation.
+        * When more VLANs are added, the driver will copy each existing MAC
+        * filter and add it for the new VLAN.
+        *
+        * Broadcast filters are handled specially by
+        * i40e_sync_filters_subtask, as the driver must to set the broadcast
+        * promiscuous bit instead of adding this directly as a MAC/VLAN
+        * filter. The subtask will update the correct broadcast promiscuous
+        * bits as VLANs become active or inactive.
+        */
+       eth_broadcast_addr(broadcast);
+       spin_lock_bh(&vsi->mac_filter_hash_lock);
+       i40e_add_filter(vsi, broadcast, I40E_VLAN_ANY);
+       spin_unlock_bh(&vsi->mac_filter_hash_lock);
+
        ether_addr_copy(netdev->dev_addr, mac_addr);
        ether_addr_copy(netdev->perm_addr, mac_addr);
 
@@ -9176,6 +9385,11 @@ static int i40e_config_netdev(struct i40e_vsi *vsi)
        i40e_fcoe_config_netdev(netdev, vsi);
 #endif
 
+       /* MTU range: 68 - 9706 */
+       netdev->min_mtu = ETH_MIN_MTU;
+       netdev->max_mtu = I40E_MAX_RXBUFFER -
+                         (ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN);
+
        return 0;
 }
 
@@ -9238,11 +9452,12 @@ int i40e_is_vsi_uplink_mode_veb(struct i40e_vsi *vsi)
 static int i40e_add_vsi(struct i40e_vsi *vsi)
 {
        int ret = -ENODEV;
-       i40e_status aq_ret = 0;
        struct i40e_pf *pf = vsi->back;
        struct i40e_hw *hw = &pf->hw;
        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 */
        int f_count = 0;
@@ -9426,28 +9641,16 @@ static int i40e_add_vsi(struct i40e_vsi *vsi)
                vsi->seid = ctxt.seid;
                vsi->id = ctxt.vsi_number;
        }
-       /* Except FDIR VSI, for all othet VSI set the broadcast filter */
-       if (vsi->type != I40E_VSI_FDIR) {
-               aq_ret = i40e_aq_set_vsi_broadcast(hw, vsi->seid, true, NULL);
-               if (aq_ret) {
-                       ret = i40e_aq_rc_to_posix(aq_ret,
-                                                 hw->aq.asq_last_status);
-                       dev_info(&pf->pdev->dev,
-                                "set brdcast promisc failed, err %s, aq_err %s\n",
-                                i40e_stat_str(hw, aq_ret),
-                                i40e_aq_str(hw, hw->aq.asq_last_status));
-               }
-       }
 
        vsi->active_filters = 0;
        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 */
-       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_count++;
        }
-       spin_unlock_bh(&vsi->mac_filter_list_lock);
+       spin_unlock_bh(&vsi->mac_filter_hash_lock);
 
        if (f_count) {
                vsi->flags |= I40E_VSI_FLAG_FILTER_CHANGED;
@@ -9477,11 +9680,12 @@ err:
  **/
 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_pf *pf;
        u16 uplink_seid;
-       int i, n;
+       int i, n, bkt;
 
        pf = vsi->back;
 
@@ -9511,11 +9715,19 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
                i40e_vsi_disable_irq(vsi);
        }
 
-       spin_lock_bh(&vsi->mac_filter_list_lock);
-       list_for_each_entry_safe(f, ftmp, &vsi->mac_filter_list, list)
-               i40e_del_filter(vsi, f->macaddr, f->vlan,
-                               f->is_vf, f->is_netdev);
-       spin_unlock_bh(&vsi->mac_filter_list_lock);
+       spin_lock_bh(&vsi->mac_filter_hash_lock);
+
+       /* clear the sync flag on all filters */
+       if (vsi->netdev) {
+               __dev_uc_unsync(vsi->netdev, NULL);
+               __dev_mc_unsync(vsi->netdev, NULL);
+       }
+
+       /* make sure any remaining filters are marked for deletion */
+       hash_for_each_safe(vsi->mac_filter_hash, bkt, h, f, hlist)
+               __i40e_del_filter(vsi, f);
+
+       spin_unlock_bh(&vsi->mac_filter_hash_lock);
 
        i40e_sync_vsi_filters(vsi);
 
@@ -10784,10 +10996,12 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        mutex_init(&hw->aq.asq_mutex);
        mutex_init(&hw->aq.arq_mutex);
 
-       if (debug != -1) {
-               pf->msg_enable = pf->hw.debug_mask;
-               pf->msg_enable = debug;
-       }
+       pf->msg_enable = netif_msg_init(debug,
+                                       NETIF_MSG_DRV |
+                                       NETIF_MSG_PROBE |
+                                       NETIF_MSG_LINK);
+       if (debug < -1)
+               pf->hw.debug_mask = debug;
 
        /* do a special CORER for clearing PXE mode once at init */
        if (hw->revision_id == 0 &&
@@ -10929,7 +11143,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        err = i40e_init_pf_dcb(pf);
        if (err) {
                dev_info(&pdev->dev, "DCB init failed %d, disabled\n", err);
-               pf->flags &= ~(I40E_FLAG_DCB_CAPABLE & I40E_FLAG_DCB_ENABLED);
+               pf->flags &= ~(I40E_FLAG_DCB_CAPABLE | I40E_FLAG_DCB_ENABLED);
                /* Continue without DCB enabled */
        }
 #endif /* CONFIG_I40E_DCB */
@@ -11187,7 +11401,6 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                dev_dbg(&pf->pdev->dev, "get supported phy types ret =  %s last_status =  %s\n",
                        i40e_stat_str(&pf->hw, err),
                        i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status));
-       pf->hw.phy.phy_types = le32_to_cpu(abilities.phy_type);
 
        /* Add a filter to drop all Flow control frames from any VSI from being
         * transmitted. By doing so we stop a malicious VF from sending out
@@ -11199,9 +11412,10 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                                                       pf->main_vsi_seid);
 
        if ((pf->hw.device_id == I40E_DEV_ID_10G_BASE_T) ||
-           (pf->hw.device_id == I40E_DEV_ID_10G_BASE_T4))
-               pf->flags |= I40E_FLAG_HAVE_10GBASET_PHY;
-
+               (pf->hw.device_id == I40E_DEV_ID_10G_BASE_T4))
+               pf->flags |= I40E_FLAG_PHY_CONTROLS_LEDS;
+       if (pf->hw.device_id == I40E_DEV_ID_SFP_I_X722)
+               pf->flags |= I40E_FLAG_HAVE_CRT_RETIMER;
        /* print a string summarizing features */
        i40e_print_features(pf);
 
@@ -11309,11 +11523,7 @@ static void i40e_remove(struct pci_dev *pdev)
        }
 
        /* shutdown the adminq */
-       ret_code = i40e_shutdown_adminq(hw);
-       if (ret_code)
-               dev_warn(&pdev->dev,
-                        "Failed to destroy the Admin Queue resources: %d\n",
-                        ret_code);
+       i40e_shutdown_adminq(hw);
 
        /* destroy the locks only once, here */
        mutex_destroy(&hw->aq.arq_mutex);
@@ -11360,6 +11570,12 @@ static pci_ers_result_t i40e_pci_error_detected(struct pci_dev *pdev,
 
        dev_info(&pdev->dev, "%s: error %d\n", __func__, error);
 
+       if (!pf) {
+               dev_info(&pdev->dev,
+                        "Cannot recover - error happened during device probe\n");
+               return PCI_ERS_RESULT_DISCONNECT;
+       }
+
        /* shutdown all operations */
        if (!test_bit(__I40E_SUSPENDED, &pf->state)) {
                rtnl_lock();
@@ -11582,7 +11798,8 @@ static int __init i40e_init_module(void)
         * it can't be any worse than using the system workqueue which
         * was already single threaded
         */
-       i40e_wq = create_singlethread_workqueue(i40e_driver_name);
+       i40e_wq = alloc_workqueue("%s", WQ_UNBOUND | WQ_MEM_RECLAIM, 1,
+                                 i40e_driver_name);
        if (!i40e_wq) {
                pr_err("%s: Failed to create workqueue\n", i40e_driver_name);
                return -ENOMEM;