From bd3fcf0d0fa1424053f4eacc962a1434029956df Mon Sep 17 00:00:00 2001 From: Alvin Zhang Date: Wed, 15 Apr 2020 16:48:07 +0800 Subject: [PATCH] net/igc: support RSS Below ops are added: reta_update reta_query rss_hash_update rss_hash_conf_get Signed-off-by: Alvin Zhang Reviewed-by: Ferruh Yigit --- doc/guides/nics/features/igc.ini | 2 + drivers/net/igc/igc_ethdev.c | 171 +++++++++++++++++++++++++++++++ drivers/net/igc/igc_ethdev.h | 9 ++ drivers/net/igc/igc_txrx.c | 2 +- drivers/net/igc/igc_txrx.h | 2 + 5 files changed, 185 insertions(+), 1 deletion(-) diff --git a/doc/guides/nics/features/igc.ini b/doc/guides/nics/features/igc.ini index a364e049cd..23434af4eb 100644 --- a/doc/guides/nics/features/igc.ini +++ b/doc/guides/nics/features/igc.ini @@ -28,6 +28,8 @@ Extended stats = Y Stats per queue = Y Rx interrupt = Y Flow control = Y +RSS key update = Y +RSS reta update = Y Linux UIO = Y Linux VFIO = Y x86-64 = Y diff --git a/drivers/net/igc/igc_ethdev.c b/drivers/net/igc/igc_ethdev.c index b0548d000d..78364a58a0 100644 --- a/drivers/net/igc/igc_ethdev.c +++ b/drivers/net/igc/igc_ethdev.c @@ -217,6 +217,16 @@ static int eth_igc_flow_ctrl_get(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf); static int eth_igc_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf); +static int eth_igc_rss_reta_update(struct rte_eth_dev *dev, + struct rte_eth_rss_reta_entry64 *reta_conf, + uint16_t reta_size); +static int eth_igc_rss_reta_query(struct rte_eth_dev *dev, + struct rte_eth_rss_reta_entry64 *reta_conf, + uint16_t reta_size); +static int eth_igc_rss_hash_update(struct rte_eth_dev *dev, + struct rte_eth_rss_conf *rss_conf); +static int eth_igc_rss_hash_conf_get(struct rte_eth_dev *dev, + struct rte_eth_rss_conf *rss_conf); static const struct eth_dev_ops eth_igc_ops = { .dev_configure = eth_igc_configure, @@ -265,6 +275,10 @@ static const struct eth_dev_ops eth_igc_ops = { .rx_queue_intr_disable = eth_igc_rx_queue_intr_disable, .flow_ctrl_get = eth_igc_flow_ctrl_get, .flow_ctrl_set = eth_igc_flow_ctrl_set, + .reta_update = eth_igc_rss_reta_update, + .reta_query = eth_igc_rss_reta_query, + .rss_hash_update = eth_igc_rss_hash_update, + .rss_hash_conf_get = eth_igc_rss_hash_conf_get, }; /* @@ -2187,6 +2201,163 @@ eth_igc_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) return -EIO; } +static int +eth_igc_rss_reta_update(struct rte_eth_dev *dev, + struct rte_eth_rss_reta_entry64 *reta_conf, + uint16_t reta_size) +{ + struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev); + uint16_t i; + + if (reta_size != ETH_RSS_RETA_SIZE_128) { + PMD_DRV_LOG(ERR, + "The size of RSS redirection table configured(%d) doesn't match the number hardware can supported(%d)", + reta_size, ETH_RSS_RETA_SIZE_128); + return -EINVAL; + } + + /* set redirection table */ + for (i = 0; i < ETH_RSS_RETA_SIZE_128; i += IGC_RSS_RDT_REG_SIZE) { + union igc_rss_reta_reg reta, reg; + uint16_t idx, shift; + uint8_t j, mask; + + idx = i / RTE_RETA_GROUP_SIZE; + shift = i % RTE_RETA_GROUP_SIZE; + mask = (uint8_t)((reta_conf[idx].mask >> shift) & + IGC_RSS_RDT_REG_SIZE_MASK); + + /* if no need to update the register */ + if (!mask) + continue; + + /* check mask whether need to read the register value first */ + if (mask == IGC_RSS_RDT_REG_SIZE_MASK) + reg.dword = 0; + else + reg.dword = IGC_READ_REG_LE_VALUE(hw, + IGC_RETA(i / IGC_RSS_RDT_REG_SIZE)); + + /* update the register */ + for (j = 0; j < IGC_RSS_RDT_REG_SIZE; j++) { + if (mask & (1u << j)) + reta.bytes[j] = + (uint8_t)reta_conf[idx].reta[shift + j]; + else + reta.bytes[j] = reg.bytes[j]; + } + IGC_WRITE_REG_LE_VALUE(hw, + IGC_RETA(i / IGC_RSS_RDT_REG_SIZE), reta.dword); + } + + return 0; +} + +static int +eth_igc_rss_reta_query(struct rte_eth_dev *dev, + struct rte_eth_rss_reta_entry64 *reta_conf, + uint16_t reta_size) +{ + struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev); + uint16_t i; + + if (reta_size != ETH_RSS_RETA_SIZE_128) { + PMD_DRV_LOG(ERR, + "The size of RSS redirection table configured(%d) doesn't match the number hardware can supported(%d)", + reta_size, ETH_RSS_RETA_SIZE_128); + return -EINVAL; + } + + /* read redirection table */ + for (i = 0; i < ETH_RSS_RETA_SIZE_128; i += IGC_RSS_RDT_REG_SIZE) { + union igc_rss_reta_reg reta; + uint16_t idx, shift; + uint8_t j, mask; + + idx = i / RTE_RETA_GROUP_SIZE; + shift = i % RTE_RETA_GROUP_SIZE; + mask = (uint8_t)((reta_conf[idx].mask >> shift) & + IGC_RSS_RDT_REG_SIZE_MASK); + + /* if no need to read register */ + if (!mask) + continue; + + /* read register and get the queue index */ + reta.dword = IGC_READ_REG_LE_VALUE(hw, + IGC_RETA(i / IGC_RSS_RDT_REG_SIZE)); + for (j = 0; j < IGC_RSS_RDT_REG_SIZE; j++) { + if (mask & (1u << j)) + reta_conf[idx].reta[shift + j] = reta.bytes[j]; + } + } + + return 0; +} + +static int +eth_igc_rss_hash_update(struct rte_eth_dev *dev, + struct rte_eth_rss_conf *rss_conf) +{ + struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev); + igc_hw_rss_hash_set(hw, rss_conf); + return 0; +} + +static int +eth_igc_rss_hash_conf_get(struct rte_eth_dev *dev, + struct rte_eth_rss_conf *rss_conf) +{ + struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev); + uint32_t *hash_key = (uint32_t *)rss_conf->rss_key; + uint32_t mrqc; + uint64_t rss_hf; + + if (hash_key != NULL) { + int i; + + /* if not enough space for store hash key */ + if (rss_conf->rss_key_len != IGC_HKEY_SIZE) { + PMD_DRV_LOG(ERR, + "RSS hash key size %u in parameter doesn't match the hardware hash key size %u", + rss_conf->rss_key_len, IGC_HKEY_SIZE); + return -EINVAL; + } + + /* read RSS key from register */ + for (i = 0; i < IGC_HKEY_MAX_INDEX; i++) + hash_key[i] = IGC_READ_REG_LE_VALUE(hw, IGC_RSSRK(i)); + } + + /* get RSS functions configured in MRQC register */ + mrqc = IGC_READ_REG(hw, IGC_MRQC); + if ((mrqc & IGC_MRQC_ENABLE_RSS_4Q) == 0) + return 0; + + rss_hf = 0; + if (mrqc & IGC_MRQC_RSS_FIELD_IPV4) + rss_hf |= ETH_RSS_IPV4; + if (mrqc & IGC_MRQC_RSS_FIELD_IPV4_TCP) + rss_hf |= ETH_RSS_NONFRAG_IPV4_TCP; + if (mrqc & IGC_MRQC_RSS_FIELD_IPV6) + rss_hf |= ETH_RSS_IPV6; + if (mrqc & IGC_MRQC_RSS_FIELD_IPV6_EX) + rss_hf |= ETH_RSS_IPV6_EX; + if (mrqc & IGC_MRQC_RSS_FIELD_IPV6_TCP) + rss_hf |= ETH_RSS_NONFRAG_IPV6_TCP; + if (mrqc & IGC_MRQC_RSS_FIELD_IPV6_TCP_EX) + rss_hf |= ETH_RSS_IPV6_TCP_EX; + if (mrqc & IGC_MRQC_RSS_FIELD_IPV4_UDP) + rss_hf |= ETH_RSS_NONFRAG_IPV4_UDP; + if (mrqc & IGC_MRQC_RSS_FIELD_IPV6_UDP) + rss_hf |= ETH_RSS_NONFRAG_IPV6_UDP; + if (mrqc & IGC_MRQC_RSS_FIELD_IPV6_UDP_EX) + rss_hf |= ETH_RSS_IPV6_UDP_EX; + + rss_conf->rss_hf |= rss_hf; + return 0; +} + static int eth_igc_pci_probe(struct rte_pci_driver *pci_drv __rte_unused, struct rte_pci_device *pci_dev) diff --git a/drivers/net/igc/igc_ethdev.h b/drivers/net/igc/igc_ethdev.h index d63890fa17..e8fd1b1e97 100644 --- a/drivers/net/igc/igc_ethdev.h +++ b/drivers/net/igc/igc_ethdev.h @@ -16,11 +16,20 @@ extern "C" { #endif +#define IGC_RSS_RDT_SIZD 128 #define IGC_QUEUE_PAIRS_NUM 4 #define IGC_HKEY_MAX_INDEX 10 #define IGC_RSS_RDT_SIZD 128 +#define IGC_DEFAULT_REG_SIZE 4 +#define IGC_DEFAULT_REG_SIZE_MASK 0xf + +#define IGC_RSS_RDT_REG_SIZE IGC_DEFAULT_REG_SIZE +#define IGC_RSS_RDT_REG_SIZE_MASK IGC_DEFAULT_REG_SIZE_MASK +#define IGC_HKEY_REG_SIZE IGC_DEFAULT_REG_SIZE +#define IGC_HKEY_SIZE (IGC_HKEY_REG_SIZE * IGC_HKEY_MAX_INDEX) + /* * TDBA/RDBA should be aligned on 16 byte boundary. But TDLEN/RDLEN should be * multiple of 128 bytes. So we align TDBA/RDBA on 128 byte boundary. diff --git a/drivers/net/igc/igc_txrx.c b/drivers/net/igc/igc_txrx.c index 3437c4de2d..3028a66b6f 100644 --- a/drivers/net/igc/igc_txrx.c +++ b/drivers/net/igc/igc_txrx.c @@ -847,7 +847,7 @@ igc_rss_disable(struct rte_eth_dev *dev) IGC_WRITE_REG(hw, IGC_MRQC, mrqc); } -static void +void igc_hw_rss_hash_set(struct igc_hw *hw, struct rte_eth_rss_conf *rss_conf) { uint32_t *hash_key = (uint32_t *)rss_conf->rss_key; diff --git a/drivers/net/igc/igc_txrx.h b/drivers/net/igc/igc_txrx.h index 1b66b3ff4e..63b19f527d 100644 --- a/drivers/net/igc/igc_txrx.h +++ b/drivers/net/igc/igc_txrx.h @@ -38,6 +38,8 @@ int eth_igc_tx_done_cleanup(void *txqueue, uint32_t free_cnt); int igc_rx_init(struct rte_eth_dev *dev); void igc_tx_init(struct rte_eth_dev *dev); +void +igc_hw_rss_hash_set(struct igc_hw *hw, struct rte_eth_rss_conf *rss_conf); void eth_igc_rxq_info_get(struct rte_eth_dev *dev, uint16_t queue_id, struct rte_eth_rxq_info *qinfo); void eth_igc_txq_info_get(struct rte_eth_dev *dev, uint16_t queue_id,