net/igc: support RSS
authorAlvin Zhang <alvinx.zhang@intel.com>
Wed, 15 Apr 2020 08:48:07 +0000 (16:48 +0800)
committerFerruh Yigit <ferruh.yigit@intel.com>
Tue, 21 Apr 2020 11:57:08 +0000 (13:57 +0200)
Below ops are added:
reta_update
reta_query
rss_hash_update
rss_hash_conf_get

Signed-off-by: Alvin Zhang <alvinx.zhang@intel.com>
Reviewed-by: Ferruh Yigit <ferruh.yigit@intel.com>
doc/guides/nics/features/igc.ini
drivers/net/igc/igc_ethdev.c
drivers/net/igc/igc_ethdev.h
drivers/net/igc/igc_txrx.c
drivers/net/igc/igc_txrx.h

index a364e04..23434af 100644 (file)
@@ -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
index b0548d0..78364a5 100644 (file)
@@ -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)
index d63890f..e8fd1b1 100644 (file)
 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.
index 3437c4d..3028a66 100644 (file)
@@ -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;
index 1b66b3f..63b19f5 100644 (file)
@@ -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,