i40e: Fix i40e_print_features() VEB mode output
[cascardo/linux.git] / drivers / net / ethernet / intel / i40e / i40e_main.c
index b825f97..0ddec19 100644 (file)
@@ -38,8 +38,8 @@ static const char i40e_driver_string[] =
 #define DRV_KERN "-k"
 
 #define DRV_VERSION_MAJOR 1
-#define DRV_VERSION_MINOR 3
-#define DRV_VERSION_BUILD 46
+#define DRV_VERSION_MINOR 4
+#define DRV_VERSION_BUILD 4
 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \
             __stringify(DRV_VERSION_MINOR) "." \
             __stringify(DRV_VERSION_BUILD)    DRV_KERN
@@ -55,6 +55,8 @@ 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);
 
@@ -881,6 +883,7 @@ static void i40e_update_vsi_stats(struct i40e_vsi *vsi)
        u64 bytes, packets;
        unsigned int start;
        u64 tx_linearize;
+       u64 tx_force_wb;
        u64 rx_p, rx_b;
        u64 tx_p, tx_b;
        u16 q;
@@ -899,7 +902,7 @@ static void i40e_update_vsi_stats(struct i40e_vsi *vsi)
         */
        rx_b = rx_p = 0;
        tx_b = tx_p = 0;
-       tx_restart = tx_busy = tx_linearize = 0;
+       tx_restart = tx_busy = tx_linearize = tx_force_wb = 0;
        rx_page = 0;
        rx_buf = 0;
        rcu_read_lock();
@@ -917,6 +920,7 @@ static void i40e_update_vsi_stats(struct i40e_vsi *vsi)
                tx_restart += p->tx_stats.restart_queue;
                tx_busy += p->tx_stats.tx_busy;
                tx_linearize += p->tx_stats.tx_linearize;
+               tx_force_wb += p->tx_stats.tx_force_wb;
 
                /* Rx queue is part of the same block as Tx queue */
                p = &p[1];
@@ -934,6 +938,7 @@ static void i40e_update_vsi_stats(struct i40e_vsi *vsi)
        vsi->tx_restart = tx_restart;
        vsi->tx_busy = tx_busy;
        vsi->tx_linearize = tx_linearize;
+       vsi->tx_force_wb = tx_force_wb;
        vsi->rx_page_failed = rx_page;
        vsi->rx_buf_failed = rx_buf;
 
@@ -1547,9 +1552,11 @@ static int i40e_set_mac(struct net_device *netdev, void *p)
                spin_unlock_bh(&vsi->mac_filter_list_lock);
        }
 
-       i40e_sync_vsi_filters(vsi, false);
        ether_addr_copy(netdev->dev_addr, addr->sa_data);
-
+       /* schedule our worker thread which will take care of
+        * applying the new filter changes
+        */
+       i40e_service_event_schedule(vsi->back);
        return 0;
 }
 
