ethdev: allow to set RSS hash computation flags and/or key
authorIvan Boule <ivan.boule@6wind.com>
Fri, 16 May 2014 08:58:40 +0000 (10:58 +0200)
committerThomas Monjalon <thomas.monjalon@6wind.com>
Tue, 27 May 2014 16:42:05 +0000 (18:42 +0200)
1) Add a new function "rss_hash_update" in the PMD API to dynamically
   update the RSS flags and/or the RSS key used by a NIC to compute the RSS
   hash of input packets.
   The new function uses the existing data structure "rte_eth_rss_conf" for
   the argument that contains the new hash flags and/or the new hash key to
   use.

2) Add the ixgbe-specific function "ixgbe_dev_rss_hash_update" and the
   igb-specific function "eth_igb_rss_hash_update" to update the RSS
   hash configuration of ixgbe and igb controllers respectively.
   Before changing anything, these 2 functions check that the update RSS
   operation does not attempt to disable RSS, if RSS was enabled at port
   initialization time, or does not attempt to enable RSS, if RSS was
   disabled at port initialization time.

Note:
   Configuring the RSS hash flags and the RSS key used by a NIC consists in
   updating appropriate PCI registers of the NIC.
   These operations have been manually tested with the interactive commands
   "write reg" and "write regbit" of the testpmd application.

Signed-off-by: Ivan Boule <ivan.boule@6wind.com>
Acked-by: Thomas Monjalon <thomas.monjalon@6wind.com>
lib/librte_ether/rte_ethdev.c
lib/librte_ether/rte_ethdev.h
lib/librte_pmd_e1000/e1000_ethdev.h
lib/librte_pmd_e1000/igb_ethdev.c
lib/librte_pmd_e1000/igb_rxtx.c
lib/librte_pmd_ixgbe/ixgbe_ethdev.c
lib/librte_pmd_ixgbe/ixgbe_ethdev.h
lib/librte_pmd_ixgbe/ixgbe_rxtx.c

index 473c98b..91375a1 100644 (file)
@@ -1571,6 +1571,28 @@ rte_eth_dev_rss_reta_query(uint8_t port_id, struct rte_eth_rss_reta *reta_conf)
        return (*dev->dev_ops->reta_query)(dev, reta_conf);
 }
 
