i40e/i40evf: RSS changes for X722
authorAnjali Singhai Jain <anjali.singhai@intel.com>
Tue, 23 Jun 2015 23:00:04 +0000 (19:00 -0400)
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>
Wed, 5 Aug 2015 23:53:45 +0000 (16:53 -0700)
X722 uses the admin queue to configure RSS. This patch adds the necessary
flow changes to configure RSS through AQ. It also adds the separate VMDQ2
lookup tables and hash key programming for X722.

X722 also exposes a different set of PCTYPES for RSS, this patch
accommodates those changes.

Signed-off-by: Anjali Singhai Jain <anjali.singhai@intel.com>
Signed-off-by: Catherine Sullivan <catherine.sullivan@intel.com>
Signed-off-by: Mitch Williams <mitch.a.williams@intel.com>
Tested-by: Jim Young <james.m.young@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
drivers/net/ethernet/intel/i40e/i40e.h
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/intel/i40e/i40e_txrx.h
drivers/net/ethernet/intel/i40e/i40e_type.h
drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
drivers/net/ethernet/intel/i40evf/i40e_txrx.h
drivers/net/ethernet/intel/i40evf/i40e_type.h
drivers/net/ethernet/intel/i40evf/i40evf.h
drivers/net/ethernet/intel/i40evf/i40evf_main.c

index 99148861b1c0f19e54692ee76ebb18d6ac3efcf1..66d0780f12972e86818f8bca6729507eac0234c6 100644 (file)
 #define I40E_MIN_MSIX                 2
 #define I40E_DEFAULT_NUM_VMDQ_VSI     8 /* max 256 VSIs */
 #define I40E_MIN_VSI_ALLOC            51 /* LAN, ATR, FCOE, 32 VF, 16 VMDQ */
-#define I40E_DEFAULT_QUEUES_PER_VMDQ  2 /* max 16 qps */
+/* max 16 qps */
+#define i40e_default_queues_per_vmdq(pf) \
+               (((pf)->flags & I40E_FLAG_RSS_AQ_CAPABLE) ? 4 : 1)
 #define I40E_DEFAULT_QUEUES_PER_VF    4
 #define I40E_DEFAULT_QUEUES_PER_TC    1 /* should be a power of 2 */
-#define I40E_MAX_QUEUES_PER_TC        64 /* should be a power of 2 */
+#define i40e_pf_get_max_q_per_tc(pf) \
+               (((pf)->flags & I40E_FLAG_128_QP_RSS_CAPABLE) ? 128 : 64)
 #define I40E_FDIR_RING                0
 #define I40E_FDIR_RING_COUNT          32
 #ifdef I40E_FCOE
index 3269b059762ee726027da10b1a7d9c4987a4f14b..2e84165606328022c4e6fbaa45ec9ea0690cd6df 100644 (file)
@@ -1550,7 +1550,7 @@ static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi,
         */
        qcount = min_t(int, vsi->alloc_queue_pairs, pf->num_lan_msix);
        num_tc_qps = qcount / numtc;
-       num_tc_qps = min_t(int, num_tc_qps, I40E_MAX_QUEUES_PER_TC);
+       num_tc_qps = min_t(int, num_tc_qps, i40e_pf_get_max_q_per_tc(pf));
 
        /* Setup queue offset/count for all TCs for given VSI */
        for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
@@ -7469,62 +7469,139 @@ static int i40e_setup_misc_vector(struct i40e_pf *pf)
 }
 
 /**
- * i40e_config_rss - Prepare for RSS if used
+ * i40e_config_rss_aq - Prepare for RSS using AQ commands
+ * @vsi: vsi structure
+ * @seed: RSS hash seed
+ **/
+static int i40e_config_rss_aq(struct i40e_vsi *vsi, const u8 *seed)
+{
+       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;
+
+       memset(&rss_key, 0, sizeof(rss_key));
+       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;
+
+       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));
+               return ret;
+       }
+
+       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));
+
+       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;
+
+       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 i40e_config_rss_aq(vsi, seed);
+
+       return 0;
+}
+
+/**
+ * i40e_config_rss_reg - Prepare for RSS if used
  * @pf: board private structure
+ * @seed: RSS hash seed
  **/