@@ -1625,7 +1632,8 @@ static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi,
 
                        switch (vsi->type) {
                        case I40E_VSI_MAIN:
-                               qcount = min_t(int, pf->rss_size, num_tc_qps);
+                               qcount = min_t(int, pf->alloc_rss_size,
+                                              num_tc_qps);
                                break;
 #ifdef I40E_FCOE
                        case I40E_VSI_FCOE:
@@ -1851,13 +1859,12 @@ static void i40e_cleanup_add_list(struct list_head *add_list)
 /**
  * i40e_sync_vsi_filters - Update the VSI filter list to the HW
  * @vsi: ptr to the VSI
- * @grab_rtnl: whether RTNL needs to be grabbed
  *
  * Push any outstanding VSI filter changes through the AdminQ.
  *
  * Returns 0 or error value
  **/
-int i40e_sync_vsi_filters(struct i40e_vsi *vsi, bool grab_rtnl)
+int i40e_sync_vsi_filters(struct i40e_vsi *vsi)
 {
        struct list_head tmp_del_list, tmp_add_list;
        struct i40e_mac_filter *f, *ftmp, *fclone;
@@ -2112,12 +2119,7 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi, bool grab_rtnl)
                         */
                        if (pf->cur_promisc != cur_promisc) {
                                pf->cur_promisc = cur_promisc;
-                               if (grab_rtnl)
-                                       i40e_do_reset_safe(pf,
-                                               BIT(__I40E_PF_RESET_REQUESTED));
-                               else
-                                       i40e_do_reset(pf,
-                                               BIT(__I40E_PF_RESET_REQUESTED));
+                               set_bit(__I40E_PF_RESET_REQUESTED, &pf->state);
                        }
                } else {
                        ret = i40e_aq_set_vsi_unicast_promiscuous(
@@ -2166,8 +2168,15 @@ static void i40e_sync_filters_subtask(struct i40e_pf *pf)
 
        for (v = 0; v < pf->num_alloc_vsi; v++) {
                if (pf->vsi[v] &&
-                   (pf->vsi[v]->flags & I40E_VSI_FLAG_FILTER_CHANGED))
-                       i40e_sync_vsi_filters(pf->vsi[v], true);
+                   (pf->vsi[v]->flags & I40E_VSI_FLAG_FILTER_CHANGED)) {
+                       int ret = i40e_sync_vsi_filters(pf->vsi[v]);
+
+                       if (ret) {
+                               /* come back and try again later */
+                               pf->flags |= I40E_FLAG_FILTER_SYNC;
+                               break;
+                       }
+               }
        }
 }
 
@@ -2377,16 +2386,13 @@ int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid)
                }
        }
 
-       /* Make sure to release before sync_vsi_filter because that
-        * function will lock/unlock as necessary
-        */
        spin_unlock_bh(&vsi->mac_filter_list_lock);
 
-       if (test_bit(__I40E_DOWN, &vsi->back->state) ||
-           test_bit(__I40E_RESET_RECOVERY_PENDING, &vsi->back->state))
-               return 0;
-
-       return i40e_sync_vsi_filters(vsi, false);
+       /* schedule our worker thread which will take care of
+        * applying the new filter changes
+        */
+       i40e_service_event_schedule(vsi->back);
+       return 0;
 }
 
 /**
@@ -2459,16 +2465,13 @@ int i40e_vsi_kill_vlan(struct i40e_vsi *vsi, s16 vid)
                }
        }
 
-       /* Make sure to release before sync_vsi_filter because that
-        * function with lock/unlock as necessary
-        */
        spin_unlock_bh(&vsi->mac_filter_list_lock);
 