+int
+rte_eth_dev_rss_hash_update(uint8_t port_id, struct rte_eth_rss_conf *rss_conf)
+{
+       struct rte_eth_dev *dev;
+       uint16_t rss_hash_protos;
+
+       if (port_id >= nb_ports) {
+               PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+               return (-ENODEV);
+       }
+       rss_hash_protos = rss_conf->rss_hf;
+       if ((rss_hash_protos != 0) &&
+           ((rss_hash_protos & ETH_RSS_PROTO_MASK) == 0)) {
+               PMD_DEBUG_TRACE("Invalid rss_hash_protos=0x%x\n",
+                               rss_hash_protos);
+               return (-EINVAL);
+       }
+       dev = &rte_eth_devices[port_id];
+       FUNC_PTR_OR_ERR_RET(*dev->dev_ops->rss_hash_update, -ENOTSUP);
+       return (*dev->dev_ops->rss_hash_update)(dev, rss_conf);
+}
+
 int
 rte_eth_led_on(uint8_t port_id)
 {
index d5ea46b..e4ad9a7 100644 (file)
@@ -331,6 +331,8 @@ struct rte_eth_rss_conf {
 #define ETH_RSS_IPV4_UDP    0x0040 /**< IPv4/UDP packet. */
 #define ETH_RSS_IPV6_UDP    0x0080 /**< IPv6/UDP packet. */
 #define ETH_RSS_IPV6_UDP_EX 0x0100 /**< IPv6/UDP with extension headers. */
+
+#define ETH_RSS_PROTO_MASK  0x01FF /**< Mask of valid RSS hash protocols */
 /* Definitions used for redirection table entry size */
 #define ETH_RSS_RETA_NUM_ENTRIES 128
 #define ETH_RSS_RETA_MAX_QUEUE   16  
@@ -966,6 +968,10 @@ typedef int (*reta_query_t)(struct rte_eth_dev *dev,
                                struct rte_eth_rss_reta *reta_conf);
 /**< @internal Query RSS redirection table on an Ethernet device */
 
+typedef int (*rss_hash_update_t)(struct rte_eth_dev *dev,
+                                struct rte_eth_rss_conf *rss_conf);
+/**< @internal Update RSS hash configuration of an Ethernet device */
+
 typedef int (*eth_dev_led_on_t)(struct rte_eth_dev *dev);
 /**< @internal Turn on SW controllable LED on an Ethernet device */
 
@@ -1153,6 +1159,8 @@ struct eth_dev_ops {
   bypass_wd_reset_t bypass_wd_reset;
 #endif
 
+       /** Configure RSS hash protocols. */
+       rss_hash_update_t rss_hash_update;
 };
 
 /**
@@ -2725,6 +2733,22 @@ int rte_eth_dev_bypass_wd_timeout_show(uint8_t port, uint32_t *wd_timeout);
  */
 int rte_eth_dev_bypass_wd_reset(uint8_t port);
 
+ /**
+ * Configuration of Receive Side Scaling hash computation of Ethernet device.
+ *
+ * @param port
+ *   The port identifier of the Ethernet device.
+ * @param rss_conf
+ *   The new configuration to use for RSS hash computation on the port.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENODEV) if port identifier is invalid.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-EINVAL) if bad parameter.
+ */
+int rte_eth_dev_rss_hash_update(uint8_t port_id,
+                               struct rte_eth_rss_conf *rss_conf);
+
 #ifdef __cplusplus
 }
 #endif
index d09064e..d9dc8d1 100644 (file)
@@ -138,6 +138,9 @@ uint16_t eth_igb_recv_pkts(void *rxq, struct rte_mbuf **rx_pkts,
 uint16_t eth_igb_recv_scattered_pkts(void *rxq,
                struct rte_mbuf **rx_pkts, uint16_t nb_pkts);
 
+int eth_igb_rss_hash_update(struct rte_eth_dev *dev,
+                           struct rte_eth_rss_conf *rss_conf);
+
 int eth_igbvf_rx_init(struct rte_eth_dev *dev);
 
 void eth_igbvf_tx_init(struct rte_eth_dev *dev);
index 044eac3..92794c8 100644 (file)
@@ -194,6 +194,7 @@ static struct eth_dev_ops eth_igb_ops = {
        .mac_addr_remove      = eth_igb_rar_clear,
        .reta_update          = eth_igb_rss_reta_update,
        .reta_query           = eth_igb_rss_reta_query,
+       .rss_hash_update      = eth_igb_rss_hash_update,
 };
 
 /*
index 7fe1780..9637704 100644 (file)
@@ -1519,53 +1519,28 @@ igb_rss_disable(struct rte_eth_dev *dev)
 }
 
 static void
-igb_rss_configure(struct rte_eth_dev *dev)
+igb_hw_rss_hash_set(struct e1000_hw *hw, struct rte_eth_rss_conf *rss_conf)
 {
-       struct e1000_hw *hw;
-       uint8_t *hash_key;
+       uint8_t  *hash_key;
        uint32_t rss_key;
        uint32_t mrqc;
-       uint32_t shift;
        uint16_t rss_hf;
        uint16_t i;
 
-       hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-
-       rss_hf = dev->data->dev_conf.rx_adv_conf.rss_conf.rss_hf;
-       if (rss_hf == 0) /* Disable RSS. */ {
-               igb_rss_disable(dev);
-               return;
-       }
-       hash_key = dev->data->dev_conf.rx_adv_conf.rss_conf.rss_key;
-       if (hash_key == NULL)
-               hash_key = rss_intel_key; /* Default hash key. */
-
-       /* Fill in RSS hash key. */
-       for (i = 0; i < 10; i++) {
-               rss_key  = hash_key[(i * 4)];
-               rss_key |= hash_key[(i * 4) + 1] << 8;
-               rss_key |= hash_key[(i * 4) + 2] << 16;
-               rss_key |= hash_key[(i * 4) + 3] << 24;
-               E1000_WRITE_REG_ARRAY(hw, E1000_RSSRK(0), i, rss_key);
-       }
-
-       /* Fill in redirection table. */
-       shift = (hw->mac.type == e1000_82575) ? 6 : 0;
-       for (i = 0; i < 128; i++) {
-               union e1000_reta {
-                       uint32_t dword;
-                       uint8_t  bytes[4];
-               } reta;
-               uint8_t q_idx;
-
-               q_idx = (uint8_t) ((dev->data->nb_rx_queues > 1) ?
-                                  i % dev->data->nb_rx_queues : 0);
-               reta.bytes[i & 3] = (uint8_t) (q_idx << shift);
-               if ((i & 3) == 3)
-                       E1000_WRITE_REG(hw, E1000_RETA(i >> 2), reta.dword);
+       hash_key = rss_conf->rss_key;
+       if (hash_key != NULL) {
+               /* Fill in RSS hash key */
+               for (i = 0; i < 10; i++) {
+                       rss_key  = hash_key[(i * 4)];
+                       rss_key |= hash_key[(i * 4) + 1] << 8;
+                       rss_key |= hash_key[(i * 4) + 2] << 16;
+                       rss_key |= hash_key[(i * 4) + 3] << 24;
+                       E1000_WRITE_REG_ARRAY(hw, E1000_RSSRK(0), i, rss_key);
+               }
        }
 
-       /* Set configured hashing functions in MRQC register. */
+       /* Set configured hashing protocols in MRQC register */
+       rss_hf = rss_conf->rss_hf;
        mrqc = E1000_MRQC_ENABLE_RSS_4Q; /* RSS enabled. */
        if (rss_hf & ETH_RSS_IPV4)
                mrqc |= E1000_MRQC_RSS_FIELD_IPV4;
@@ -1588,6 +1563,76 @@ igb_rss_configure(struct rte_eth_dev *dev)
        E1000_WRITE_REG(hw, E1000_MRQC, mrqc);
 }
 
+int
+eth_igb_rss_hash_update(struct rte_eth_dev *dev,
+                       struct rte_eth_rss_conf *rss_conf)
+{
+       struct e1000_hw *hw;
+       uint32_t mrqc;
+       uint16_t rss_hf;
+
+       hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+       /*
+        * Before changing anything, first check that the update RSS operation
+        * does not attempt to disable RSS, if RSS was enabled at
+        * initialization time, or does not attempt to enable RSS, if RSS was
+        * disabled at initialization time.
+        */
+       rss_hf = rss_conf->rss_hf;
+       mrqc = E1000_READ_REG(hw, E1000_MRQC);
+       if (!(mrqc & E1000_MRQC_ENABLE_MASK)) { /* RSS disabled */
+               if (rss_hf != 0) /* Enable RSS */
+                       return -(EINVAL);
+               return 0; /* Nothing to do */
+       }
+       /* RSS enabled */
+       if (rss_hf == 0) /* Disable RSS */
+               return -(EINVAL);
+       igb_hw_rss_hash_set(hw, rss_conf);
+       return 0;
+}
+
+static void
+igb_rss_configure(struct rte_eth_dev *dev)
+{
+       struct rte_eth_rss_conf rss_conf;
+       struct e1000_hw *hw;
+       uint32_t shift;
+       uint16_t i;
+
+       hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+       /* Fill in redirection table. */
+       shift = (hw->mac.type == e1000_82575) ? 6 : 0;
+       for (i = 0; i < 128; i++) {
+               union e1000_reta {
+                       uint32_t dword;
+                       uint8_t  bytes[4];
+               } reta;
+               uint8_t q_idx;
+
+               q_idx = (uint8_t) ((dev->data->nb_rx_queues > 1) ?
+                                  i % dev->data->nb_rx_queues : 0);
+               reta.bytes[i & 3] = (uint8_t) (q_idx << shift);
+               if ((i & 3) == 3)
+                       E1000_WRITE_REG(hw, E1000_RETA(i >> 2), reta.dword);
+       }
+
+       /*
+        * Configure the RSS key and the RSS protocols used to compute
+        * the RSS hash of input packets.
+        */
+       rss_conf = dev->data->dev_conf.rx_adv_conf.rss_conf;
+       if (rss_conf.rss_hf == 0) {
+               igb_rss_disable(dev);
+               return;
+       }
+       if (rss_conf.rss_key == NULL)
+               rss_conf.rss_key = rss_intel_key; /* Default hash key */
+       igb_hw_rss_hash_set(hw, &rss_conf);
+}
+
 /*
  * Check if the mac type support VMDq or not.
  * Return 1 if it supports, otherwise, return 0.
index 113271e..0b81f2b 100644 (file)
@@ -307,6 +307,7 @@ static struct eth_dev_ops ixgbe_eth_dev_ops = {
        .bypass_ver_show      = ixgbe_bypass_ver_show,
        .bypass_wd_reset      = ixgbe_bypass_wd_reset,
 #endif /* RTE_NIC_BYPASS */
+       .rss_hash_update = ixgbe_dev_rss_hash_update,
 };
 
 /*
index 9d7e93f..06d51ab 100644 (file)
@@ -235,6 +235,9 @@ uint16_t ixgbe_xmit_pkts(void *tx_queue, struct rte_mbuf **tx_pkts,
 uint16_t ixgbe_xmit_pkts_simple(void *tx_queue, struct rte_mbuf **tx_pkts,
                uint16_t nb_pkts);
 
+int ixgbe_dev_rss_hash_update(struct rte_eth_dev *dev,
+                             struct rte_eth_rss_conf *rss_conf);
+
 /*
  * Flow director function prototypes
  */
index 303144b..111d1fa 100644 (file)
@@ -2292,49 +2292,29 @@ ixgbe_rss_disable(struct rte_eth_dev *dev)
 }
 
 static void