-static int i40e_config_rss(struct i40e_pf *pf)
+static int i40e_config_rss_reg(struct i40e_pf *pf, const u8 *seed)
 {
-       u32 rss_key[I40E_PFQF_HKEY_MAX_INDEX + 1];
        struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
        struct i40e_hw *hw = &pf->hw;
+       u32 *seed_dw = (u32 *)seed;
+       u32 current_queue = 0;
        u32 lut = 0;
        int i, j;
-       u64 hena;
-       u32 reg_val;
 
-       netdev_rss_key_fill(rss_key, sizeof(rss_key));
+       /* Fill out hash function seed */
        for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++)
-               wr32(hw, I40E_PFQF_HKEY(i), rss_key[i]);
+               wr32(hw, I40E_PFQF_HKEY(i), seed_dw[i]);
+
+       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);
+       }
+       i40e_flush(hw);
+
+       return 0;
+}
+
+/**
+ * i40e_config_rss - Prepare for RSS if used
+ * @pf: board private structure
+ **/
+static int i40e_config_rss(struct i40e_pf *pf)
+{
+       struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
+       u8 seed[I40E_HKEY_ARRAY_SIZE];
+       struct i40e_hw *hw = &pf->hw;
+       u32 reg_val;
+       u64 hena;
+
+       netdev_rss_key_fill((void *)seed, I40E_HKEY_ARRAY_SIZE);
 
        /* By default we enable TCP/UDP with IPv4/IPv6 ptypes */
        hena = (u64)rd32(hw, I40E_PFQF_HENA(0)) |
                ((u64)rd32(hw, I40E_PFQF_HENA(1)) << 32);
-       hena |= I40E_DEFAULT_RSS_HENA;
+       hena |= i40e_pf_get_default_rss_hena(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);
 
-       /* Check capability and Set table size and register per hw expectation*/
+       /* Determine the RSS table size based on the hardware capabilities */
        reg_val = rd32(hw, I40E_PFQF_CTL_0);
-       if (pf->rss_table_size == 512)
-               reg_val |= I40E_PFQF_CTL_0_HASHLUTSIZE_512;
-       else
-               reg_val &= ~I40E_PFQF_CTL_0_HASHLUTSIZE_512;
+       reg_val = (pf->rss_table_size == 512) ?
+                       (reg_val | I40E_PFQF_CTL_0_HASHLUTSIZE_512) :
+                       (reg_val & ~I40E_PFQF_CTL_0_HASHLUTSIZE_512);
        wr32(hw, I40E_PFQF_CTL_0, reg_val);
 
-       /* Populate the LUT with max no. of queues in round robin fashion */
-       for (i = 0, j = 0; i < pf->rss_table_size; i++, j++) {
-
-               /* The assumption is that lan qp count will be the highest
-                * qp count for any PF VSI that needs RSS.
-                * If multiple VSIs need RSS support, all the qp counts
-                * for those VSIs should be a power of 2 for RSS to work.
-                * If LAN VSI is the only consumer for RSS then this requirement
-                * is not necessary.
-                */
-               if (j == vsi->rss_size)
-                       j = 0;
-               /* lut = 4-byte sliding window of 4 lut entries */
-               lut = (lut << 8) | (j &
-                        (BIT(pf->hw.func_caps.rss_table_entry_width) - 1));
-               /* On i = 3, we have 4 entries in lut; write to the register */
-               if ((i & 3) == 3)
-                       wr32(hw, I40E_PFQF_HLUT(i >> 2), lut);
-       }
-       i40e_flush(hw);
-
-       return 0;
+       if (pf->flags & I40E_FLAG_RSS_AQ_CAPABLE)
+               return i40e_config_rss_aq(pf->vsi[pf->lan_vsi], seed);
+       else
+               return i40e_config_rss_reg(pf, seed);
 }
 
 /**
@@ -7765,9 +7842,8 @@ static int i40e_sw_init(struct i40e_pf *pf)
        }
 
        if (pf->hw.func_caps.vmdq) {
-               pf->flags |= I40E_FLAG_VMDQ_ENABLED;
                pf->num_vmdq_vsis = I40E_DEFAULT_NUM_VMDQ_VSI;
-               pf->num_vmdq_qps = I40E_DEFAULT_QUEUES_PER_VMDQ;
+               pf->flags |= I40E_FLAG_VMDQ_ENABLED;
        }
 
 #ifdef I40E_FCOE
@@ -8948,6 +9024,10 @@ struct i40e_vsi *i40e_vsi_setup(struct i40e_pf *pf, u8 type,
                break;
        }
 
+       if ((pf->flags & I40E_FLAG_RSS_AQ_CAPABLE) &&
+           (vsi->type == I40E_VSI_VMDQ2)) {
+               ret = i40e_vsi_config_rss(vsi);
+       }
        return vsi;
 
 err_rings:
index 429833c47245faa6cd3ad7d1e757b9668c169b05..8b618d0151cd2fa4be4b573ca97b1792e63185a1 100644 (file)
@@ -78,6 +78,18 @@ enum i40e_dyn_idx_t {
        BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV6) | \
        BIT_ULL(I40E_FILTER_PCTYPE_L2_PAYLOAD))
 
+#define I40E_DEFAULT_RSS_HENA_EXPANDED (I40E_DEFAULT_RSS_HENA | \
+       BIT(I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK) | \
+       BIT(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP) | \
+       BIT(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP) | \
+       BIT(I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK) | \
+       BIT(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP) | \
+       BIT(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP))
+
+#define i40e_pf_get_default_rss_hena(pf) \
+       (((pf)->flags & I40E_FLAG_MULTIPLE_TCP_UDP_RSS_PCTYPE) ? \
+         I40E_DEFAULT_RSS_HENA_EXPANDED : I40E_DEFAULT_RSS_HENA)
+
 /* Supported Rx Buffer Sizes */
 #define I40E_RXBUFFER_512   512    /* Used for packet split */
 #define I40E_RXBUFFER_2048  2048
