+ uint8_t *key = (void *)(uintptr_t)rss_conf->conf.key;
+ uint64_t hena;
+ int ret;
+
+ ret = i40e_set_rss_key(pf->main_vsi, key,
+ rss_conf->conf.key_len);
+ if (ret)
+ return ret;
+
+ hena = i40e_config_hena(pf->adapter, rss_conf->conf.types);
+ i40e_write_rx_ctl(hw, I40E_PFQF_HENA(0), (uint32_t)hena);
+ i40e_write_rx_ctl(hw, I40E_PFQF_HENA(1), (uint32_t)(hena >> 32));
+ I40E_WRITE_FLUSH(hw);
+
+ return 0;
+}
+
+/* Configure hash input set */
+static int
+i40e_rss_conf_hash_inset(struct i40e_pf *pf, uint64_t types)
+{
+ struct i40e_hw *hw = I40E_PF_TO_HW(pf);
+ struct rte_eth_input_set_conf conf;
+ uint64_t mask0;
+ int ret = 0;
+ uint32_t j;
+ int i;
+ static const struct {
+ uint64_t type;
+ enum rte_eth_input_set_field field;
+ } inset_match_table[] = {
+ {ETH_RSS_FRAG_IPV4 | ETH_RSS_L3_SRC_ONLY,
+ RTE_ETH_INPUT_SET_L3_SRC_IP4},
+ {ETH_RSS_FRAG_IPV4 | ETH_RSS_L3_DST_ONLY,
+ RTE_ETH_INPUT_SET_L3_DST_IP4},
+ {ETH_RSS_FRAG_IPV4 | ETH_RSS_L4_SRC_ONLY,
+ RTE_ETH_INPUT_SET_UNKNOWN},
+ {ETH_RSS_FRAG_IPV4 | ETH_RSS_L4_DST_ONLY,
+ RTE_ETH_INPUT_SET_UNKNOWN},
+
+ {ETH_RSS_NONFRAG_IPV4_TCP | ETH_RSS_L3_SRC_ONLY,
+ RTE_ETH_INPUT_SET_L3_SRC_IP4},
+ {ETH_RSS_NONFRAG_IPV4_TCP | ETH_RSS_L3_DST_ONLY,
+ RTE_ETH_INPUT_SET_L3_DST_IP4},
+ {ETH_RSS_NONFRAG_IPV4_TCP | ETH_RSS_L4_SRC_ONLY,
+ RTE_ETH_INPUT_SET_L4_TCP_SRC_PORT},
+ {ETH_RSS_NONFRAG_IPV4_TCP | ETH_RSS_L4_DST_ONLY,
+ RTE_ETH_INPUT_SET_L4_TCP_DST_PORT},
+
+ {ETH_RSS_NONFRAG_IPV4_UDP | ETH_RSS_L3_SRC_ONLY,
+ RTE_ETH_INPUT_SET_L3_SRC_IP4},
+ {ETH_RSS_NONFRAG_IPV4_UDP | ETH_RSS_L3_DST_ONLY,
+ RTE_ETH_INPUT_SET_L3_DST_IP4},
+ {ETH_RSS_NONFRAG_IPV4_UDP | ETH_RSS_L4_SRC_ONLY,
+ RTE_ETH_INPUT_SET_L4_UDP_SRC_PORT},
+ {ETH_RSS_NONFRAG_IPV4_UDP | ETH_RSS_L4_DST_ONLY,
+ RTE_ETH_INPUT_SET_L4_UDP_DST_PORT},
+
+ {ETH_RSS_NONFRAG_IPV4_SCTP | ETH_RSS_L3_SRC_ONLY,
+ RTE_ETH_INPUT_SET_L3_SRC_IP4},
+ {ETH_RSS_NONFRAG_IPV4_SCTP | ETH_RSS_L3_DST_ONLY,
+ RTE_ETH_INPUT_SET_L3_DST_IP4},
+ {ETH_RSS_NONFRAG_IPV4_SCTP | ETH_RSS_L4_SRC_ONLY,
+ RTE_ETH_INPUT_SET_L4_SCTP_SRC_PORT},
+ {ETH_RSS_NONFRAG_IPV4_SCTP | ETH_RSS_L4_DST_ONLY,
+ RTE_ETH_INPUT_SET_L4_SCTP_DST_PORT},
+
+ {ETH_RSS_NONFRAG_IPV4_OTHER | ETH_RSS_L3_SRC_ONLY,
+ RTE_ETH_INPUT_SET_L3_SRC_IP4},
+ {ETH_RSS_NONFRAG_IPV4_OTHER | ETH_RSS_L3_DST_ONLY,
+ RTE_ETH_INPUT_SET_L3_DST_IP4},
+ {ETH_RSS_NONFRAG_IPV4_OTHER | ETH_RSS_L4_SRC_ONLY,
+ RTE_ETH_INPUT_SET_UNKNOWN},
+ {ETH_RSS_NONFRAG_IPV4_OTHER | ETH_RSS_L4_DST_ONLY,
+ RTE_ETH_INPUT_SET_UNKNOWN},
+
+ {ETH_RSS_FRAG_IPV6 | ETH_RSS_L3_SRC_ONLY,
+ RTE_ETH_INPUT_SET_L3_SRC_IP6},
+ {ETH_RSS_FRAG_IPV6 | ETH_RSS_L3_DST_ONLY,
+ RTE_ETH_INPUT_SET_L3_DST_IP6},
+ {ETH_RSS_FRAG_IPV6 | ETH_RSS_L4_SRC_ONLY,
+ RTE_ETH_INPUT_SET_UNKNOWN},
+ {ETH_RSS_FRAG_IPV6 | ETH_RSS_L4_DST_ONLY,
+ RTE_ETH_INPUT_SET_UNKNOWN},
+
+ {ETH_RSS_NONFRAG_IPV6_TCP | ETH_RSS_L3_SRC_ONLY,
+ RTE_ETH_INPUT_SET_L3_SRC_IP6},
+ {ETH_RSS_NONFRAG_IPV6_TCP | ETH_RSS_L3_DST_ONLY,
+ RTE_ETH_INPUT_SET_L3_DST_IP6},
+ {ETH_RSS_NONFRAG_IPV6_TCP | ETH_RSS_L4_SRC_ONLY,
+ RTE_ETH_INPUT_SET_L4_TCP_SRC_PORT},
+ {ETH_RSS_NONFRAG_IPV6_TCP | ETH_RSS_L4_DST_ONLY,
+ RTE_ETH_INPUT_SET_L4_TCP_DST_PORT},
+
+ {ETH_RSS_NONFRAG_IPV6_UDP | ETH_RSS_L3_SRC_ONLY,
+ RTE_ETH_INPUT_SET_L3_SRC_IP6},
+ {ETH_RSS_NONFRAG_IPV6_UDP | ETH_RSS_L3_DST_ONLY,
+ RTE_ETH_INPUT_SET_L3_DST_IP6},
+ {ETH_RSS_NONFRAG_IPV6_UDP | ETH_RSS_L4_SRC_ONLY,
+ RTE_ETH_INPUT_SET_L4_UDP_SRC_PORT},
+ {ETH_RSS_NONFRAG_IPV6_UDP | ETH_RSS_L4_DST_ONLY,
+ RTE_ETH_INPUT_SET_L4_UDP_DST_PORT},
+
+ {ETH_RSS_NONFRAG_IPV6_SCTP | ETH_RSS_L3_SRC_ONLY,
+ RTE_ETH_INPUT_SET_L3_SRC_IP6},
+ {ETH_RSS_NONFRAG_IPV6_SCTP | ETH_RSS_L3_DST_ONLY,
+ RTE_ETH_INPUT_SET_L3_DST_IP6},
+ {ETH_RSS_NONFRAG_IPV6_SCTP | ETH_RSS_L4_SRC_ONLY,
+ RTE_ETH_INPUT_SET_L4_SCTP_SRC_PORT},
+ {ETH_RSS_NONFRAG_IPV6_SCTP | ETH_RSS_L4_DST_ONLY,
+ RTE_ETH_INPUT_SET_L4_SCTP_DST_PORT},
+
+ {ETH_RSS_NONFRAG_IPV6_OTHER | ETH_RSS_L3_SRC_ONLY,
+ RTE_ETH_INPUT_SET_L3_SRC_IP6},
+ {ETH_RSS_NONFRAG_IPV6_OTHER | ETH_RSS_L3_DST_ONLY,
+ RTE_ETH_INPUT_SET_L3_DST_IP6},
+ {ETH_RSS_NONFRAG_IPV6_OTHER | ETH_RSS_L4_SRC_ONLY,
+ RTE_ETH_INPUT_SET_UNKNOWN},
+ {ETH_RSS_NONFRAG_IPV6_OTHER | ETH_RSS_L4_DST_ONLY,
+ RTE_ETH_INPUT_SET_UNKNOWN},
+ };
+
+ mask0 = types & pf->adapter->flow_types_mask;
+ conf.op = RTE_ETH_INPUT_SET_SELECT;
+ conf.inset_size = 0;
+ for (i = RTE_ETH_FLOW_UNKNOWN + 1; i < RTE_ETH_FLOW_MAX; i++) {
+ if (mask0 & (1ULL << i)) {
+ conf.flow_type = i;
+ break;
+ }
+ }
+
+ for (j = 0; j < RTE_DIM(inset_match_table); j++) {
+ if ((types & inset_match_table[j].type) ==
+ inset_match_table[j].type) {
+ if (inset_match_table[j].field ==
+ RTE_ETH_INPUT_SET_UNKNOWN)
+ return -EINVAL;
+
+ conf.field[conf.inset_size] =
+ inset_match_table[j].field;
+ conf.inset_size++;
+ }
+ }
+
+ if (conf.inset_size) {
+ ret = i40e_hash_filter_inset_select(hw, &conf);
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+}
+
+/* Look up the conflicted rule then mark it as invalid */
+static void
+i40e_rss_mark_invalid_rule(struct i40e_pf *pf,
+ struct i40e_rte_flow_rss_conf *conf)
+{
+ struct i40e_rss_filter *rss_item;
+ uint64_t rss_inset;
+
+ /* Clear input set bits before comparing the pctype */
+ rss_inset = ~(ETH_RSS_L3_SRC_ONLY | ETH_RSS_L3_DST_ONLY |
+ ETH_RSS_L4_SRC_ONLY | ETH_RSS_L4_DST_ONLY);
+
+ /* Look up the conflicted rule then mark it as invalid */
+ TAILQ_FOREACH(rss_item, &pf->rss_config_list, next) {
+ if (!rss_item->rss_filter_info.valid)
+ continue;
+
+ if (conf->conf.queue_num &&
+ rss_item->rss_filter_info.conf.queue_num)
+ rss_item->rss_filter_info.valid = false;
+
+ if (conf->conf.types &&
+ (rss_item->rss_filter_info.conf.types &
+ rss_inset) ==
+ (conf->conf.types & rss_inset))
+ rss_item->rss_filter_info.valid = false;
+
+ if (conf->conf.func ==
+ RTE_ETH_HASH_FUNCTION_SIMPLE_XOR &&
+ rss_item->rss_filter_info.conf.func ==
+ RTE_ETH_HASH_FUNCTION_SIMPLE_XOR)
+ rss_item->rss_filter_info.valid = false;
+ }
+}
+
+/* Configure RSS hash function */
+static int
+i40e_rss_config_hash_function(struct i40e_pf *pf,
+ struct i40e_rte_flow_rss_conf *conf)
+{
+ struct i40e_hw *hw = I40E_PF_TO_HW(pf);
+ uint32_t reg, i;
+ uint64_t mask0;
+ uint16_t j;
+
+ if (conf->conf.func == RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) {
+ reg = i40e_read_rx_ctl(hw, I40E_GLQF_CTL);
+ if (!(reg & I40E_GLQF_CTL_HTOEP_MASK)) {
+ PMD_DRV_LOG(DEBUG, "Hash function already set to Simple XOR");
+ I40E_WRITE_FLUSH(hw);
+ i40e_rss_mark_invalid_rule(pf, conf);