diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 99148861b1c0f19e54692ee76ebb18d6ac3efcf1..66d0780f12972e86818f8bca6729507eac0234c6 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -79,10 +79,13 @@ #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 diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 3269b059762ee726027da10b1a7d9c4987a4f14b..2e84165606328022c4e6fbaa45ec9ea0690cd6df 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -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: diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h index 429833c47245faa6cd3ad7d1e757b9668c169b05..8b618d0151cd2fa4be4b573ca97b1792e63185a1 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h @@ -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 diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index 778266fa41043177604bb1deeb583943a96bfe20..1ffd27143a3cd211ec1438b479b8732a6a24eaf2 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -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, diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index d29d4062addf51141dbeefc152d1613b8171c981..8a7607c6e142d05b247ff7b948e9c6599c22a91c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -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; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.h b/drivers/net/ethernet/intel/i40evf/i40e_txrx.h index 6b47c818d1f08c11b81fd5e21b7ba9b162bdadd9..b2f9b8203c673a0720c588771bf2714039063474 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.h @@ -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 diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h index c50536b0e15c0c3f664c0de5bc9ae54359ad9f7d..627bf7689bbc5fc5c0b3f249a5a4ce9e399cfdca 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_type.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h @@ -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, diff --git a/drivers/net/ethernet/intel/i40evf/i40evf.h b/drivers/net/ethernet/intel/i40evf/i40evf.h index bd227b39ac550f60e7ab9b1997db55edf941a4ef..fa421d6020bea329b0a31ce0ccb85c7852a475e8 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf.h +++ b/drivers/net/ethernet/intel/i40evf/i40evf.h @@ -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. */ diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 642944e622af8b133431472424a04f4d35d9f8d9..2a6063a3a14d8dc2474ec3f91ad9cb3aad43aa2d 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -1172,6 +1172,113 @@ static int i40evf_set_interrupt_capability(struct i40evf_adapter *adapter) 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 @@ static void i40evf_watchdog_task(struct work_struct *work) 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,