134d5e97eSMichal Krawczyk /* SPDX-License-Identifier: BSD-3-Clause 234d5e97eSMichal Krawczyk * Copyright (c) 2020 Amazon.com, Inc. or its affiliates. 334d5e97eSMichal Krawczyk * All rights reserved. 434d5e97eSMichal Krawczyk */ 534d5e97eSMichal Krawczyk 634d5e97eSMichal Krawczyk #include "ena_ethdev.h" 734d5e97eSMichal Krawczyk #include "ena_logs.h" 834d5e97eSMichal Krawczyk 934d5e97eSMichal Krawczyk #include <ena_admin_defs.h> 1034d5e97eSMichal Krawczyk 1134d5e97eSMichal Krawczyk #define TEST_BIT(val, bit_shift) ((val) & (1UL << (bit_shift))) 1234d5e97eSMichal Krawczyk 1334d5e97eSMichal Krawczyk #define ENA_HF_RSS_ALL_L2 (ENA_ADMIN_RSS_L3_SA | ENA_ADMIN_RSS_L3_DA) 1434d5e97eSMichal Krawczyk #define ENA_HF_RSS_ALL_L3 (ENA_ADMIN_RSS_L3_SA | ENA_ADMIN_RSS_L3_DA) 1534d5e97eSMichal Krawczyk #define ENA_HF_RSS_ALL_L4 (ENA_ADMIN_RSS_L4_SP | ENA_ADMIN_RSS_L4_DP) 1634d5e97eSMichal Krawczyk #define ENA_HF_RSS_ALL_L3_L4 (ENA_HF_RSS_ALL_L3 | ENA_HF_RSS_ALL_L4) 1734d5e97eSMichal Krawczyk #define ENA_HF_RSS_ALL_L2_L3_L4 (ENA_HF_RSS_ALL_L2 | ENA_HF_RSS_ALL_L3_L4) 1834d5e97eSMichal Krawczyk 1934d5e97eSMichal Krawczyk enum ena_rss_hash_fields { 2034d5e97eSMichal Krawczyk ENA_HF_RSS_TCP4 = ENA_HF_RSS_ALL_L3_L4, 2134d5e97eSMichal Krawczyk ENA_HF_RSS_UDP4 = ENA_HF_RSS_ALL_L3_L4, 2234d5e97eSMichal Krawczyk ENA_HF_RSS_TCP6 = ENA_HF_RSS_ALL_L3_L4, 2334d5e97eSMichal Krawczyk ENA_HF_RSS_UDP6 = ENA_HF_RSS_ALL_L3_L4, 2434d5e97eSMichal Krawczyk ENA_HF_RSS_IP4 = ENA_HF_RSS_ALL_L3, 2534d5e97eSMichal Krawczyk ENA_HF_RSS_IP6 = ENA_HF_RSS_ALL_L3, 2634d5e97eSMichal Krawczyk ENA_HF_RSS_IP4_FRAG = ENA_HF_RSS_ALL_L3, 2734d5e97eSMichal Krawczyk ENA_HF_RSS_NOT_IP = ENA_HF_RSS_ALL_L2, 2834d5e97eSMichal Krawczyk ENA_HF_RSS_TCP6_EX = ENA_HF_RSS_ALL_L3_L4, 2934d5e97eSMichal Krawczyk ENA_HF_RSS_IP6_EX = ENA_HF_RSS_ALL_L3, 3034d5e97eSMichal Krawczyk }; 3134d5e97eSMichal Krawczyk 3234d5e97eSMichal Krawczyk static int ena_fill_indirect_table_default(struct ena_com_dev *ena_dev, 3334d5e97eSMichal Krawczyk size_t tbl_size, 3434d5e97eSMichal Krawczyk size_t queue_num); 3534d5e97eSMichal Krawczyk static uint64_t ena_admin_hf_to_eth_hf(enum ena_admin_flow_hash_proto proto, 3634d5e97eSMichal Krawczyk uint16_t field); 3734d5e97eSMichal Krawczyk static uint16_t ena_eth_hf_to_admin_hf(enum ena_admin_flow_hash_proto proto, 3834d5e97eSMichal Krawczyk uint64_t rss_hf); 3934d5e97eSMichal Krawczyk static int ena_set_hash_fields(struct ena_com_dev *ena_dev, uint64_t rss_hf); 4034d5e97eSMichal Krawczyk static int ena_rss_hash_set(struct ena_com_dev *ena_dev, 4134d5e97eSMichal Krawczyk struct rte_eth_rss_conf *rss_conf, 4234d5e97eSMichal Krawczyk bool default_allowed); 4334d5e97eSMichal Krawczyk static void ena_reorder_rss_hash_key(uint8_t *reordered_key, 4434d5e97eSMichal Krawczyk uint8_t *key, 4534d5e97eSMichal Krawczyk size_t key_size); 4634d5e97eSMichal Krawczyk static int ena_get_rss_hash_key(struct ena_com_dev *ena_dev, uint8_t *rss_key); 4734d5e97eSMichal Krawczyk 4834d5e97eSMichal Krawczyk void ena_rss_key_fill(void *key, size_t size) 4934d5e97eSMichal Krawczyk { 5034d5e97eSMichal Krawczyk static bool key_generated; 5134d5e97eSMichal Krawczyk static uint8_t default_key[ENA_HASH_KEY_SIZE]; 5234d5e97eSMichal Krawczyk size_t i; 5334d5e97eSMichal Krawczyk 5434d5e97eSMichal Krawczyk if (!key_generated) { 5524499495SDavid Marchand for (i = 0; i < RTE_DIM(default_key); ++i) 5634d5e97eSMichal Krawczyk default_key[i] = rte_rand() & 0xff; 5734d5e97eSMichal Krawczyk key_generated = true; 5834d5e97eSMichal Krawczyk } 5934d5e97eSMichal Krawczyk 6024499495SDavid Marchand RTE_ASSERT(size <= sizeof(default_key)); 6124499495SDavid Marchand rte_memcpy(key, default_key, RTE_MIN(size, sizeof(default_key))); 6234d5e97eSMichal Krawczyk } 6334d5e97eSMichal Krawczyk 6434d5e97eSMichal Krawczyk int ena_rss_reta_update(struct rte_eth_dev *dev, 6534d5e97eSMichal Krawczyk struct rte_eth_rss_reta_entry64 *reta_conf, 6634d5e97eSMichal Krawczyk uint16_t reta_size) 6734d5e97eSMichal Krawczyk { 6834d5e97eSMichal Krawczyk struct ena_adapter *adapter = dev->data->dev_private; 6934d5e97eSMichal Krawczyk struct ena_com_dev *ena_dev = &adapter->ena_dev; 7034d5e97eSMichal Krawczyk int rc, i; 7134d5e97eSMichal Krawczyk u16 entry_value; 7234d5e97eSMichal Krawczyk int conf_idx; 7334d5e97eSMichal Krawczyk int idx; 7434d5e97eSMichal Krawczyk 7534d5e97eSMichal Krawczyk if (reta_size == 0 || reta_conf == NULL) 7634d5e97eSMichal Krawczyk return -EINVAL; 7734d5e97eSMichal Krawczyk 78295968d1SFerruh Yigit if (!(dev->data->dev_conf.rxmode.offloads & RTE_ETH_RX_OFFLOAD_RSS_HASH)) { 79*e99981afSDavid Marchand PMD_DRV_LOG_LINE(ERR, 80*e99981afSDavid Marchand "RSS was not configured for the PMD"); 8134d5e97eSMichal Krawczyk return -ENOTSUP; 8234d5e97eSMichal Krawczyk } 8334d5e97eSMichal Krawczyk 8434d5e97eSMichal Krawczyk if (reta_size > ENA_RX_RSS_TABLE_SIZE) { 85*e99981afSDavid Marchand PMD_DRV_LOG_LINE(WARNING, 86*e99981afSDavid Marchand "Requested indirection table size (%d) is bigger than supported: %d", 8734d5e97eSMichal Krawczyk reta_size, ENA_RX_RSS_TABLE_SIZE); 8834d5e97eSMichal Krawczyk return -EINVAL; 8934d5e97eSMichal Krawczyk } 9034d5e97eSMichal Krawczyk 91e3595539SStanislaw Kardach /* Prevent RETA table structure update races */ 92e3595539SStanislaw Kardach rte_spinlock_lock(&adapter->admin_lock); 9334d5e97eSMichal Krawczyk for (i = 0 ; i < reta_size ; i++) { 9434d5e97eSMichal Krawczyk /* Each reta_conf is for 64 entries. 9534d5e97eSMichal Krawczyk * To support 128 we use 2 conf of 64. 9634d5e97eSMichal Krawczyk */ 97295968d1SFerruh Yigit conf_idx = i / RTE_ETH_RETA_GROUP_SIZE; 98295968d1SFerruh Yigit idx = i % RTE_ETH_RETA_GROUP_SIZE; 9934d5e97eSMichal Krawczyk if (TEST_BIT(reta_conf[conf_idx].mask, idx)) { 10034d5e97eSMichal Krawczyk entry_value = 10134d5e97eSMichal Krawczyk ENA_IO_RXQ_IDX(reta_conf[conf_idx].reta[idx]); 10234d5e97eSMichal Krawczyk 10334d5e97eSMichal Krawczyk rc = ena_com_indirect_table_fill_entry(ena_dev, i, 10434d5e97eSMichal Krawczyk entry_value); 10534d5e97eSMichal Krawczyk if (unlikely(rc != 0)) { 106*e99981afSDavid Marchand PMD_DRV_LOG_LINE(ERR, 107*e99981afSDavid Marchand "Cannot fill indirection table"); 108195e0f24SDavid Marchand rte_spinlock_unlock(&adapter->admin_lock); 10934d5e97eSMichal Krawczyk return rc; 11034d5e97eSMichal Krawczyk } 11134d5e97eSMichal Krawczyk } 11234d5e97eSMichal Krawczyk } 11334d5e97eSMichal Krawczyk 114e3595539SStanislaw Kardach rc = ena_mp_indirect_table_set(adapter); 11534d5e97eSMichal Krawczyk rte_spinlock_unlock(&adapter->admin_lock); 11634d5e97eSMichal Krawczyk if (unlikely(rc != 0)) { 117*e99981afSDavid Marchand PMD_DRV_LOG_LINE(ERR, "Cannot set the indirection table"); 11834d5e97eSMichal Krawczyk return rc; 11934d5e97eSMichal Krawczyk } 12034d5e97eSMichal Krawczyk 121*e99981afSDavid Marchand PMD_DRV_LOG_LINE(DEBUG, "RSS configured %d entries for port %d", 12234d5e97eSMichal Krawczyk reta_size, dev->data->port_id); 12334d5e97eSMichal Krawczyk 12434d5e97eSMichal Krawczyk return 0; 12534d5e97eSMichal Krawczyk } 12634d5e97eSMichal Krawczyk 12734d5e97eSMichal Krawczyk /* Query redirection table. */ 12834d5e97eSMichal Krawczyk int ena_rss_reta_query(struct rte_eth_dev *dev, 12934d5e97eSMichal Krawczyk struct rte_eth_rss_reta_entry64 *reta_conf, 13034d5e97eSMichal Krawczyk uint16_t reta_size) 13134d5e97eSMichal Krawczyk { 132e3595539SStanislaw Kardach uint32_t indirect_table[ENA_RX_RSS_TABLE_SIZE]; 13334d5e97eSMichal Krawczyk struct ena_adapter *adapter = dev->data->dev_private; 13434d5e97eSMichal Krawczyk int rc; 13534d5e97eSMichal Krawczyk int i; 13634d5e97eSMichal Krawczyk int reta_conf_idx; 13734d5e97eSMichal Krawczyk int reta_idx; 13834d5e97eSMichal Krawczyk 1397a4edfd7SFerruh Yigit if (reta_size == 0 || reta_conf == NULL) 14034d5e97eSMichal Krawczyk return -EINVAL; 14134d5e97eSMichal Krawczyk 142295968d1SFerruh Yigit if (!(dev->data->dev_conf.rxmode.offloads & RTE_ETH_RX_OFFLOAD_RSS_HASH)) { 143*e99981afSDavid Marchand PMD_DRV_LOG_LINE(ERR, 144*e99981afSDavid Marchand "RSS was not configured for the PMD"); 14534d5e97eSMichal Krawczyk return -ENOTSUP; 14634d5e97eSMichal Krawczyk } 14734d5e97eSMichal Krawczyk 14834d5e97eSMichal Krawczyk rte_spinlock_lock(&adapter->admin_lock); 149e3595539SStanislaw Kardach rc = ena_mp_indirect_table_get(adapter, indirect_table); 15034d5e97eSMichal Krawczyk rte_spinlock_unlock(&adapter->admin_lock); 15134d5e97eSMichal Krawczyk if (unlikely(rc != 0)) { 152*e99981afSDavid Marchand PMD_DRV_LOG_LINE(ERR, "Cannot get indirection table"); 15334d5e97eSMichal Krawczyk return rc; 15434d5e97eSMichal Krawczyk } 15534d5e97eSMichal Krawczyk 15634d5e97eSMichal Krawczyk for (i = 0 ; i < reta_size ; i++) { 157295968d1SFerruh Yigit reta_conf_idx = i / RTE_ETH_RETA_GROUP_SIZE; 158295968d1SFerruh Yigit reta_idx = i % RTE_ETH_RETA_GROUP_SIZE; 15934d5e97eSMichal Krawczyk if (TEST_BIT(reta_conf[reta_conf_idx].mask, reta_idx)) 16034d5e97eSMichal Krawczyk reta_conf[reta_conf_idx].reta[reta_idx] = 16134d5e97eSMichal Krawczyk ENA_IO_RXQ_IDX_REV(indirect_table[i]); 16234d5e97eSMichal Krawczyk } 16334d5e97eSMichal Krawczyk 16434d5e97eSMichal Krawczyk return 0; 16534d5e97eSMichal Krawczyk } 16634d5e97eSMichal Krawczyk 16734d5e97eSMichal Krawczyk static int ena_fill_indirect_table_default(struct ena_com_dev *ena_dev, 16834d5e97eSMichal Krawczyk size_t tbl_size, 16934d5e97eSMichal Krawczyk size_t queue_num) 17034d5e97eSMichal Krawczyk { 17134d5e97eSMichal Krawczyk size_t i; 17234d5e97eSMichal Krawczyk int rc; 17334d5e97eSMichal Krawczyk uint16_t val; 17434d5e97eSMichal Krawczyk 17534d5e97eSMichal Krawczyk for (i = 0; i < tbl_size; ++i) { 17634d5e97eSMichal Krawczyk val = i % queue_num; 17734d5e97eSMichal Krawczyk rc = ena_com_indirect_table_fill_entry(ena_dev, i, 17834d5e97eSMichal Krawczyk ENA_IO_RXQ_IDX(val)); 17934d5e97eSMichal Krawczyk if (unlikely(rc != 0)) { 180*e99981afSDavid Marchand PMD_DRV_LOG_LINE(DEBUG, 181*e99981afSDavid Marchand "Failed to set %zu indirection table entry with val %" PRIu16 "", 18234d5e97eSMichal Krawczyk i, val); 18334d5e97eSMichal Krawczyk return rc; 18434d5e97eSMichal Krawczyk } 18534d5e97eSMichal Krawczyk } 18634d5e97eSMichal Krawczyk 18734d5e97eSMichal Krawczyk return 0; 18834d5e97eSMichal Krawczyk } 18934d5e97eSMichal Krawczyk 19034d5e97eSMichal Krawczyk static uint64_t ena_admin_hf_to_eth_hf(enum ena_admin_flow_hash_proto proto, 19134d5e97eSMichal Krawczyk uint16_t fields) 19234d5e97eSMichal Krawczyk { 19334d5e97eSMichal Krawczyk uint64_t rss_hf = 0; 19434d5e97eSMichal Krawczyk 19534d5e97eSMichal Krawczyk /* If no fields are activated, then RSS is disabled for this proto */ 19634d5e97eSMichal Krawczyk if ((fields & ENA_HF_RSS_ALL_L2_L3_L4) == 0) 19734d5e97eSMichal Krawczyk return 0; 19834d5e97eSMichal Krawczyk 19934d5e97eSMichal Krawczyk /* Convert proto to ETH flag */ 20034d5e97eSMichal Krawczyk switch (proto) { 20134d5e97eSMichal Krawczyk case ENA_ADMIN_RSS_TCP4: 202295968d1SFerruh Yigit rss_hf |= RTE_ETH_RSS_NONFRAG_IPV4_TCP; 20334d5e97eSMichal Krawczyk break; 20434d5e97eSMichal Krawczyk case ENA_ADMIN_RSS_UDP4: 205295968d1SFerruh Yigit rss_hf |= RTE_ETH_RSS_NONFRAG_IPV4_UDP; 20634d5e97eSMichal Krawczyk break; 20734d5e97eSMichal Krawczyk case ENA_ADMIN_RSS_TCP6: 208295968d1SFerruh Yigit rss_hf |= RTE_ETH_RSS_NONFRAG_IPV6_TCP; 20934d5e97eSMichal Krawczyk break; 21034d5e97eSMichal Krawczyk case ENA_ADMIN_RSS_UDP6: 211295968d1SFerruh Yigit rss_hf |= RTE_ETH_RSS_NONFRAG_IPV6_UDP; 21234d5e97eSMichal Krawczyk break; 21334d5e97eSMichal Krawczyk case ENA_ADMIN_RSS_IP4: 214295968d1SFerruh Yigit rss_hf |= RTE_ETH_RSS_IPV4; 21534d5e97eSMichal Krawczyk break; 21634d5e97eSMichal Krawczyk case ENA_ADMIN_RSS_IP6: 217295968d1SFerruh Yigit rss_hf |= RTE_ETH_RSS_IPV6; 21834d5e97eSMichal Krawczyk break; 21934d5e97eSMichal Krawczyk case ENA_ADMIN_RSS_IP4_FRAG: 220295968d1SFerruh Yigit rss_hf |= RTE_ETH_RSS_FRAG_IPV4; 22134d5e97eSMichal Krawczyk break; 22234d5e97eSMichal Krawczyk case ENA_ADMIN_RSS_NOT_IP: 223295968d1SFerruh Yigit rss_hf |= RTE_ETH_RSS_L2_PAYLOAD; 22434d5e97eSMichal Krawczyk break; 22534d5e97eSMichal Krawczyk case ENA_ADMIN_RSS_TCP6_EX: 226295968d1SFerruh Yigit rss_hf |= RTE_ETH_RSS_IPV6_TCP_EX; 22734d5e97eSMichal Krawczyk break; 22834d5e97eSMichal Krawczyk case ENA_ADMIN_RSS_IP6_EX: 229295968d1SFerruh Yigit rss_hf |= RTE_ETH_RSS_IPV6_EX; 23034d5e97eSMichal Krawczyk break; 23134d5e97eSMichal Krawczyk default: 23234d5e97eSMichal Krawczyk break; 23334d5e97eSMichal Krawczyk }; 23434d5e97eSMichal Krawczyk 23534d5e97eSMichal Krawczyk /* Check if only DA or SA is being used for L3. */ 23634d5e97eSMichal Krawczyk switch (fields & ENA_HF_RSS_ALL_L3) { 23734d5e97eSMichal Krawczyk case ENA_ADMIN_RSS_L3_SA: 238295968d1SFerruh Yigit rss_hf |= RTE_ETH_RSS_L3_SRC_ONLY; 23934d5e97eSMichal Krawczyk break; 24034d5e97eSMichal Krawczyk case ENA_ADMIN_RSS_L3_DA: 241295968d1SFerruh Yigit rss_hf |= RTE_ETH_RSS_L3_DST_ONLY; 24234d5e97eSMichal Krawczyk break; 24334d5e97eSMichal Krawczyk default: 24434d5e97eSMichal Krawczyk break; 24534d5e97eSMichal Krawczyk }; 24634d5e97eSMichal Krawczyk 24734d5e97eSMichal Krawczyk /* Check if only DA or SA is being used for L4. */ 24834d5e97eSMichal Krawczyk switch (fields & ENA_HF_RSS_ALL_L4) { 24934d5e97eSMichal Krawczyk case ENA_ADMIN_RSS_L4_SP: 250295968d1SFerruh Yigit rss_hf |= RTE_ETH_RSS_L4_SRC_ONLY; 25134d5e97eSMichal Krawczyk break; 25234d5e97eSMichal Krawczyk case ENA_ADMIN_RSS_L4_DP: 253295968d1SFerruh Yigit rss_hf |= RTE_ETH_RSS_L4_DST_ONLY; 25434d5e97eSMichal Krawczyk break; 25534d5e97eSMichal Krawczyk default: 25634d5e97eSMichal Krawczyk break; 25734d5e97eSMichal Krawczyk }; 25834d5e97eSMichal Krawczyk 25934d5e97eSMichal Krawczyk return rss_hf; 26034d5e97eSMichal Krawczyk } 26134d5e97eSMichal Krawczyk 26234d5e97eSMichal Krawczyk static uint16_t ena_eth_hf_to_admin_hf(enum ena_admin_flow_hash_proto proto, 26334d5e97eSMichal Krawczyk uint64_t rss_hf) 26434d5e97eSMichal Krawczyk { 26534d5e97eSMichal Krawczyk uint16_t fields_mask = 0; 26634d5e97eSMichal Krawczyk 26734d5e97eSMichal Krawczyk /* L2 always uses source and destination addresses. */ 26834d5e97eSMichal Krawczyk fields_mask = ENA_ADMIN_RSS_L2_DA | ENA_ADMIN_RSS_L2_SA; 26934d5e97eSMichal Krawczyk 27034d5e97eSMichal Krawczyk /* Determine which fields of L3 should be used. */ 271295968d1SFerruh Yigit switch (rss_hf & (RTE_ETH_RSS_L3_SRC_ONLY | RTE_ETH_RSS_L3_DST_ONLY)) { 272295968d1SFerruh Yigit case RTE_ETH_RSS_L3_DST_ONLY: 27334d5e97eSMichal Krawczyk fields_mask |= ENA_ADMIN_RSS_L3_DA; 27434d5e97eSMichal Krawczyk break; 275295968d1SFerruh Yigit case RTE_ETH_RSS_L3_SRC_ONLY: 27634d5e97eSMichal Krawczyk fields_mask |= ENA_ADMIN_RSS_L3_SA; 27734d5e97eSMichal Krawczyk break; 27834d5e97eSMichal Krawczyk default: 27934d5e97eSMichal Krawczyk /* 28034d5e97eSMichal Krawczyk * If SRC nor DST aren't set, it means both of them should be 28134d5e97eSMichal Krawczyk * used. 28234d5e97eSMichal Krawczyk */ 28334d5e97eSMichal Krawczyk fields_mask |= ENA_HF_RSS_ALL_L3; 28434d5e97eSMichal Krawczyk } 28534d5e97eSMichal Krawczyk 28634d5e97eSMichal Krawczyk /* Determine which fields of L4 should be used. */ 287295968d1SFerruh Yigit switch (rss_hf & (RTE_ETH_RSS_L4_SRC_ONLY | RTE_ETH_RSS_L4_DST_ONLY)) { 288295968d1SFerruh Yigit case RTE_ETH_RSS_L4_DST_ONLY: 28934d5e97eSMichal Krawczyk fields_mask |= ENA_ADMIN_RSS_L4_DP; 29034d5e97eSMichal Krawczyk break; 291295968d1SFerruh Yigit case RTE_ETH_RSS_L4_SRC_ONLY: 29234d5e97eSMichal Krawczyk fields_mask |= ENA_ADMIN_RSS_L4_SP; 29334d5e97eSMichal Krawczyk break; 29434d5e97eSMichal Krawczyk default: 29534d5e97eSMichal Krawczyk /* 29634d5e97eSMichal Krawczyk * If SRC nor DST aren't set, it means both of them should be 29734d5e97eSMichal Krawczyk * used. 29834d5e97eSMichal Krawczyk */ 29934d5e97eSMichal Krawczyk fields_mask |= ENA_HF_RSS_ALL_L4; 30034d5e97eSMichal Krawczyk } 30134d5e97eSMichal Krawczyk 30234d5e97eSMichal Krawczyk /* Return appropriate hash fields. */ 30334d5e97eSMichal Krawczyk switch (proto) { 30434d5e97eSMichal Krawczyk case ENA_ADMIN_RSS_TCP4: 30534d5e97eSMichal Krawczyk return ENA_HF_RSS_TCP4 & fields_mask; 30634d5e97eSMichal Krawczyk case ENA_ADMIN_RSS_UDP4: 30734d5e97eSMichal Krawczyk return ENA_HF_RSS_UDP4 & fields_mask; 30834d5e97eSMichal Krawczyk case ENA_ADMIN_RSS_TCP6: 30934d5e97eSMichal Krawczyk return ENA_HF_RSS_TCP6 & fields_mask; 31034d5e97eSMichal Krawczyk case ENA_ADMIN_RSS_UDP6: 31134d5e97eSMichal Krawczyk return ENA_HF_RSS_UDP6 & fields_mask; 31234d5e97eSMichal Krawczyk case ENA_ADMIN_RSS_IP4: 31334d5e97eSMichal Krawczyk return ENA_HF_RSS_IP4 & fields_mask; 31434d5e97eSMichal Krawczyk case ENA_ADMIN_RSS_IP6: 31534d5e97eSMichal Krawczyk return ENA_HF_RSS_IP6 & fields_mask; 31634d5e97eSMichal Krawczyk case ENA_ADMIN_RSS_IP4_FRAG: 31734d5e97eSMichal Krawczyk return ENA_HF_RSS_IP4_FRAG & fields_mask; 31834d5e97eSMichal Krawczyk case ENA_ADMIN_RSS_NOT_IP: 31934d5e97eSMichal Krawczyk return ENA_HF_RSS_NOT_IP & fields_mask; 32034d5e97eSMichal Krawczyk case ENA_ADMIN_RSS_TCP6_EX: 32134d5e97eSMichal Krawczyk return ENA_HF_RSS_TCP6_EX & fields_mask; 32234d5e97eSMichal Krawczyk case ENA_ADMIN_RSS_IP6_EX: 32334d5e97eSMichal Krawczyk return ENA_HF_RSS_IP6_EX & fields_mask; 32434d5e97eSMichal Krawczyk default: 32534d5e97eSMichal Krawczyk break; 32634d5e97eSMichal Krawczyk } 32734d5e97eSMichal Krawczyk 32834d5e97eSMichal Krawczyk return 0; 32934d5e97eSMichal Krawczyk } 33034d5e97eSMichal Krawczyk 33134d5e97eSMichal Krawczyk static int ena_set_hash_fields(struct ena_com_dev *ena_dev, uint64_t rss_hf) 33234d5e97eSMichal Krawczyk { 33334d5e97eSMichal Krawczyk struct ena_admin_proto_input selected_fields[ENA_ADMIN_RSS_PROTO_NUM] = {}; 33434d5e97eSMichal Krawczyk int rc, i; 33534d5e97eSMichal Krawczyk 33634d5e97eSMichal Krawczyk /* Turn on appropriate fields for each requested packet type */ 337295968d1SFerruh Yigit if ((rss_hf & RTE_ETH_RSS_NONFRAG_IPV4_TCP) != 0) 33834d5e97eSMichal Krawczyk selected_fields[ENA_ADMIN_RSS_TCP4].fields = 33934d5e97eSMichal Krawczyk ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_TCP4, rss_hf); 34034d5e97eSMichal Krawczyk 341295968d1SFerruh Yigit if ((rss_hf & RTE_ETH_RSS_NONFRAG_IPV4_UDP) != 0) 34234d5e97eSMichal Krawczyk selected_fields[ENA_ADMIN_RSS_UDP4].fields = 34334d5e97eSMichal Krawczyk ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_UDP4, rss_hf); 34434d5e97eSMichal Krawczyk 345295968d1SFerruh Yigit if ((rss_hf & RTE_ETH_RSS_NONFRAG_IPV6_TCP) != 0) 34634d5e97eSMichal Krawczyk selected_fields[ENA_ADMIN_RSS_TCP6].fields = 34734d5e97eSMichal Krawczyk ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_TCP6, rss_hf); 34834d5e97eSMichal Krawczyk 349295968d1SFerruh Yigit if ((rss_hf & RTE_ETH_RSS_NONFRAG_IPV6_UDP) != 0) 35034d5e97eSMichal Krawczyk selected_fields[ENA_ADMIN_RSS_UDP6].fields = 35134d5e97eSMichal Krawczyk ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_UDP6, rss_hf); 35234d5e97eSMichal Krawczyk 353295968d1SFerruh Yigit if ((rss_hf & RTE_ETH_RSS_IPV4) != 0) 35434d5e97eSMichal Krawczyk selected_fields[ENA_ADMIN_RSS_IP4].fields = 35534d5e97eSMichal Krawczyk ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_IP4, rss_hf); 35634d5e97eSMichal Krawczyk 357295968d1SFerruh Yigit if ((rss_hf & RTE_ETH_RSS_IPV6) != 0) 35834d5e97eSMichal Krawczyk selected_fields[ENA_ADMIN_RSS_IP6].fields = 35934d5e97eSMichal Krawczyk ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_IP6, rss_hf); 36034d5e97eSMichal Krawczyk 361295968d1SFerruh Yigit if ((rss_hf & RTE_ETH_RSS_FRAG_IPV4) != 0) 36234d5e97eSMichal Krawczyk selected_fields[ENA_ADMIN_RSS_IP4_FRAG].fields = 36334d5e97eSMichal Krawczyk ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_IP4_FRAG, rss_hf); 36434d5e97eSMichal Krawczyk 365295968d1SFerruh Yigit if ((rss_hf & RTE_ETH_RSS_L2_PAYLOAD) != 0) 36634d5e97eSMichal Krawczyk selected_fields[ENA_ADMIN_RSS_NOT_IP].fields = 36734d5e97eSMichal Krawczyk ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_NOT_IP, rss_hf); 36834d5e97eSMichal Krawczyk 369295968d1SFerruh Yigit if ((rss_hf & RTE_ETH_RSS_IPV6_TCP_EX) != 0) 37034d5e97eSMichal Krawczyk selected_fields[ENA_ADMIN_RSS_TCP6_EX].fields = 37134d5e97eSMichal Krawczyk ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_TCP6_EX, rss_hf); 37234d5e97eSMichal Krawczyk 373295968d1SFerruh Yigit if ((rss_hf & RTE_ETH_RSS_IPV6_EX) != 0) 37434d5e97eSMichal Krawczyk selected_fields[ENA_ADMIN_RSS_IP6_EX].fields = 37534d5e97eSMichal Krawczyk ena_eth_hf_to_admin_hf(ENA_ADMIN_RSS_IP6_EX, rss_hf); 37634d5e97eSMichal Krawczyk 37734d5e97eSMichal Krawczyk /* Try to write them to the device */ 37834d5e97eSMichal Krawczyk for (i = 0; i < ENA_ADMIN_RSS_PROTO_NUM; i++) { 37934d5e97eSMichal Krawczyk rc = ena_com_fill_hash_ctrl(ena_dev, 38034d5e97eSMichal Krawczyk (enum ena_admin_flow_hash_proto)i, 38134d5e97eSMichal Krawczyk selected_fields[i].fields); 38234d5e97eSMichal Krawczyk if (unlikely(rc != 0)) { 383*e99981afSDavid Marchand PMD_DRV_LOG_LINE(DEBUG, 384*e99981afSDavid Marchand "Failed to set ENA HF %d with fields %" PRIu16 "", 38534d5e97eSMichal Krawczyk i, selected_fields[i].fields); 38634d5e97eSMichal Krawczyk return rc; 38734d5e97eSMichal Krawczyk } 38834d5e97eSMichal Krawczyk } 38934d5e97eSMichal Krawczyk 39034d5e97eSMichal Krawczyk return 0; 39134d5e97eSMichal Krawczyk } 39234d5e97eSMichal Krawczyk 39334d5e97eSMichal Krawczyk static int ena_rss_hash_set(struct ena_com_dev *ena_dev, 39434d5e97eSMichal Krawczyk struct rte_eth_rss_conf *rss_conf, 39534d5e97eSMichal Krawczyk bool default_allowed) 39634d5e97eSMichal Krawczyk { 39734d5e97eSMichal Krawczyk uint8_t hw_rss_key[ENA_HASH_KEY_SIZE]; 39834d5e97eSMichal Krawczyk uint8_t *rss_key; 39934d5e97eSMichal Krawczyk int rc; 40034d5e97eSMichal Krawczyk 40134d5e97eSMichal Krawczyk if (rss_conf->rss_key != NULL) { 40234d5e97eSMichal Krawczyk /* Reorder the RSS key bytes for the hardware requirements. */ 40334d5e97eSMichal Krawczyk ena_reorder_rss_hash_key(hw_rss_key, rss_conf->rss_key, 40434d5e97eSMichal Krawczyk ENA_HASH_KEY_SIZE); 40534d5e97eSMichal Krawczyk rss_key = hw_rss_key; 40634d5e97eSMichal Krawczyk } else { 40734d5e97eSMichal Krawczyk rss_key = NULL; 40834d5e97eSMichal Krawczyk } 40934d5e97eSMichal Krawczyk 41034d5e97eSMichal Krawczyk /* If the rss_key is NULL, then the randomized key will be used. */ 41134d5e97eSMichal Krawczyk rc = ena_com_fill_hash_function(ena_dev, ENA_ADMIN_TOEPLITZ, 41234d5e97eSMichal Krawczyk rss_key, ENA_HASH_KEY_SIZE, 0); 41334d5e97eSMichal Krawczyk if (rc != 0 && !(default_allowed && rc == ENA_COM_UNSUPPORTED)) { 414*e99981afSDavid Marchand PMD_DRV_LOG_LINE(ERR, 415*e99981afSDavid Marchand "Failed to set RSS hash function in the device"); 41634d5e97eSMichal Krawczyk return rc; 41734d5e97eSMichal Krawczyk } 41834d5e97eSMichal Krawczyk 41934d5e97eSMichal Krawczyk rc = ena_set_hash_fields(ena_dev, rss_conf->rss_hf); 42034d5e97eSMichal Krawczyk if (rc == ENA_COM_UNSUPPORTED) { 42134d5e97eSMichal Krawczyk if (rss_conf->rss_key == NULL && !default_allowed) { 422*e99981afSDavid Marchand PMD_DRV_LOG_LINE(ERR, 423*e99981afSDavid Marchand "Setting RSS hash fields is not supported"); 42434d5e97eSMichal Krawczyk return -ENOTSUP; 42534d5e97eSMichal Krawczyk } 426*e99981afSDavid Marchand PMD_DRV_LOG_LINE(WARNING, 427*e99981afSDavid Marchand "Setting RSS hash fields is not supported. Using default values: 0x%"PRIx64, 42834d5e97eSMichal Krawczyk (uint64_t)(ENA_ALL_RSS_HF)); 42934d5e97eSMichal Krawczyk } else if (rc != 0) { 430*e99981afSDavid Marchand PMD_DRV_LOG_LINE(ERR, "Failed to set RSS hash fields"); 43134d5e97eSMichal Krawczyk return rc; 43234d5e97eSMichal Krawczyk } 43334d5e97eSMichal Krawczyk 43434d5e97eSMichal Krawczyk return 0; 43534d5e97eSMichal Krawczyk } 43634d5e97eSMichal Krawczyk 43734d5e97eSMichal Krawczyk /* ENA HW interprets the RSS key in reverse bytes order. Because of that, the 43834d5e97eSMichal Krawczyk * key must be processed upon interaction with ena_com layer. 43934d5e97eSMichal Krawczyk */ 44034d5e97eSMichal Krawczyk static void ena_reorder_rss_hash_key(uint8_t *reordered_key, 44134d5e97eSMichal Krawczyk uint8_t *key, 44234d5e97eSMichal Krawczyk size_t key_size) 44334d5e97eSMichal Krawczyk { 44434d5e97eSMichal Krawczyk size_t i, rev_i; 44534d5e97eSMichal Krawczyk 44634d5e97eSMichal Krawczyk for (i = 0, rev_i = key_size - 1; i < key_size; ++i, --rev_i) 44734d5e97eSMichal Krawczyk reordered_key[i] = key[rev_i]; 44834d5e97eSMichal Krawczyk } 44934d5e97eSMichal Krawczyk 45034d5e97eSMichal Krawczyk static int ena_get_rss_hash_key(struct ena_com_dev *ena_dev, uint8_t *rss_key) 45134d5e97eSMichal Krawczyk { 45234d5e97eSMichal Krawczyk uint8_t hw_rss_key[ENA_HASH_KEY_SIZE]; 45334d5e97eSMichal Krawczyk int rc; 45434d5e97eSMichal Krawczyk 45534d5e97eSMichal Krawczyk /* The default RSS hash key cannot be retrieved from the HW. Unless it's 45634d5e97eSMichal Krawczyk * explicitly set, this operation shouldn't be supported. 45734d5e97eSMichal Krawczyk */ 45834d5e97eSMichal Krawczyk if (ena_dev->rss.hash_key == NULL) { 459*e99981afSDavid Marchand PMD_DRV_LOG_LINE(WARNING, 460*e99981afSDavid Marchand "Retrieving default RSS hash key is not supported"); 46134d5e97eSMichal Krawczyk return -ENOTSUP; 46234d5e97eSMichal Krawczyk } 46334d5e97eSMichal Krawczyk 46434d5e97eSMichal Krawczyk rc = ena_com_get_hash_key(ena_dev, hw_rss_key); 46534d5e97eSMichal Krawczyk if (rc != 0) 46634d5e97eSMichal Krawczyk return rc; 46734d5e97eSMichal Krawczyk 46834d5e97eSMichal Krawczyk ena_reorder_rss_hash_key(rss_key, hw_rss_key, ENA_HASH_KEY_SIZE); 46934d5e97eSMichal Krawczyk 47034d5e97eSMichal Krawczyk return 0; 47134d5e97eSMichal Krawczyk } 47234d5e97eSMichal Krawczyk 47334d5e97eSMichal Krawczyk int ena_rss_configure(struct ena_adapter *adapter) 47434d5e97eSMichal Krawczyk { 47534d5e97eSMichal Krawczyk struct rte_eth_rss_conf *rss_conf; 47634d5e97eSMichal Krawczyk struct ena_com_dev *ena_dev; 47734d5e97eSMichal Krawczyk int rc; 47834d5e97eSMichal Krawczyk 47934d5e97eSMichal Krawczyk ena_dev = &adapter->ena_dev; 48034d5e97eSMichal Krawczyk rss_conf = &adapter->edev_data->dev_conf.rx_adv_conf.rss_conf; 48134d5e97eSMichal Krawczyk 48234d5e97eSMichal Krawczyk if (adapter->edev_data->nb_rx_queues == 0) 48334d5e97eSMichal Krawczyk return 0; 48434d5e97eSMichal Krawczyk 48534d5e97eSMichal Krawczyk /* Restart the indirection table. The number of queues could change 48634d5e97eSMichal Krawczyk * between start/stop calls, so it must be reinitialized with default 48734d5e97eSMichal Krawczyk * values. 48834d5e97eSMichal Krawczyk */ 48934d5e97eSMichal Krawczyk rc = ena_fill_indirect_table_default(ena_dev, ENA_RX_RSS_TABLE_SIZE, 49034d5e97eSMichal Krawczyk adapter->edev_data->nb_rx_queues); 49134d5e97eSMichal Krawczyk if (unlikely(rc != 0)) { 492*e99981afSDavid Marchand PMD_DRV_LOG_LINE(ERR, 493*e99981afSDavid Marchand "Failed to fill indirection table with default values"); 49434d5e97eSMichal Krawczyk return rc; 49534d5e97eSMichal Krawczyk } 49634d5e97eSMichal Krawczyk 49734d5e97eSMichal Krawczyk rc = ena_com_indirect_table_set(ena_dev); 49834d5e97eSMichal Krawczyk if (unlikely(rc != 0 && rc != ENA_COM_UNSUPPORTED)) { 499*e99981afSDavid Marchand PMD_DRV_LOG_LINE(ERR, 500*e99981afSDavid Marchand "Failed to set indirection table in the device"); 50134d5e97eSMichal Krawczyk return rc; 50234d5e97eSMichal Krawczyk } 50334d5e97eSMichal Krawczyk 50434d5e97eSMichal Krawczyk rc = ena_rss_hash_set(ena_dev, rss_conf, true); 50534d5e97eSMichal Krawczyk if (unlikely(rc != 0)) { 506*e99981afSDavid Marchand PMD_DRV_LOG_LINE(ERR, "Failed to set RSS hash"); 50734d5e97eSMichal Krawczyk return rc; 50834d5e97eSMichal Krawczyk } 50934d5e97eSMichal Krawczyk 510*e99981afSDavid Marchand PMD_DRV_LOG_LINE(DEBUG, "RSS configured for port %d", 51134d5e97eSMichal Krawczyk adapter->edev_data->port_id); 51234d5e97eSMichal Krawczyk 51334d5e97eSMichal Krawczyk return 0; 51434d5e97eSMichal Krawczyk } 51534d5e97eSMichal Krawczyk 51634d5e97eSMichal Krawczyk int ena_rss_hash_update(struct rte_eth_dev *dev, 51734d5e97eSMichal Krawczyk struct rte_eth_rss_conf *rss_conf) 51834d5e97eSMichal Krawczyk { 51934d5e97eSMichal Krawczyk struct ena_adapter *adapter = dev->data->dev_private; 52034d5e97eSMichal Krawczyk int rc; 52134d5e97eSMichal Krawczyk 52234d5e97eSMichal Krawczyk rte_spinlock_lock(&adapter->admin_lock); 52334d5e97eSMichal Krawczyk rc = ena_rss_hash_set(&adapter->ena_dev, rss_conf, false); 52434d5e97eSMichal Krawczyk rte_spinlock_unlock(&adapter->admin_lock); 52534d5e97eSMichal Krawczyk if (unlikely(rc != 0)) { 526*e99981afSDavid Marchand PMD_DRV_LOG_LINE(ERR, "Failed to set RSS hash"); 52734d5e97eSMichal Krawczyk return rc; 52834d5e97eSMichal Krawczyk } 52934d5e97eSMichal Krawczyk 53034d5e97eSMichal Krawczyk return 0; 53134d5e97eSMichal Krawczyk } 53234d5e97eSMichal Krawczyk 53334d5e97eSMichal Krawczyk int ena_rss_hash_conf_get(struct rte_eth_dev *dev, 53434d5e97eSMichal Krawczyk struct rte_eth_rss_conf *rss_conf) 53534d5e97eSMichal Krawczyk { 53634d5e97eSMichal Krawczyk struct ena_adapter *adapter = dev->data->dev_private; 53734d5e97eSMichal Krawczyk struct ena_com_dev *ena_dev = &adapter->ena_dev; 53834d5e97eSMichal Krawczyk enum ena_admin_flow_hash_proto proto; 53934d5e97eSMichal Krawczyk uint64_t rss_hf = 0; 54034d5e97eSMichal Krawczyk int rc, i; 54134d5e97eSMichal Krawczyk uint16_t admin_hf; 54234d5e97eSMichal Krawczyk static bool warn_once; 54334d5e97eSMichal Krawczyk 544295968d1SFerruh Yigit if (!(dev->data->dev_conf.rxmode.offloads & RTE_ETH_RX_OFFLOAD_RSS_HASH)) { 545*e99981afSDavid Marchand PMD_DRV_LOG_LINE(ERR, "RSS was not configured for the PMD"); 54634d5e97eSMichal Krawczyk return -ENOTSUP; 54734d5e97eSMichal Krawczyk } 54834d5e97eSMichal Krawczyk 54934d5e97eSMichal Krawczyk if (rss_conf->rss_key != NULL) { 55034d5e97eSMichal Krawczyk rc = ena_get_rss_hash_key(ena_dev, rss_conf->rss_key); 55134d5e97eSMichal Krawczyk if (unlikely(rc != 0)) { 552*e99981afSDavid Marchand PMD_DRV_LOG_LINE(ERR, 553*e99981afSDavid Marchand "Cannot retrieve RSS hash key, err: %d", 55434d5e97eSMichal Krawczyk rc); 55534d5e97eSMichal Krawczyk return rc; 55634d5e97eSMichal Krawczyk } 55734d5e97eSMichal Krawczyk } 55834d5e97eSMichal Krawczyk 55934d5e97eSMichal Krawczyk for (i = 0; i < ENA_ADMIN_RSS_PROTO_NUM; ++i) { 56034d5e97eSMichal Krawczyk proto = (enum ena_admin_flow_hash_proto)i; 56134d5e97eSMichal Krawczyk rte_spinlock_lock(&adapter->admin_lock); 56234d5e97eSMichal Krawczyk rc = ena_com_get_hash_ctrl(ena_dev, proto, &admin_hf); 56334d5e97eSMichal Krawczyk rte_spinlock_unlock(&adapter->admin_lock); 56434d5e97eSMichal Krawczyk if (rc == ENA_COM_UNSUPPORTED) { 56534d5e97eSMichal Krawczyk /* As some devices may support only reading rss hash 56634d5e97eSMichal Krawczyk * key and not the hash ctrl, we want to notify the 56734d5e97eSMichal Krawczyk * caller that this feature is only partially supported 56834d5e97eSMichal Krawczyk * and do not return an error - the caller could be 56934d5e97eSMichal Krawczyk * interested only in the key value. 57034d5e97eSMichal Krawczyk */ 57134d5e97eSMichal Krawczyk if (!warn_once) { 572*e99981afSDavid Marchand PMD_DRV_LOG_LINE(WARNING, 573*e99981afSDavid Marchand "Reading hash control from the device is not supported. .rss_hf will contain a default value."); 57434d5e97eSMichal Krawczyk warn_once = true; 57534d5e97eSMichal Krawczyk } 57634d5e97eSMichal Krawczyk rss_hf = ENA_ALL_RSS_HF; 57734d5e97eSMichal Krawczyk break; 57834d5e97eSMichal Krawczyk } else if (rc != 0) { 579*e99981afSDavid Marchand PMD_DRV_LOG_LINE(ERR, 580*e99981afSDavid Marchand "Failed to retrieve hash ctrl for proto: %d with err: %d", 58134d5e97eSMichal Krawczyk i, rc); 58234d5e97eSMichal Krawczyk return rc; 58334d5e97eSMichal Krawczyk } 58434d5e97eSMichal Krawczyk 58534d5e97eSMichal Krawczyk rss_hf |= ena_admin_hf_to_eth_hf(proto, admin_hf); 58634d5e97eSMichal Krawczyk } 58734d5e97eSMichal Krawczyk 58834d5e97eSMichal Krawczyk rss_conf->rss_hf = rss_hf; 58934d5e97eSMichal Krawczyk return 0; 59034d5e97eSMichal Krawczyk } 591