-ixgbe_rss_configure(struct rte_eth_dev *dev)
+ixgbe_hw_rss_hash_set(struct ixgbe_hw *hw, struct rte_eth_rss_conf *rss_conf)
 {
-       struct ixgbe_hw *hw;
-       uint8_t *hash_key;
-       uint32_t rss_key;
+       uint8_t  *hash_key;
        uint32_t mrqc;
-       uint32_t reta;
+       uint32_t rss_key;
        uint16_t rss_hf;
        uint16_t i;
-       uint16_t j;
-
-       PMD_INIT_FUNC_TRACE();
-       hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-
-       rss_hf = dev->data->dev_conf.rx_adv_conf.rss_conf.rss_hf;
-       if (rss_hf == 0) { /* Disable RSS */
-               ixgbe_rss_disable(dev);
-               return;
-       }
-       hash_key = dev->data->dev_conf.rx_adv_conf.rss_conf.rss_key;
-       if (hash_key == NULL)
-               hash_key = rss_intel_key; /* Default hash key */
-
-       /* Fill in RSS hash key */
-       for (i = 0; i < 10; i++) {
-               rss_key  = hash_key[(i * 4)];
-               rss_key |= hash_key[(i * 4) + 1] << 8;
-               rss_key |= hash_key[(i * 4) + 2] << 16;
-               rss_key |= hash_key[(i * 4) + 3] << 24;
-               IXGBE_WRITE_REG_ARRAY(hw, IXGBE_RSSRK(0), i, rss_key);
-       }
 
-       /* Fill in redirection table */
-       reta = 0;
-       for (i = 0, j = 0; i < 128; i++, j++) {
-               if (j == dev->data->nb_rx_queues) j = 0;
-               reta = (reta << 8) | j;
-               if ((i & 3) == 3)
-                       IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2), rte_bswap32(reta));
+       hash_key = rss_conf->rss_key;
+       if (hash_key != NULL) {
+               /* Fill in RSS hash key */
+               for (i = 0; i < 10; i++) {
+                       rss_key  = hash_key[(i * 4)];
+                       rss_key |= hash_key[(i * 4) + 1] << 8;
+                       rss_key |= hash_key[(i * 4) + 2] << 16;
+                       rss_key |= hash_key[(i * 4) + 3] << 24;
+                       IXGBE_WRITE_REG_ARRAY(hw, IXGBE_RSSRK(0), i, rss_key);
+               }
        }
 
