-int
-i40e_rss_conf_init(struct i40e_rte_flow_rss_conf *out,
- const struct rte_flow_action_rss *in)
-{
- if (in->key_len > RTE_DIM(out->key) ||
- in->queue_num > RTE_DIM(out->queue))
- return -EINVAL;
- if (!in->key && in->key_len)
- return -EINVAL;
- out->conf = (struct rte_flow_action_rss){
- .func = in->func,
- .level = in->level,
- .types = in->types,
- .key_len = in->key_len,
- .queue_num = in->queue_num,
- .queue = memcpy(out->queue, in->queue,
- sizeof(*in->queue) * in->queue_num),
- };
- if (in->key)
- out->conf.key = memcpy(out->key, in->key, in->key_len);
- return 0;
-}
-
-/* Write HENA register to enable hash */
-static int
-i40e_rss_hash_set(struct i40e_pf *pf, struct i40e_rte_flow_rss_conf *rss_conf)
-{
- struct i40e_hw *hw = I40E_PF_TO_HW(pf);
- 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);
-
- return 0;
- }
- reg &= ~I40E_GLQF_CTL_HTOEP_MASK;
-
- i40e_write_global_rx_ctl(hw, I40E_GLQF_CTL, reg);
- I40E_WRITE_FLUSH(hw);
- i40e_rss_mark_invalid_rule(pf, conf);
- } else if (conf->conf.func ==
- RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ) {
- mask0 = conf->conf.types & pf->adapter->flow_types_mask;
-
- i40e_set_symmetric_hash_enable_per_port(hw, 1);
- for (i = RTE_ETH_FLOW_UNKNOWN + 1; i < UINT64_BIT; i++) {
- if (mask0 & (1UL << i))
- break;
- }
-
- if (i == UINT64_BIT)
- return -EINVAL;
-
- for (j = I40E_FILTER_PCTYPE_INVALID + 1;
- j < I40E_FILTER_PCTYPE_MAX; j++) {
- if (pf->adapter->pctypes_tbl[i] & (1ULL << j))
- i40e_write_global_rx_ctl(hw,
- I40E_GLQF_HSYM(j),
- I40E_GLQF_HSYM_SYMH_ENA_MASK);
- }
- }
-
- return 0;
-}
-
-/* Enable RSS according to the configuration */
-static int
-i40e_rss_enable_hash(struct i40e_pf *pf,
- struct i40e_rte_flow_rss_conf *conf)
-{
- struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info;
- struct i40e_rte_flow_rss_conf rss_conf;
-
- if (!(conf->conf.types & pf->adapter->flow_types_mask))
- return -ENOTSUP;
-
- memset(&rss_conf, 0, sizeof(rss_conf));
- rte_memcpy(&rss_conf, conf, sizeof(rss_conf));
-
- /* Configure hash input set */
- if (i40e_rss_conf_hash_inset(pf, conf->conf.types))
- return -EINVAL;
-
- if (rss_conf.conf.key == NULL || rss_conf.conf.key_len <
- (I40E_PFQF_HKEY_MAX_INDEX + 1) * sizeof(uint32_t)) {
- /* Random default keys */
- static uint32_t rss_key_default[] = {0x6b793944,
- 0x23504cb5, 0x5bea75b6, 0x309f4f12, 0x3dc0a2b8,
- 0x024ddcdf, 0x339b8ca0, 0x4c4af64a, 0x34fac605,
- 0x55d85839, 0x3a58997d, 0x2ec938e1, 0x66031581};
-
- rss_conf.conf.key = (uint8_t *)rss_key_default;
- rss_conf.conf.key_len = (I40E_PFQF_HKEY_MAX_INDEX + 1) *
- sizeof(uint32_t);
- PMD_DRV_LOG(INFO,
- "No valid RSS key config for i40e, using default\n");
- }
-
- rss_conf.conf.types |= rss_info->conf.types;
- i40e_rss_hash_set(pf, &rss_conf);
-
- if (conf->conf.func == RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ)
- i40e_rss_config_hash_function(pf, conf);
-
- i40e_rss_mark_invalid_rule(pf, conf);
-
- return 0;
-}
-
-/* Configure RSS queue region */
-static int
-i40e_rss_config_queue_region(struct i40e_pf *pf,
- struct i40e_rte_flow_rss_conf *conf)
-{
- struct i40e_hw *hw = I40E_PF_TO_HW(pf);
- uint32_t lut = 0;
- uint16_t j, num;
- uint32_t i;
-
- /* If both VMDQ and RSS enabled, not all of PF queues are configured.
- * It's necessary to calculate the actual PF queues that are configured.
- */
- if (pf->dev_data->dev_conf.rxmode.mq_mode & ETH_MQ_RX_VMDQ_FLAG)
- num = i40e_pf_calc_configured_queues_num(pf);
- else
- num = pf->dev_data->nb_rx_queues;
-
- num = RTE_MIN(num, conf->conf.queue_num);
- PMD_DRV_LOG(INFO, "Max of contiguous %u PF queues are configured",
- num);
-
- if (num == 0) {
- PMD_DRV_LOG(ERR,
- "No PF queues are configured to enable RSS for port %u",
- pf->dev_data->port_id);
- return -ENOTSUP;
- }
-
- /* Fill in redirection table */
- for (i = 0, j = 0; i < hw->func_caps.rss_table_size; i++, j++) {
- if (j == num)
- j = 0;
- lut = (lut << 8) | (conf->conf.queue[j] & ((0x1 <<
- hw->func_caps.rss_table_entry_width) - 1));
- if ((i & 3) == 3)
- I40E_WRITE_REG(hw, I40E_PFQF_HLUT(i >> 2), lut);
- }
-
- i40e_rss_mark_invalid_rule(pf, conf);
-
- return 0;
-}
-
-/* Configure RSS hash function to default */
-static int
-i40e_rss_clear_hash_function(struct i40e_pf *pf,
- struct i40e_rte_flow_rss_conf *conf)
-{
- struct i40e_hw *hw = I40E_PF_TO_HW(pf);
- uint32_t i, reg;
- 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 Toeplitz");
- I40E_WRITE_FLUSH(hw);
-
- return 0;
- }
- reg |= I40E_GLQF_CTL_HTOEP_MASK;
-
- i40e_write_global_rx_ctl(hw, I40E_GLQF_CTL, reg);
- I40E_WRITE_FLUSH(hw);
- } else if (conf->conf.func ==
- RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ) {
- mask0 = conf->conf.types & pf->adapter->flow_types_mask;
-
- for (i = RTE_ETH_FLOW_UNKNOWN + 1; i < UINT64_BIT; i++) {
- if (mask0 & (1UL << i))
- break;
- }
-
- if (i == UINT64_BIT)
- return -EINVAL;
-
- for (j = I40E_FILTER_PCTYPE_INVALID + 1;
- j < I40E_FILTER_PCTYPE_MAX; j++) {
- if (pf->adapter->pctypes_tbl[i] & (1ULL << j))
- i40e_write_global_rx_ctl(hw,
- I40E_GLQF_HSYM(j),
- 0);
- }
- }
-
- return 0;
-}
-
-/* Disable RSS hash and configure default input set */
-static int
-i40e_rss_disable_hash(struct i40e_pf *pf,
- struct i40e_rte_flow_rss_conf *conf)
-{
- struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info;
- struct i40e_hw *hw = I40E_PF_TO_HW(pf);
- struct i40e_rte_flow_rss_conf rss_conf;
- uint32_t i;
-
- memset(&rss_conf, 0, sizeof(rss_conf));
- rte_memcpy(&rss_conf, conf, sizeof(rss_conf));
-
- /* Disable RSS hash */
- rss_conf.conf.types = rss_info->conf.types & ~(conf->conf.types);
- i40e_rss_hash_set(pf, &rss_conf);
-
- for (i = RTE_ETH_FLOW_IPV4; i <= RTE_ETH_FLOW_L2_PAYLOAD; i++) {
- if (!(pf->adapter->flow_types_mask & (1ULL << i)) ||
- !(conf->conf.types & (1ULL << i)))
- continue;
-
- /* Configure default input set */
- struct rte_eth_input_set_conf input_conf = {
- .op = RTE_ETH_INPUT_SET_SELECT,
- .flow_type = i,
- .inset_size = 1,
- };
- input_conf.field[0] = RTE_ETH_INPUT_SET_DEFAULT;
- i40e_hash_filter_inset_select(hw, &input_conf);
- }
-
- rss_info->conf.types = rss_conf.conf.types;
-
- i40e_rss_clear_hash_function(pf, conf);
-
- return 0;
-}
-
-/* Configure RSS queue region to default */
-static int
-i40e_rss_clear_queue_region(struct i40e_pf *pf)
-{
- struct i40e_hw *hw = I40E_PF_TO_HW(pf);
- struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info;
- uint16_t queue[I40E_MAX_Q_PER_TC];
- uint32_t num_rxq, i;
- uint32_t lut = 0;
- uint16_t j, num;
-
- num_rxq = RTE_MIN(pf->dev_data->nb_rx_queues, I40E_MAX_Q_PER_TC);
-
- for (j = 0; j < num_rxq; j++)
- queue[j] = j;
-
- /* If both VMDQ and RSS enabled, not all of PF queues are configured.
- * It's necessary to calculate the actual PF queues that are configured.
- */
- if (pf->dev_data->dev_conf.rxmode.mq_mode & ETH_MQ_RX_VMDQ_FLAG)
- num = i40e_pf_calc_configured_queues_num(pf);
- else
- num = pf->dev_data->nb_rx_queues;
-
- num = RTE_MIN(num, num_rxq);
- PMD_DRV_LOG(INFO, "Max of contiguous %u PF queues are configured",
- num);
-
- if (num == 0) {
- PMD_DRV_LOG(ERR,
- "No PF queues are configured to enable RSS for port %u",
- pf->dev_data->port_id);
- return -ENOTSUP;
- }
-
- /* Fill in redirection table */
- for (i = 0, j = 0; i < hw->func_caps.rss_table_size; i++, j++) {
- if (j == num)
- j = 0;
- lut = (lut << 8) | (queue[j] & ((0x1 <<
- hw->func_caps.rss_table_entry_width) - 1));
- if ((i & 3) == 3)
- I40E_WRITE_REG(hw, I40E_PFQF_HLUT(i >> 2), lut);
- }
-
- rss_info->conf.queue_num = 0;
- memset(&rss_info->conf.queue, 0, sizeof(uint16_t));
-
- return 0;
-}
-
-int
-i40e_config_rss_filter(struct i40e_pf *pf,
- struct i40e_rte_flow_rss_conf *conf, bool add)
-{
- struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info;
- struct rte_flow_action_rss update_conf = rss_info->conf;
- int ret = 0;
-
- if (add) {
- if (conf->conf.queue_num) {
- /* Configure RSS queue region */
- ret = i40e_rss_config_queue_region(pf, conf);
- if (ret)
- return ret;
-
- update_conf.queue_num = conf->conf.queue_num;
- update_conf.queue = conf->conf.queue;
- } else if (conf->conf.func ==
- RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) {
- /* Configure hash function */
- ret = i40e_rss_config_hash_function(pf, conf);
- if (ret)
- return ret;
-
- update_conf.func = conf->conf.func;
- } else {
- /* Configure hash enable and input set */
- ret = i40e_rss_enable_hash(pf, conf);
- if (ret)
- return ret;
-
- update_conf.types |= conf->conf.types;
- update_conf.key = conf->conf.key;
- update_conf.key_len = conf->conf.key_len;
- }
-
- /* Update RSS info in pf */
- if (i40e_rss_conf_init(rss_info, &update_conf))
- return -EINVAL;
- } else {
- if (!conf->valid)
- return 0;
-
- if (conf->conf.queue_num)
- i40e_rss_clear_queue_region(pf);
- else if (conf->conf.func == RTE_ETH_HASH_FUNCTION_SIMPLE_XOR)
- i40e_rss_clear_hash_function(pf, conf);
- else
- i40e_rss_disable_hash(pf, conf);
- }
-
- return 0;
-}
-