1) Add a new function "rss_hash_conf_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_conf_update" and the
   igb-specific function "eth_igb_rss_hash_conf_update" to update the RSS
   hash configuration of ixgbe and igb controllers respectively.

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 at 6wind.com>
---
 lib/librte_ether/rte_ethdev.c       |   23 +++++++++
 lib/librte_ether/rte_ethdev.h       |   25 ++++++++++
 lib/librte_pmd_e1000/e1000_ethdev.h |    3 ++
 lib/librte_pmd_e1000/igb_ethdev.c   |    1 +
 lib/librte_pmd_e1000/igb_rxtx.c     |   93 +++++++++++++++++++++--------------
 lib/librte_pmd_ixgbe/ixgbe_ethdev.c |    1 +
 lib/librte_pmd_ixgbe/ixgbe_ethdev.h |    3 ++
 lib/librte_pmd_ixgbe/ixgbe_rxtx.c   |   90 ++++++++++++++++++++-------------
 8 files changed, 169 insertions(+), 70 deletions(-)

diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 473c98b..c00dff0 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -1572,6 +1572,29 @@ rte_eth_dev_rss_reta_query(uint8_t port_id, struct 
rte_eth_rss_reta *reta_conf)
 }

 int
+rte_eth_dev_rss_hash_conf_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_conf_update, -ENOTSUP);
+       return (*dev->dev_ops->rss_hash_conf_update)(dev, rss_conf);
+}
+
+int
 rte_eth_led_on(uint8_t port_id)
 {
        struct rte_eth_dev *dev;
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index dea7471..a970761 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -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_conf_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_conf_update_t rss_hash_conf_update;
 };

 /**
@@ -2859,6 +2867,23 @@ 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_conf_update(uint8_t port_id,
+                                struct rte_eth_rss_conf *rss_conf);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_pmd_e1000/e1000_ethdev.h 
b/lib/librte_pmd_e1000/e1000_ethdev.h
index d09064e..e228c53 100644
--- a/lib/librte_pmd_e1000/e1000_ethdev.h
+++ b/lib/librte_pmd_e1000/e1000_ethdev.h
@@ -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_conf_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);
diff --git a/lib/librte_pmd_e1000/igb_ethdev.c 
b/lib/librte_pmd_e1000/igb_ethdev.c
index 673b4de..07ae149 100644
--- a/lib/librte_pmd_e1000/igb_ethdev.c
+++ b/lib/librte_pmd_e1000/igb_ethdev.c
@@ -193,6 +193,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_conf_update = eth_igb_rss_hash_conf_update,
 };

 /*
diff --git a/lib/librte_pmd_e1000/igb_rxtx.c b/lib/librte_pmd_e1000/igb_rxtx.c
index 1ebe2f5..5499fd8 100644
--- a/lib/librte_pmd_e1000/igb_rxtx.c
+++ b/lib/librte_pmd_e1000/igb_rxtx.c
@@ -1518,54 +1518,36 @@ igb_rss_disable(struct rte_eth_dev *dev)
        E1000_WRITE_REG(hw, E1000_MRQC, mrqc);
 }

-static void
-igb_rss_configure(struct rte_eth_dev *dev)
+int
+eth_igb_rss_hash_conf_update(struct rte_eth_dev *dev,
+                            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);
+       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);
+               }
        }
-
-       /* 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);
+       rss_hf = rss_conf->rss_hf;
+       if (rss_hf == 0) { /* Disable RSS */
+               igb_rss_disable(dev);
+               return 0;
        }

-       /* Set configured hashing functions in MRQC register. */
+       /* Set configured hashing protocols in MRQC register */
        mrqc = E1000_MRQC_ENABLE_RSS_4Q; /* RSS enabled. */
        if (rss_hf & ETH_RSS_IPV4)
                mrqc |= E1000_MRQC_RSS_FIELD_IPV4;
@@ -1586,6 +1568,43 @@ igb_rss_configure(struct rte_eth_dev *dev)
        if (rss_hf & ETH_RSS_IPV6_UDP_EX)
                mrqc |= E1000_MRQC_RSS_FIELD_IPV6_UDP_EX;
        E1000_WRITE_REG(hw, E1000_MRQC, mrqc);
+       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_key == NULL)
+               rss_conf.rss_key = rss_intel_key; /* Default hash key */
+       (void) eth_igb_rss_hash_conf_update(dev, &rss_conf);
 }

 /*
diff --git a/lib/librte_pmd_ixgbe/ixgbe_ethdev.c 
b/lib/librte_pmd_ixgbe/ixgbe_ethdev.c
index 6dd52d7..5910501 100644
--- a/lib/librte_pmd_ixgbe/ixgbe_ethdev.c
+++ b/lib/librte_pmd_ixgbe/ixgbe_ethdev.c
@@ -300,6 +300,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_conf_update = ixgbe_dev_rss_hash_conf_update,
 };

 /*
diff --git a/lib/librte_pmd_ixgbe/ixgbe_ethdev.h 
b/lib/librte_pmd_ixgbe/ixgbe_ethdev.h
index 9d7e93f..3d33ad2 100644
--- a/lib/librte_pmd_ixgbe/ixgbe_ethdev.h
+++ b/lib/librte_pmd_ixgbe/ixgbe_ethdev.h
@@ -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_conf_update(struct rte_eth_dev *dev,
+                                  struct rte_eth_rss_conf *rss_conf);
+
 /*
  * Flow director function prototypes
  */
diff --git a/lib/librte_pmd_ixgbe/ixgbe_rxtx.c 
b/lib/librte_pmd_ixgbe/ixgbe_rxtx.c
index 7930dbd..877ecfd 100644
--- a/lib/librte_pmd_ixgbe/ixgbe_rxtx.c
+++ b/lib/librte_pmd_ixgbe/ixgbe_rxtx.c
@@ -2291,50 +2291,37 @@ ixgbe_rss_disable(struct rte_eth_dev *dev)
        IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
 }

-static void
-ixgbe_rss_configure(struct rte_eth_dev *dev)
+int
+ixgbe_dev_rss_hash_conf_update(struct rte_eth_dev *dev,
+                              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;
+       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);
+               }
+       }
+       rss_hf = 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));
+               return 0;
        }

-       /* Set configured hashing functions in MRQC register */
-       mrqc = IXGBE_MRQC_RSSEN; /* RSS enable */
+       /* Set configured hashing protocols in MRQC register */
+       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)
@@ -2354,6 +2341,43 @@ ixgbe_rss_configure(struct rte_eth_dev *dev)
        if (rss_hf & ETH_RSS_IPV6_UDP_EX)
                mrqc |= IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP;
        IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
+       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_key == NULL)
+               rss_conf.rss_key = rss_intel_key; /* Default hash key */
+       (void) ixgbe_dev_rss_hash_conf_update(dev, &rss_conf);
 }

 #define NUM_VFTA_REGISTERS 128
-- 
1.7.10.4

Reply via email to