-       if (test_bit(__I40E_DOWN, &vsi->back->state) ||
-           test_bit(__I40E_RESET_RECOVERY_PENDING, &vsi->back->state))
-               return 0;
-
-       return i40e_sync_vsi_filters(vsi, false);
+       /* schedule our worker thread which will take care of
+        * applying the new filter changes
+        */
+       i40e_service_event_schedule(vsi->back);
+       return 0;
 }
 
 /**
@@ -2711,6 +2714,11 @@ static void i40e_config_xps_tx_ring(struct i40e_ring *ring)
                netif_set_xps_queue(ring->netdev, mask, ring->queue_index);
                free_cpumask_var(mask);
        }
+
+       /* schedule our worker thread which will take care of
+        * applying the new filter changes
+        */
+       i40e_service_event_schedule(vsi->back);
 }
 
 /**
@@ -5738,7 +5746,7 @@ static void i40e_handle_lan_overflow_event(struct i40e_pf *pf,
  **/
 static void i40e_service_event_complete(struct i40e_pf *pf)
 {
-       BUG_ON(!test_bit(__I40E_SERVICE_SCHED, &pf->state));
+       WARN_ON(!test_bit(__I40E_SERVICE_SCHED, &pf->state));
 
        /* flush memory to make sure state is correct before next watchog */
        smp_mb__before_atomic();
@@ -6013,6 +6021,9 @@ static void i40e_link_event(struct i40e_pf *pf)
        i40e_status status;
        bool new_link, old_link;
 
+       /* save off old link status information */
+       pf->hw.phy.link_info_old = pf->hw.phy.link_info;
+
        /* set this to force the get_link_status call to refresh state */
        pf->hw.phy.get_link_info = true;
 
@@ -6147,13 +6158,9 @@ unlock:
 static void i40e_handle_link_event(struct i40e_pf *pf,
                                   struct i40e_arq_event_info *e)
 {
-       struct i40e_hw *hw = &pf->hw;
        struct i40e_aqc_get_link_status *status =
                (struct i40e_aqc_get_link_status *)&e->desc.params.raw;
 
-       /* save off old link status information */
-       hw->phy.link_info_old = hw->phy.link_info;
-
        /* Do a new status request to re-enable LSE reporting
         * and load new status information into the hw struct
         * This completely ignores any state information
@@ -6685,6 +6692,7 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit)
        struct i40e_hw *hw = &pf->hw;
        u8 set_fc_aq_fail = 0;
        i40e_status ret;
+       u32 val;
        u32 v;
 
        /* Now we wait for GRST to settle out.
@@ -6823,6 +6831,20 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit)
                }
        }
 
+       /* Reconfigure hardware for allowing smaller MSS in the case
+        * of TSO, so that we avoid the MDD being fired and causing
+        * a reset in the case of small MSS+TSO.
+        */
+#define I40E_REG_MSS          0x000E64DC
+#define I40E_REG_MSS_MIN_MASK 0x3FF0000
+#define I40E_64BYTE_MSS       0x400000
+       val = rd32(hw, I40E_REG_MSS);
+       if ((val & I40E_REG_MSS_MIN_MASK) > I40E_64BYTE_MSS) {
+               val &= ~I40E_REG_MSS_MIN_MASK;
+               val |= I40E_64BYTE_MSS;
+               wr32(hw, I40E_REG_MSS, val);
+       }
+
        if (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 33)) ||
            (pf->hw.aq.fw_maj_ver < 4)) {
                msleep(75);
@@ -7281,6 +7303,23 @@ static void i40e_vsi_free_arrays(struct i40e_vsi *vsi, bool free_qvectors)
        vsi->rx_rings = NULL;
 }
 
+/**
+ * i40e_clear_rss_config_user - clear the user configured RSS hash keys
+ * and lookup table
+ * @vsi: Pointer to VSI structure
+ */
+static void i40e_clear_rss_config_user(struct i40e_vsi *vsi)
+{
+       if (!vsi)
+               return;
+
+       kfree(vsi->rss_hkey_user);
+       vsi->rss_hkey_user = NULL;
+
+       kfree(vsi->rss_lut_user);
+       vsi->rss_lut_user = NULL;
+}
+
 /**
  * i40e_vsi_clear - Deallocate the VSI provided
  * @vsi: the VSI being un-configured
@@ -7318,6 +7357,7 @@ static int i40e_vsi_clear(struct i40e_vsi *vsi)
        i40e_put_lump(pf->irq_pile, vsi->base_vector, vsi->idx);
 
        i40e_vsi_free_arrays(vsi, true);
+       i40e_clear_rss_config_user(vsi);
 
        pf->vsi[vsi->idx] = NULL;
        if (vsi->idx < pf->next_vsi)
@@ -7780,7 +7820,8 @@ static int i40e_setup_misc_vector(struct i40e_pf *pf)
  * @vsi: vsi structure
  * @seed: RSS hash seed
  **/
-static int i40e_config_rss_aq(struct i40e_vsi *vsi, const u8 *seed)
+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;
@@ -7833,43 +7874,57 @@ 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;
 
-       netdev_rss_key_fill((void *)seed, I40E_HKEY_ARRAY_SIZE);
-       vsi->rss_size = min_t(int, pf->rss_size, vsi->num_queue_pairs);
+       if (!(pf->flags & I40E_FLAG_RSS_AQ_CAPABLE))
+               return 0;
 
