Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[cascardo/linux.git] / drivers / net / ethernet / intel / i40e / i40e_main.c
index d0b3a1b..61b0fc4 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 12
 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \
             __stringify(DRV_VERSION_MINOR) "." \
             __stringify(DRV_VERSION_BUILD)    DRV_KERN
@@ -527,6 +527,7 @@ void i40e_pf_reset_stats(struct i40e_pf *pf)
                        pf->veb[i]->stat_offsets_loaded = false;
                }
        }
+       pf->hw_csum_rx_error = 0;
 }
 
 /**
@@ -4616,7 +4617,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 +4635,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++;
@@ -7990,72 +7989,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 +8066,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
@@ -8695,6 +8696,28 @@ bool i40e_set_ntuple(struct i40e_pf *pf, netdev_features_t features)
        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 +8731,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
@@ -11582,7 +11611,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;