index 778266fa41043177604bb1deeb583943a96bfe20..1ffd27143a3cd211ec1438b479b8732a6a24eaf2 100644 (file)
@@ -973,15 +973,24 @@ struct i40e_filter_program_desc {
 
 /* Packet Classifier Types for filters */
 enum i40e_filter_pctype {
-       /* Note: Values 0-30 are reserved for future use */
+       /* Note: Values 0-28 are reserved for future use.
+        * Value 29, 30, 32 are not supported on XL710 and X710.
+        */
+       I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP        = 29,
+       I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP      = 30,
        I40E_FILTER_PCTYPE_NONF_IPV4_UDP                = 31,
-       /* Note: Value 32 is reserved for future use */
+       I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK     = 32,
        I40E_FILTER_PCTYPE_NONF_IPV4_TCP                = 33,
        I40E_FILTER_PCTYPE_NONF_IPV4_SCTP               = 34,
        I40E_FILTER_PCTYPE_NONF_IPV4_OTHER              = 35,
        I40E_FILTER_PCTYPE_FRAG_IPV4                    = 36,
-       /* Note: Values 37-40 are reserved for future use */
+       /* Note: Values 37-38 are reserved for future use.
+        * Value 39, 40, 42 are not supported on XL710 and X710.
+        */
+       I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP        = 39,
+       I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP      = 40,
        I40E_FILTER_PCTYPE_NONF_IPV6_UDP                = 41,
+       I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK     = 42,
        I40E_FILTER_PCTYPE_NONF_IPV6_TCP                = 43,
        I40E_FILTER_PCTYPE_NONF_IPV6_SCTP               = 44,
        I40E_FILTER_PCTYPE_NONF_IPV6_OTHER              = 45,
index d29d4062addf51141dbeefc152d1613b8171c981..8a7607c6e142d05b247ff7b948e9c6599c22a91c 100644 (file)
@@ -1177,9 +1177,14 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg)
        vfres->vf_offload_flags = I40E_VIRTCHNL_VF_OFFLOAD_L2;
        vsi = pf->vsi[vf->lan_vsi_idx];
        if (!vsi->info.pvid)
-               vfres->vf_offload_flags |= I40E_VIRTCHNL_VF_OFFLOAD_VLAN |
-                                          I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG;
-
+               vfres->vf_offload_flags |= I40E_VIRTCHNL_VF_OFFLOAD_VLAN;
+       if (pf->flags & I40E_FLAG_RSS_AQ_CAPABLE) {
+               if (vf->driver_caps & I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ)
+                       vfres->vf_offload_flags |=
+                               I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ;
+       } else {
+               vfres->vf_offload_flags |= I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG;
+       }
        vfres->num_vsis = num_vsis;
        vfres->num_queue_pairs = vf->num_queue_pairs;
        vfres->max_vectors = pf->hw.func_caps.num_msix_vectors_vf;
index 6b47c818d1f08c11b81fd5e21b7ba9b162bdadd9..b2f9b8203c673a0720c588771bf2714039063474 100644 (file)
@@ -78,6 +78,18 @@ enum i40e_dyn_idx_t {
        BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV6) | \
        BIT_ULL(I40E_FILTER_PCTYPE_L2_PAYLOAD))
 