-       if (pf->flags & I40E_FLAG_RSS_AQ_CAPABLE)
-               return i40e_config_rss_aq(vsi, seed);
+       lut = kzalloc(vsi->rss_table_size, GFP_KERNEL);
+       if (!lut)
+               return -ENOMEM;
 
-       return 0;
+       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);
+
+       return ret;
 }
 
 /**
- * i40e_config_rss_reg - Prepare for RSS if used
- * @pf: board private structure
+ * i40e_config_rss_reg - Configure RSS keys and lut by writing registers
+ * @vsi: Pointer to vsi structure
  * @seed: RSS hash seed
+ * @lut: Lookup table
+ * @lut_size: Lookup table size
+ *
+ * Returns 0 on success, negative on failure
  **/
-static int i40e_config_rss_reg(struct i40e_pf *pf, const u8 *seed)
+static int i40e_config_rss_reg(struct i40e_vsi *vsi, const u8 *seed,
+                              const u8 *lut, u16 lut_size)
 {
-       struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
+       struct i40e_pf *pf = vsi->back;
        struct i40e_hw *hw = &pf->hw;
-       u32 *seed_dw = (u32 *)seed;
-       u32 current_queue = 0;
-       u32 lut = 0;
-       int i, j;
+       u8 i;
 
        /* Fill out hash function seed */
-       for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++)
-               wr32(hw, I40E_PFQF_HKEY(i), seed_dw[i]);
+       if (seed) {
+               u32 *seed_dw = (u32 *)seed;
 
-       for (i = 0; i <= I40E_PFQF_HLUT_MAX_INDEX; i++) {
-               lut = 0;
-               for (j = 0; j < 4; j++) {
-                       if (current_queue == vsi->rss_size)
-                               current_queue = 0;
-                       lut |= ((current_queue) << (8 * j));
-                       current_queue++;
-               }
-               wr32(&pf->hw, I40E_PFQF_HLUT(i), lut);
+               for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++)
+                       wr32(hw, I40E_PFQF_HKEY(i), seed_dw[i]);
+       }
+
+       if (lut) {
+               u32 *lut_dw = (u32 *)lut;
+
+               if (lut_size != I40E_HLUT_ARRAY_SIZE)
+                       return -EINVAL;
+
+               for (i = 0; i <= I40E_PFQF_HLUT_MAX_INDEX; i++)
+                       wr32(hw, I40E_PFQF_HLUT(i), lut_dw[i]);
        }
        i40e_flush(hw);
 