-       /* Set configured hashing functions in MRQC register */
-       mrqc = IXGBE_MRQC_RSSEN; /* RSS enable */
+       /* Set configured hashing protocols in MRQC register */
+       rss_hf = rss_conf->rss_hf;
+       mrqc = IXGBE_MRQC_RSSEN; /* Enable RSS */
        if (rss_hf & ETH_RSS_IPV4)
                mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4;
        if (rss_hf & ETH_RSS_IPV4_TCP)
@@ -2356,6 +2336,80 @@ ixgbe_rss_configure(struct rte_eth_dev *dev)
        IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
 }
 
+int
+ixgbe_dev_rss_hash_update(struct rte_eth_dev *dev,
+                         struct rte_eth_rss_conf *rss_conf)
+{
+       struct ixgbe_hw *hw;
+       uint32_t mrqc;
+       uint16_t rss_hf;
+
+       hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+       /*
+        * Excerpt from section 7.1.2.8 Receive-Side Scaling (RSS):
+        *     "RSS enabling cannot be done dynamically while it must be
+        *      preceded by a software reset"
+        * Before changing anything, first check that the update RSS operation
+        * does not attempt to disable RSS, if RSS was enabled at
+        * initialization time, or does not attempt to enable RSS, if RSS was
+        * disabled at initialization time.
+        */
+       rss_hf = rss_conf->rss_hf;
+       mrqc = IXGBE_READ_REG(hw, IXGBE_MRQC);
+       if (!(mrqc & IXGBE_MRQC_RSSEN)) { /* RSS disabled */
+               if (rss_hf != 0) /* Enable RSS */
+                       return -(EINVAL);
+               return 0; /* Nothing to do */
+       }
+       /* RSS enabled */
+       if (rss_hf == 0) /* Disable RSS */
+               return -(EINVAL);
+       ixgbe_hw_rss_hash_set(hw, rss_conf);
+       return 0;
+}
+
+static void
+ixgbe_rss_configure(struct rte_eth_dev *dev)
+{
+       struct rte_eth_rss_conf rss_conf;
+       struct ixgbe_hw *hw;
+       uint32_t reta;
+       uint16_t i;
+       uint16_t j;
+
+       PMD_INIT_FUNC_TRACE();
+       hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+       /*
+        * Fill in redirection table
+        * The byte-swap is needed because NIC registers are in
+        * little-endian order.
+        */
+       reta = 0;
+       for (i = 0, j = 0; i < 128; i++, j++) {
+               if (j == dev->data->nb_rx_queues)
+                       j = 0;
+               reta = (reta << 8) | j;
+               if ((i & 3) == 3)
+                       IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2),
+                                       rte_bswap32(reta));
+       }
+
+       /*
+        * Configure the RSS key and the RSS protocols used to compute
+        * the RSS hash of input packets.
+        */
+       rss_conf = dev->data->dev_conf.rx_adv_conf.rss_conf;
+       if (rss_conf.rss_hf == 0) {
+               ixgbe_rss_disable(dev);
+               return;
+       }
+       if (rss_conf.rss_key == NULL)
+               rss_conf.rss_key = rss_intel_key; /* Default hash key */
+       ixgbe_hw_rss_hash_set(hw, &rss_conf);
+}
+
 #define NUM_VFTA_REGISTERS 128
 #define NIC_RX_BUFFER_SIZE 0x200