+#define I40E_DEFAULT_RSS_HENA_EXPANDED (I40E_DEFAULT_RSS_HENA | \
+               BIT(I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK) | \
+               BIT(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP) | \
+               BIT(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP) | \
+               BIT(I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK) | \
+               BIT(I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP) | \
+               BIT(I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP))
+
+#define i40e_pf_get_default_rss_hena(pf) \
+       (((pf)->flags & I40E_FLAG_MULTIPLE_TCP_UDP_RSS_PCTYPE) ? \
+               I40E_DEFAULT_RSS_HENA_EXPANDED : I40E_DEFAULT_RSS_HENA)
+
 /* Supported Rx Buffer Sizes */
 #define I40E_RXBUFFER_512   512    /* Used for packet split */
 #define I40E_RXBUFFER_2048  2048
index c50536b0e15c0c3f664c0de5bc9ae54359ad9f7d..627bf7689bbc5fc5c0b3f249a5a4ce9e399cfdca 100644 (file)
@@ -967,15 +967,24 @@ struct i40e_filter_program_desc {
 
 /* Packet Classifier Types for filters */
 enum i40e_filter_pctype {
-       /* Note: Values 0-30 are reserved for future use */
+       /* Note: Values 0-28 are reserved for future use.
+        * Value 29, 30, 32 are not supported on XL710 and X710.
+        */
+       I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP        = 29,
+       I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP      = 30,
        I40E_FILTER_PCTYPE_NONF_IPV4_UDP                = 31,
-       /* Note: Value 32 is reserved for future use */
+       I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK     = 32,
        I40E_FILTER_PCTYPE_NONF_IPV4_TCP                = 33,
        I40E_FILTER_PCTYPE_NONF_IPV4_SCTP               = 34,
        I40E_FILTER_PCTYPE_NONF_IPV4_OTHER              = 35,
        I40E_FILTER_PCTYPE_FRAG_IPV4                    = 36,
-       /* Note: Values 37-40 are reserved for future use */
+       /* Note: Values 37-38 are reserved for future use.
+        * Value 39, 40, 42 are not supported on XL710 and X710.
+        */
+       I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP        = 39,
+       I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP      = 40,
        I40E_FILTER_PCTYPE_NONF_IPV6_UDP                = 41,
+       I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK     = 42,
        I40E_FILTER_PCTYPE_NONF_IPV6_TCP                = 43,
        I40E_FILTER_PCTYPE_NONF_IPV6_SCTP               = 44,
        I40E_FILTER_PCTYPE_NONF_IPV6_OTHER              = 45,
index bd227b39ac550f60e7ab9b1997db55edf941a4ef..fa421d6020bea329b0a31ce0ccb85c7852a475e8 100644 (file)
@@ -101,6 +101,8 @@ struct i40e_vsi {
 #define MAX_RX_QUEUES 8
 #define MAX_TX_QUEUES MAX_RX_QUEUES
 
+#define I40EVF_HKEY_ARRAY_SIZE ((I40E_VFQF_HKEY_MAX_INDEX + 1) * 4)
+
 /* MAX_MSIX_Q_VECTORS of these are allocated,
  * but we only use one per queue-specific vector.
  */
index 642944e622af8b133431472424a04f4d35d9f8d9..2a6063a3a14d8dc2474ec3f91ad9cb3aad43aa2d 100644 (file)
@@ -1172,6 +1172,113 @@ out:
        return err;
 }
 
+/**
+ * i40e_configure_rss_aq - Prepare for RSS using AQ commands
+ * @vsi: vsi structure
+ * @seed: RSS hash seed
+ **/
+static void i40evf_configure_rss_aq(struct i40e_vsi *vsi, const u8 *seed)
+{
+       struct i40e_aqc_get_set_rss_key_data rss_key;
+       struct i40evf_adapter *adapter = vsi->back;
+       struct i40e_hw *hw = &adapter->hw;
+       int ret = 0, i;
+       u8 *rss_lut;
+
+       if (!vsi->id)
+               return;
+
+       if (adapter->current_op != I40E_VIRTCHNL_OP_UNKNOWN) {
+               /* bail because we already have a command pending */
+               dev_err(&adapter->pdev->dev, "Cannot confiure RSS, command %d pending\n",
+                       adapter->current_op);
+               return;
+       }
+
+       memset(&rss_key, 0, sizeof(rss_key));
+       memcpy(&rss_key, seed, sizeof(rss_key));
+
+       rss_lut = kzalloc(((I40E_VFQF_HLUT_MAX_INDEX + 1) * 4), GFP_KERNEL);
+       if (!rss_lut)
+               return;
+
+       /* Populate the LUT with max no. PF queues in round robin fashion */
+       for (i = 0; i <= (I40E_VFQF_HLUT_MAX_INDEX * 4); i++)
+               rss_lut[i] = i % adapter->num_active_queues;
+
+       ret = i40evf_aq_set_rss_key(hw, vsi->id, &rss_key);
+       if (ret) {
+               dev_err(&adapter->pdev->dev,
+                       "Cannot set RSS key, err %s aq_err %s\n",
+                       i40evf_stat_str(hw, ret),
+                       i40evf_aq_str(hw, hw->aq.asq_last_status));
+               return;
+       }
+
+       ret = i40evf_aq_set_rss_lut(hw, vsi->id, false, rss_lut,
+                                   (I40E_VFQF_HLUT_MAX_INDEX + 1) * 4);
+       if (ret)
+               dev_err(&adapter->pdev->dev,
+                       "Cannot set RSS lut, err %s aq_err %s\n",
+                       i40evf_stat_str(hw, ret),
+                       i40evf_aq_str(hw, hw->aq.asq_last_status));
+}
+
+/**
+ * i40e_configure_rss_reg - Prepare for RSS if used
+ * @adapter: board private structure
+ * @seed: RSS hash seed
+ **/
+static void i40evf_configure_rss_reg(struct i40evf_adapter *adapter,
+                                    const u8 *seed)
+{
+       struct i40e_hw *hw = &adapter->hw;
+       u32 *seed_dw = (u32 *)seed;
+       u32 cqueue = 0;
+       u32 lut = 0;
+       int i, j;
+
+       /* Fill out hash function seed */
+       for (i = 0; i <= I40E_VFQF_HKEY_MAX_INDEX; i++)
+               wr32(hw, I40E_VFQF_HKEY(i), seed_dw[i]);
+
+       /* Populate the LUT with max no. PF queues in round robin fashion */
+       for (i = 0; i <= I40E_VFQF_HLUT_MAX_INDEX; i++) {
+               lut = 0;
+               for (j = 0; j < 4; j++) {
+                       if (cqueue == adapter->num_active_queues)
+                               cqueue = 0;
+                       lut |= ((cqueue) << (8 * j));
+                       cqueue++;
+               }
+               wr32(hw, I40E_VFQF_HLUT(i), lut);
+       }
+       i40e_flush(hw);
+}
+
+/**
+ * i40evf_configure_rss - Prepare for RSS
+ * @adapter: board private structure
+ **/
+static void i40evf_configure_rss(struct i40evf_adapter *adapter)
+{
+       struct i40e_hw *hw = &adapter->hw;
+       u8 seed[I40EVF_HKEY_ARRAY_SIZE];
+       u64 hena;
+
+       netdev_rss_key_fill((void *)seed, I40EVF_HKEY_ARRAY_SIZE);
+
+       /* Enable PCTYPES for RSS, TCP/UDP with IPv4/IPv6 */
+       hena = I40E_DEFAULT_RSS_HENA;
+       wr32(hw, I40E_VFQF_HENA(0), (u32)hena);
+       wr32(hw, I40E_VFQF_HENA(1), (u32)(hena >> 32));
+
+       if (RSS_AQ(adapter))
+               i40evf_configure_rss_aq(&adapter->vsi, seed);
+       else
+               i40evf_configure_rss_reg(adapter, seed);
+}
+
 /**
  * i40evf_alloc_q_vectors - Allocate memory for interrupt vectors
  * @adapter: board private structure to initialize
@@ -1417,6 +1524,16 @@ static void i40evf_watchdog_task(struct work_struct *work)
                goto watchdog_done;
        }
 
+       if (adapter->aq_required & I40EVF_FLAG_AQ_CONFIGURE_RSS) {
+               /* This message goes straight to the firmware, not the
+                * PF, so we don't have to set current_op as we will
+                * not get a response through the ARQ.
+                */
+               i40evf_configure_rss(adapter);
+               adapter->aq_required &= ~I40EVF_FLAG_AQ_CONFIGURE_RSS;
+               goto watchdog_done;
+       }
+
        if (adapter->state == __I40EVF_RUNNING)
                i40evf_request_stats(adapter);
 watchdog_done:
@@ -1439,45 +1556,6 @@ restart_watchdog:
        schedule_work(&adapter->adminq_task);
 }
 