@@ -7877,18 +7932,101 @@ static int i40e_config_rss_reg(struct i40e_pf *pf, const u8 *seed)
 }
 
 /**
- * i40e_config_rss - Prepare for RSS if used
+ * i40e_get_rss_reg - Get the RSS keys and lut by reading registers
+ * @vsi: Pointer to VSI structure
+ * @seed: Buffer to store the keys
+ * @lut: Buffer to store the lookup table entries
+ * @lut_size: Size of buffer to store the lookup table entries
+ *
+ * Returns 0 on success, negative on failure
+ */
+static int i40e_get_rss_reg(struct i40e_vsi *vsi, u8 *seed,
+                           u8 *lut, u16 lut_size)
+{
+       struct i40e_pf *pf = vsi->back;
+       struct i40e_hw *hw = &pf->hw;
+       u16 i;
+
+       if (seed) {
+               u32 *seed_dw = (u32 *)seed;
+
+               for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++)
+                       seed_dw[i] = rd32(hw, I40E_PFQF_HKEY(i));
+       }
+       if (lut) {
+               u32 *lut_dw = (u32 *)lut;
+
+               if (lut_size != I40E_HLUT_ARRAY_SIZE)
+                       return -EINVAL;
+               for (i = 0; i <= I40E_PFQF_HLUT_MAX_INDEX; i++)
+                       lut_dw[i] = rd32(hw, I40E_PFQF_HLUT(i));
+       }
+
+       return 0;
+}
+
+/**
+ * i40e_config_rss - Configure RSS keys and lut
+ * @vsi: Pointer to VSI structure
+ * @seed: RSS hash seed
+ * @lut: Lookup table
+ * @lut_size: Lookup table size
+ *
+ * Returns 0 on success, negative on failure
+ */
+int i40e_config_rss(struct i40e_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size)
+{
+       struct i40e_pf *pf = vsi->back;
+
+       if (pf->flags & I40E_FLAG_RSS_AQ_CAPABLE)
+               return i40e_config_rss_aq(vsi, seed, lut, lut_size);
+       else
+               return i40e_config_rss_reg(vsi, seed, lut, lut_size);
+}
+
+/**
+ * i40e_get_rss - Get RSS keys and lut
+ * @vsi: Pointer to VSI structure
+ * @seed: Buffer to store the keys
+ * @lut: Buffer to store the lookup table entries
+ * lut_size: Size of buffer to store the lookup table entries
+ *
+ * Returns 0 on success, negative on failure
+ */
+int i40e_get_rss(struct i40e_vsi *vsi, u8 *seed, u8 *lut, u16 lut_size)
+{
+       return i40e_get_rss_reg(vsi, seed, lut, lut_size);
+}
+
+/**
+ * i40e_fill_rss_lut - Fill the RSS lookup table with default values
+ * @pf: Pointer to board private structure
+ * @lut: Lookup table
+ * @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)
+{
+       u16 i;
+
+       for (i = 0; i < rss_table_size; i++)
+               lut[i] = i % rss_size;
+}
+
+/**
+ * i40e_pf_config_rss - Prepare for RSS if used
  * @pf: board private structure
  **/
-static int i40e_config_rss(struct i40e_pf *pf)
+static int i40e_pf_config_rss(struct i40e_pf *pf)
 {
        struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
        u8 seed[I40E_HKEY_ARRAY_SIZE];
+       u8 *lut;
        struct i40e_hw *hw = &pf->hw;
        u32 reg_val;
        u64 hena;
-
-       netdev_rss_key_fill((void *)seed, I40E_HKEY_ARRAY_SIZE);
+       int ret;
 
        /* By default we enable TCP/UDP with IPv4/IPv6 ptypes */
        hena = (u64)rd32(hw, I40E_PFQF_HENA(0)) |
@@ -7898,8 +8036,6 @@ static int i40e_config_rss(struct i40e_pf *pf)
        wr32(hw, I40E_PFQF_HENA(0), (u32)hena);
        wr32(hw, I40E_PFQF_HENA(1), (u32)(hena >> 32));
 
-       vsi->rss_size = min_t(int, pf->rss_size, vsi->num_queue_pairs);
-
        /* Determine the RSS table size based on the hardware capabilities */
        reg_val = rd32(hw, I40E_PFQF_CTL_0);
        reg_val = (pf->rss_table_size == 512) ?
@@ -7907,10 +8043,32 @@ static int i40e_config_rss(struct i40e_pf *pf)
                        (reg_val & ~I40E_PFQF_CTL_0_HASHLUTSIZE_512);
        wr32(hw, I40E_PFQF_CTL_0, reg_val);
 
-       if (pf->flags & I40E_FLAG_RSS_AQ_CAPABLE)
-               return i40e_config_rss_aq(pf->vsi[pf->lan_vsi], seed);
+       /* Determine the RSS size of the VSI */
+       if (!vsi->rss_size)
+               vsi->rss_size = min_t(int, pf->alloc_rss_size,
+                                     vsi->num_queue_pairs);
+
+       lut = kzalloc(vsi->rss_table_size, GFP_KERNEL);
+       if (!lut)
+               return -ENOMEM;
+
+       /* Use user configured lut 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);
+
+       /* Use user configured hash key if there is one, otherwise
+        * use default.
+        */
+       if (vsi->rss_hkey_user)
+               memcpy(seed, vsi->rss_hkey_user, I40E_HKEY_ARRAY_SIZE);
        else
-               return i40e_config_rss_reg(pf, seed);
+               netdev_rss_key_fill((void *)seed, I40E_HKEY_ARRAY_SIZE);
+       ret = i40e_config_rss(vsi, seed, lut, vsi->rss_table_size);
+       kfree(lut);
+
+       return ret;
 }
 
 /**
@@ -7935,13 +8093,28 @@ int i40e_reconfig_rss_queues(struct i40e_pf *pf, int queue_count)
                vsi->req_queue_pairs = queue_count;
                i40e_prep_for_reset(pf);
 
-               pf->rss_size = new_rss_size;
+               pf->alloc_rss_size = new_rss_size;
 
                i40e_reset_and_rebuild(pf, true);
-               i40e_config_rss(pf);
+
+               /* Discard the user configured hash keys and lut, if less
+                * queues are enabled.
+                */
+               if (queue_count < vsi->rss_size) {
+                       i40e_clear_rss_config_user(vsi);
+                       dev_dbg(&pf->pdev->dev,
+                               "discard user configured hash keys and lut\n");
+               }
+
+               /* Reset vsi->rss_size, as number of enabled queues changed */
+               vsi->rss_size = min_t(int, pf->alloc_rss_size,
+                                     vsi->num_queue_pairs);
+
+               i40e_pf_config_rss(pf);
        }
-       dev_info(&pf->pdev->dev, "RSS count:  %d\n", pf->rss_size);
-       return pf->rss_size;
+       dev_info(&pf->pdev->dev, "RSS count/HW max RSS count:  %d/%d\n",
+                pf->alloc_rss_size, pf->rss_size_max);
+       return pf->alloc_rss_size;
 }
 
 /**
@@ -8112,13 +8285,14 @@ static int i40e_sw_init(struct i40e_pf *pf)
         * maximum might end up larger than the available queues
         */
        pf->rss_size_max = BIT(pf->hw.func_caps.rss_table_entry_width);
-       pf->rss_size = 1;
+       pf->alloc_rss_size = 1;
        pf->rss_table_size = pf->hw.func_caps.rss_table_size;
        pf->rss_size_max = min_t(int, pf->rss_size_max,
                                 pf->hw.func_caps.num_tx_qp);
        if (pf->hw.func_caps.rss) {
                pf->flags |= I40E_FLAG_RSS_ENABLED;
-               pf->rss_size = min_t(int, pf->rss_size_max, num_online_cpus());
+               pf->alloc_rss_size = min_t(int, pf->rss_size_max,
+                                          num_online_cpus());
        }
 
        /* MFP mode enabled */
@@ -9051,7 +9225,7 @@ int i40e_vsi_release(struct i40e_vsi *vsi)
                                f->is_vf, f->is_netdev);
        spin_unlock_bh(&vsi->mac_filter_list_lock);
 
-       i40e_sync_vsi_filters(vsi, false);
+       i40e_sync_vsi_filters(vsi);
 
        i40e_vsi_delete(vsi);
        i40e_vsi_free_q_vectors(vsi);
@@ -9947,7 +10121,7 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit)
         * the hash
         */
        if ((pf->flags & I40E_FLAG_RSS_ENABLED))
-               i40e_config_rss(pf);
+               i40e_pf_config_rss(pf);
 
        /* fill in link information and enable LSE reporting */
        i40e_update_link_info(&pf->hw);