-/**
- * i40evf_configure_rss - Prepare for RSS
- * @adapter: board private structure
- **/
-static void i40evf_configure_rss(struct i40evf_adapter *adapter)
-{
-       u32 rss_key[I40E_VFQF_HKEY_MAX_INDEX + 1];
-       struct i40e_hw *hw = &adapter->hw;
-       u32 cqueue = 0;
-       u32 lut = 0;
-       int i, j;
-       u64 hena;
-
-       /* Hash type is configured by the PF - we just supply the key */
-       netdev_rss_key_fill(rss_key, sizeof(rss_key));
-
-       /* Fill out hash function seed */
-       for (i = 0; i <= I40E_VFQF_HKEY_MAX_INDEX; i++)
-               wr32(hw, I40E_VFQF_HKEY(i), rss_key[i]);
-
-       /* Enable PCTYPES for RSS, TCP/UDP with IPv4/IPv6 */
-       hena = I40E_DEFAULT_RSS_HENA;
-       wr32(hw, I40E_VFQF_HENA(0), (u32)hena);
-       wr32(hw, I40E_VFQF_HENA(1), (u32)(hena >> 32));
-
-       /* Populate the LUT with max no. of queues in round robin fashion */
-       for (i = 0; i <= I40E_VFQF_HLUT_MAX_INDEX; i++) {
-               lut = 0;
-               for (j = 0; j < 4; j++) {
-                       if (cqueue == adapter->num_active_queues)
-                               cqueue = 0;
-                       lut |= ((cqueue) << (8 * j));
-                       cqueue++;
-               }
-               wr32(hw, I40E_VFQF_HLUT(i), lut);
-       }
-       i40e_flush(hw);
-}
-
 #define I40EVF_RESET_WAIT_MS 10
 #define I40EVF_RESET_WAIT_COUNT 500
 /**
@@ -2187,7 +2265,8 @@ static void i40evf_init_task(struct work_struct *work)
        if (err)
                goto err_sw_init;
        i40evf_map_rings_to_vectors(adapter);
-       i40evf_configure_rss(adapter);
+       if (!RSS_AQ(adapter))
+               i40evf_configure_rss(adapter);
        err = i40evf_request_misc_irq(adapter);
        if (err)
                goto err_sw_init;
@@ -2212,6 +2291,13 @@ static void i40evf_init_task(struct work_struct *work)
        adapter->state = __I40EVF_DOWN;
        set_bit(__I40E_DOWN, &adapter->vsi.state);
        i40evf_misc_irq_enable(adapter);
+
+       if (RSS_AQ(adapter)) {
+               adapter->aq_required |= I40EVF_FLAG_AQ_CONFIGURE_RSS;
+               mod_timer_pending(&adapter->watchdog_timer, jiffies + 1);
+       } else {
+               i40evf_configure_rss(adapter);
+       }
        return;
 restart:
        schedule_delayed_work(&adapter->init_task,