@@ -9985,7 +10159,7 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf)
            !(pf->flags & I40E_FLAG_MSIX_ENABLED)) {
                /* one qp for PF, no queues for anything else */
                queues_left = 0;
-               pf->rss_size = pf->num_lan_qps = 1;
+               pf->alloc_rss_size = pf->num_lan_qps = 1;
 
                /* make sure all the fancies are disabled */
                pf->flags &= ~(I40E_FLAG_RSS_ENABLED    |
@@ -10002,7 +10176,7 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf)
                                  I40E_FLAG_FD_ATR_ENABLED |
                                  I40E_FLAG_DCB_CAPABLE))) {
                /* one qp for PF */
-               pf->rss_size = pf->num_lan_qps = 1;
+               pf->alloc_rss_size = pf->num_lan_qps = 1;
                queues_left -= pf->num_lan_qps;
 
                pf->flags &= ~(I40E_FLAG_RSS_ENABLED    |
@@ -10072,8 +10246,9 @@ static void i40e_determine_queue_usage(struct i40e_pf *pf)
                "qs_avail=%d FD SB=%d lan_qs=%d lan_tc0=%d vf=%d*%d vmdq=%d*%d, remaining=%d\n",
                pf->hw.func_caps.num_tx_qp,
                !!(pf->flags & I40E_FLAG_FD_SB_ENABLED),
-               pf->num_lan_qps, pf->rss_size, pf->num_req_vfs, pf->num_vf_qps,
-               pf->num_vmdq_vsis, pf->num_vmdq_qps, queues_left);
+               pf->num_lan_qps, pf->alloc_rss_size, pf->num_req_vfs,
+               pf->num_vf_qps, pf->num_vmdq_vsis, pf->num_vmdq_qps,
+               queues_left);
 #ifdef I40E_FCOE
        dev_dbg(&pf->pdev->dev, "fcoe queues = %d\n", pf->num_fcoe_qps);
 #endif
@@ -10111,55 +10286,53 @@ static int i40e_setup_pf_filter_control(struct i40e_pf *pf)
 }
 
 #define INFO_STRING_LEN 255
+#define REMAIN(__x) (INFO_STRING_LEN - (__x))
 static void i40e_print_features(struct i40e_pf *pf)
 {
        struct i40e_hw *hw = &pf->hw;
-       char *buf, *string;
+       char *buf;
+       int i;
 
-       string = kzalloc(INFO_STRING_LEN, GFP_KERNEL);
-       if (!string) {
-               dev_err(&pf->pdev->dev, "Features string allocation failed\n");
+       buf = kmalloc(INFO_STRING_LEN, GFP_KERNEL);
+       if (!buf)
                return;
-       }
-
-       buf = string;
 
-       buf += sprintf(string, "Features: PF-id[%d] ", hw->pf_id);
+       i = snprintf(buf, INFO_STRING_LEN, "Features: PF-id[%d]", hw->pf_id);
 #ifdef CONFIG_PCI_IOV
-       buf += sprintf(buf, "VFs: %d ", pf->num_req_vfs);
+       i += snprintf(&buf[i], REMAIN(i), " VFs: %d", pf->num_req_vfs);
 #endif
-       buf += sprintf(buf, "VSIs: %d QP: %d RX: %s ",
-                      pf->hw.func_caps.num_vsis,
-                      pf->vsi[pf->lan_vsi]->num_queue_pairs,
-                      pf->flags & I40E_FLAG_RX_PS_ENABLED ? "PS" : "1BUF");
+       i += snprintf(&buf[i], REMAIN(i), " VSIs: %d QP: %d RX: %s",
+                     pf->hw.func_caps.num_vsis,
+                     pf->vsi[pf->lan_vsi]->num_queue_pairs,
+                     pf->flags & I40E_FLAG_RX_PS_ENABLED ? "PS" : "1BUF");
 
        if (pf->flags & I40E_FLAG_RSS_ENABLED)
-               buf += sprintf(buf, "RSS ");
+               i += snprintf(&buf[i], REMAIN(i), " RSS");
        if (pf->flags & I40E_FLAG_FD_ATR_ENABLED)
-               buf += sprintf(buf, "FD_ATR ");
+               i += snprintf(&buf[i], REMAIN(i), " FD_ATR");
        if (pf->flags & I40E_FLAG_FD_SB_ENABLED) {
-               buf += sprintf(buf, "FD_SB ");
-               buf += sprintf(buf, "NTUPLE ");
+               i += snprintf(&buf[i], REMAIN(i), " FD_SB");
+               i += snprintf(&buf[i], REMAIN(i), " NTUPLE");
        }
        if (pf->flags & I40E_FLAG_DCB_CAPABLE)
-               buf += sprintf(buf, "DCB ");
+               i += snprintf(&buf[i], REMAIN(i), " DCB");
 #if IS_ENABLED(CONFIG_VXLAN)
-       buf += sprintf(buf, "VxLAN ");
+       i += snprintf(&buf[i], REMAIN(i), " VxLAN");
 #endif
        if (pf->flags & I40E_FLAG_PTP)
-               buf += sprintf(buf, "PTP ");
+               i += snprintf(&buf[i], REMAIN(i), " PTP");
 #ifdef I40E_FCOE
        if (pf->flags & I40E_FLAG_FCOE_ENABLED)
-               buf += sprintf(buf, "FCOE ");
+               i += snprintf(&buf[i], REMAIN(i), " FCOE");
 #endif
        if (pf->flags & I40E_FLAG_VEB_MODE_ENABLED)
-               buf += sprintf(buf, "VEB ");
+               i += snprintf(&buf[i], REMAIN(i), " VEB");
        else
-               buf += sprintf(buf, "VEPA ");
+               i += snprintf(&buf[i], REMAIN(i), " VEPA");
 
-       BUG_ON(buf > (string + INFO_STRING_LEN));
-       dev_info(&pf->pdev->dev, "%s\n", string);
-       kfree(string);
+       dev_info(&pf->pdev->dev, "%s\n", buf);
+       kfree(buf);
+       WARN_ON(i > INFO_STRING_LEN);
 }
 
 /**
@@ -10183,6 +10356,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        u16 link_status;
        int err;
        u32 len;
+       u32 val;
        u32 i;
        u8 set_fc_aq_fail;
 
@@ -10296,6 +10470,16 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        pf->hw.fc.requested_mode = I40E_FC_NONE;
 
        err = i40e_init_adminq(hw);
+       if (err) {
+               if (err == I40E_ERR_FIRMWARE_API_VERSION)
+                       dev_info(&pdev->dev,
+                                "The driver for the device stopped because the NVM image is newer than expected. You must install the most recent version of the network driver.\n");
+               else
+                       dev_info(&pdev->dev,
+                                "The driver for the device stopped because the device firmware failed to init. Try updating your NVM image.\n");
+
+               goto err_pf_reset;
+       }
 
        /* provide nvm, fw, api versions */
        dev_info(&pdev->dev, "fw %d.%d.%05d api %d.%d nvm %s\n",
@@ -10303,12 +10487,6 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                 hw->aq.api_maj_ver, hw->aq.api_min_ver,
                 i40e_nvm_version_str(hw));
 
-       if (err) {
-               dev_info(&pdev->dev,
-                        "The driver for the device stopped because the NVM image is newer than expected. You must install the most recent version of the network driver.\n");
-               goto err_pf_reset;
-       }
-
        if (hw->aq.api_maj_ver == I40E_FW_API_VERSION_MAJOR &&
            hw->aq.api_min_ver > I40E_FW_API_VERSION_MINOR)
                dev_info(&pdev->dev,
@@ -10487,6 +10665,17 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                         i40e_stat_str(&pf->hw, err),
                         i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status));
 
+       /* Reconfigure hardware for allowing smaller MSS in the case
+        * of TSO, so that we avoid the MDD being fired and causing
+        * a reset in the case of small MSS+TSO.
+        */
+       val = rd32(hw, I40E_REG_MSS);
+       if ((val & I40E_REG_MSS_MIN_MASK) > I40E_64BYTE_MSS) {
+               val &= ~I40E_REG_MSS_MIN_MASK;
+               val |= I40E_64BYTE_MSS;
+               wr32(hw, I40E_REG_MSS, val);
+       }
+
        if (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 33)) ||
            (pf->hw.aq.fw_maj_ver < 4)) {
                msleep(75);