DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [PATCH v3 0/7] Support configuring hash functions
@ 2014-09-30  6:20 Helin Zhang
  2014-09-30  6:20 ` [dpdk-dev] [PATCH v3 1/7] ethdev: add more annotations Helin Zhang
                   ` (6 more replies)
  0 siblings, 7 replies; 71+ messages in thread
From: Helin Zhang @ 2014-09-30  6:20 UTC (permalink / raw)
  To: dev

These patches mainly support configuring hash functions.
In detail,
 - It can get or set hash functions.
 - It can configure symmetric hash functions.
   * Get/set symmetric hash enable per port.
   * Get/set symmetric hash enable per 'PCTYPE'.
   * Get/set filter swap configurations.
 - 'ethdev' level interfaces are added.
   * 'rte_eth_dev_filter_supported', to check if a filter control
     is supported on a port.
   * 'rte_eth_dev_filter_ctrl', a common API to execute
     specific filter control.
 - Six commands have been implemented in testpmd to support
   testing above.
   * get_sym_hash_ena_per_port
   * set_sym_hash_ena_per_port
   * get_sym_hash_ena_per_pctype
   * set_sym_hash_ena_per_pctype
   * get_filter_swap
   * set_filter_swap
   * get_hash_function
   * set_hash_function

Note that 'PCTYPE' means 'Packet Classification Type'.

v3 changes:
* Removed renamings in rte_ethdev.h.
* Redesigned filter control API and its relevant structures/enums.
* Renamed header file from rte_eth_features.h to rte_eth_ctrol.h.
* Remove public header file of rte_i40e.h specific for i40e.
* Added hardware initialization function during port init.
* Used constant random hash keys in i40e PF.
* renamed the commands in testpmd based on the redesigned filter control API.

Helin Zhang (7):
  ethdev: add more annotations
  ethdev: add interfaces and relevant for filter control
  ethdev: add structures and enum for hash filter control
  i40e: add hash filter control implementation
  i40e: add hardware initialization
  i40e: Use constant random hash keys
  app/testpmd: add commands to support hash filter control

 app/test-pmd/cmdline.c            | 565 ++++++++++++++++++++++++++++++++++++++
 lib/librte_ether/Makefile         |   1 +
 lib/librte_ether/rte_eth_ctrl.h   | 154 +++++++++++
 lib/librte_ether/rte_ethdev.c     |  32 +++
 lib/librte_ether/rte_ethdev.h     |  53 +++-
 lib/librte_pmd_i40e/i40e_ethdev.c | 492 ++++++++++++++++++++++++++++++++-
 6 files changed, 1290 insertions(+), 7 deletions(-)
 create mode 100644 lib/librte_ether/rte_eth_ctrl.h

-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v3 1/7] ethdev: add more annotations
  2014-09-30  6:20 [dpdk-dev] [PATCH v3 0/7] Support configuring hash functions Helin Zhang
@ 2014-09-30  6:20 ` Helin Zhang
  2014-10-13  6:12   ` [dpdk-dev] [PATCH v4 0/7] Support configuring hash functions Helin Zhang
  2014-09-30  6:20 ` [dpdk-dev] [PATCH v3 2/7] ethdev: add interfaces and relevant for filter control Helin Zhang
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 71+ messages in thread
From: Helin Zhang @ 2014-09-30  6:20 UTC (permalink / raw)
  To: dev

Add more annotations about packet classification type.

v3 changes:
* Remove renamings of RSS 'SHIFT's.
* Add more annotations for RSS 'SHIFT's.

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
Acked-by: Jingjing Wu <jingjing.wu@intel.com>
---
 lib/librte_ether/rte_ethdev.h | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index bbc6022..ad7b9d4 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -334,7 +334,10 @@ struct rte_eth_rss_conf {
 	uint64_t rss_hf;     /**< Hash functions to apply - see below. */
 };
 
-/* Supported RSS offloads */
+/*
+ * Supported RSS offloads, below '_SHIFT' can also be used to represent
+ * the 'Packet Classification type (pctype)'.
+ */
 /* for 1G & 10G */
 #define ETH_RSS_IPV4_SHIFT                    0
 #define ETH_RSS_IPV4_TCP_SHIFT                1
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v3 2/7] ethdev: add interfaces and relevant for filter control
  2014-09-30  6:20 [dpdk-dev] [PATCH v3 0/7] Support configuring hash functions Helin Zhang
  2014-09-30  6:20 ` [dpdk-dev] [PATCH v3 1/7] ethdev: add more annotations Helin Zhang
@ 2014-09-30  6:20 ` Helin Zhang
  2014-09-30  6:20 ` [dpdk-dev] [PATCH v3 3/7] ethdev: add structures and enum for hash " Helin Zhang
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 71+ messages in thread
From: Helin Zhang @ 2014-09-30  6:20 UTC (permalink / raw)
  To: dev

To support flexible filter control, 'rte_eth_dev_filter_ctrl()'
and 'rte_eth_dev_filter_supported()' are added. In addition, filter
types and operations are defined in a newly added header file.

v3 changes:
* Interfaces to be added have been re-designed.
* Header file has been renamed.

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
Acked-by: Jingjing Wu <jingjing.wu@intel.com>
---
 lib/librte_ether/Makefile       |  1 +
 lib/librte_ether/rte_eth_ctrl.h | 80 +++++++++++++++++++++++++++++++++++++++++
 lib/librte_ether/rte_ethdev.c   | 32 +++++++++++++++++
 lib/librte_ether/rte_ethdev.h   | 48 +++++++++++++++++++++++++
 4 files changed, 161 insertions(+)
 create mode 100644 lib/librte_ether/rte_eth_ctrl.h

diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
index b310f8b..a461c31 100644
--- a/lib/librte_ether/Makefile
+++ b/lib/librte_ether/Makefile
@@ -46,6 +46,7 @@ SRCS-y += rte_ethdev.c
 #
 SYMLINK-y-include += rte_ether.h
 SYMLINK-y-include += rte_ethdev.h
+SYMLINK-y-include += rte_eth_ctrl.h
 
 # this lib depends upon:
 DEPDIRS-y += lib/librte_eal lib/librte_mempool lib/librte_ring lib/librte_mbuf
diff --git a/lib/librte_ether/rte_eth_ctrl.h b/lib/librte_ether/rte_eth_ctrl.h
new file mode 100644
index 0000000..aaea075
--- /dev/null
+++ b/lib/librte_ether/rte_eth_ctrl.h
@@ -0,0 +1,80 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETH_CTRL_H_
+#define _RTE_ETH_CTRL_H_
+
+/**
+ * @file
+ *
+ * Ethernet device features and related data structures used
+ * by control APIs should be defined in this file.
+ *
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Feature filter types
+ */
+enum rte_filter_type {
+	RTE_ETH_FILTER_NONE = 0,
+	RTE_ETH_FILTER_HASH,
+	RTE_ETH_FILTER_FDIR,
+	RTE_ETH_FILTER_TUNNEL,
+	RTE_ETH_FILTER_MAX,
+};
+
+/**
+ * All generic operations to filters
+ */
+enum rte_filter_op {
+	/**< used to check whether the type filter is supported */
+	RTE_ETH_FILTER_OP_NONE = 0,
+	RTE_ETH_FILTER_OP_ADD,      /**< add filter entry */
+	RTE_ETH_FILTER_OP_UPDATE,   /**< update filter entry */
+	RTE_ETH_FILTER_OP_DELETE,   /**< delete filter entry */
+	RTE_ETH_FILTER_OP_GET,      /**< get filter entry */
+	RTE_ETH_FILTER_OP_SET,      /**< configurations */
+	/**< get information of filter, such as status or statistics */
+	RTE_ETH_FILTER_OP_GET_INFO,
+	RTE_ETH_FILTER_OP_MAX,
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_ETH_CTRL_H_ */
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index b71b679..fdafb15 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -3139,3 +3139,35 @@ rte_eth_dev_get_flex_filter(uint8_t port_id, uint16_t index,
 	return (*dev->dev_ops->get_flex_filter)(dev, index, filter,
 						rx_queue);
 }
+
+int
+rte_eth_dev_filter_supported(uint8_t port_id, enum rte_filter_type filter_type)
+{
+	struct rte_eth_dev *dev;
+
+	if (port_id >= nb_ports) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->filter_ctrl, -ENOTSUP);
+	return (*dev->dev_ops->filter_ctrl)(dev, filter_type,
+				RTE_ETH_FILTER_OP_NONE, NULL);
+}
+
+int
+rte_eth_dev_filter_ctrl(uint8_t port_id, enum rte_filter_type filter_type,
+		       enum rte_filter_op filter_op, void *arg)
+{
+	struct rte_eth_dev *dev;
+
+	if (port_id >= nb_ports) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->filter_ctrl, -ENOTSUP);
+	return (*dev->dev_ops->filter_ctrl)(dev, filter_type, filter_op, arg);
+}
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index ad7b9d4..b6e0ffc 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -177,6 +177,7 @@ extern "C" {
 #include <rte_pci.h>
 #include <rte_mbuf.h>
 #include "rte_ether.h"
+#include "rte_eth_ctrl.h"
 
 /**
  * A structure used to retrieve statistics for an Ethernet port.
@@ -1386,6 +1387,12 @@ typedef int (*eth_get_flex_filter_t)(struct rte_eth_dev *dev,
 			uint16_t *rx_queue);
 /**< @internal Get a flex filter rule on an Ethernet device */
 
+typedef int (*eth_filter_ctrl_t)(struct rte_eth_dev *dev,
+				 enum rte_filter_type filter_type,
+				 enum rte_filter_op filter_op,
+				 void *arg);
+/**< @internal Take operations to assigned filter type on an Ethernet device */
+
 /**
  * @internal A structure containing the functions exported by an Ethernet driver.
  */
@@ -1494,6 +1501,7 @@ struct eth_dev_ops {
 	eth_add_flex_filter_t          add_flex_filter;      /**< add flex filter. */
 	eth_remove_flex_filter_t       remove_flex_filter;   /**< remove flex filter. */
 	eth_get_flex_filter_t          get_flex_filter;      /**< get flex filter. */
+	eth_filter_ctrl_t              filter_ctrl;          /**< common filter control*/
 };
 
 /**
@@ -3619,6 +3627,46 @@ int rte_eth_dev_remove_flex_filter(uint8_t port_id, uint16_t index);
 int rte_eth_dev_get_flex_filter(uint8_t port_id, uint16_t index,
 			struct rte_flex_filter *filter, uint16_t *rx_queue);
 
+/**
+ * Check whether the filter type is supported on an Ethernet device.
+ * All the supported filter types are defined in 'rte_eth_ctrl.h'.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param filter_type
+ *   filter type.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support this filter type.
+ *   - (-ENODEV) if *port_id* invalid.
+ */
+int rte_eth_dev_filter_supported(uint8_t port_id,
+				 enum rte_filter_type filter_type);
+
+/**
+ * Take operations to assigned filter type on an Ethernet device.
+ * All the supported operations and filter types are defined in
+ * 'rte_eth_ctrl.h'.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param filter_type
+ *   filter type.
+  * @param filter_op
+ *   The operation taken to assigned filter.
+ * @param arg
+ *   A pointer to arguments defined specifically for the operation.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_filter_ctrl(uint8_t port_id,
+			    enum rte_filter_type filter_type,
+			    enum rte_filter_op filter_op,
+			    void *arg);
+
 #ifdef __cplusplus
 }
 #endif
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v3 3/7] ethdev: add structures and enum for hash filter control
  2014-09-30  6:20 [dpdk-dev] [PATCH v3 0/7] Support configuring hash functions Helin Zhang
  2014-09-30  6:20 ` [dpdk-dev] [PATCH v3 1/7] ethdev: add more annotations Helin Zhang
  2014-09-30  6:20 ` [dpdk-dev] [PATCH v3 2/7] ethdev: add interfaces and relevant for filter control Helin Zhang
@ 2014-09-30  6:20 ` Helin Zhang
  2014-09-30  6:20 ` [dpdk-dev] [PATCH v3 4/7] i40e: add hash filter control implementation Helin Zhang
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 71+ messages in thread
From: Helin Zhang @ 2014-09-30  6:20 UTC (permalink / raw)
  To: dev

Structures and enum are added in rte_eth_ctrl.h to support hash
filter control.

v3 changes:
* Common structures are added in rte_eth_ctrl.h to support hash
  filter control.
* Hash filter info types and hash function types are added in
  rte_eth_ctrl.h to support filter control.

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
Acked-by: Jingjing Wu <jingjing.wu@intel.com>
---
 lib/librte_ether/rte_eth_ctrl.h | 74 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 74 insertions(+)

diff --git a/lib/librte_ether/rte_eth_ctrl.h b/lib/librte_ether/rte_eth_ctrl.h
index aaea075..10197fc 100644
--- a/lib/librte_ether/rte_eth_ctrl.h
+++ b/lib/librte_ether/rte_eth_ctrl.h
@@ -73,6 +73,80 @@ enum rte_filter_op {
 	RTE_ETH_FILTER_OP_MAX,
 };
 
+/**
+ * Hash filter information types.
+ */
+enum rte_eth_hash_filter_info_type {
+	RTE_ETH_HASH_FILTER_INFO_TYPE_UNKNOWN = 0,
+	RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PCTYPE,
+	RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PORT,
+	RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP,
+	RTE_ETH_HASH_FILTER_INFO_TYPE_HASH_FUNCTION,
+	RTE_ETH_HASH_FILTER_INFO_TYPE_MAX,
+};
+
+/**
+ * Hash function types.
+ */
+enum rte_eth_hash_function {
+	RTE_ETH_HASH_FUNCTION_UNKNOWN = 0,
+	RTE_ETH_HASH_FUNCTION_TOEPLITZ,
+	RTE_ETH_HASH_FUNCTION_SIMPLE_XOR,
+	RTE_ETH_HASH_FUNCTION_MAX,
+};
+
+/**
+ * A structure used to set or get symmetric hash enable information, to support
+ * 'RTE_ETH_FILTER_HASH', 'RTE_ETH_FILTER_OP_GET/RTE_ETH_FILTER_OP_SET', with
+ * information type 'RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PCTYPE'.
+ */
+struct rte_eth_sym_hash_ena_info {
+	/**< packet classification type, defined in rte_ethdev.h */
+	uint8_t pctype;
+	uint8_t enable; /**< enable or disable flag */
+};
+
+/**
+ * A structure used to set or get filter swap information, to support
+ * 'RTE_ETH_FILTER_HASH', 'RTE_ETH_FILTER_OP_GET/RTE_ETH_FILTER_OP_SET',
+ * with information type 'RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP'.
+ */
+struct rte_eth_filter_swap_info {
+	/**< Packet classification type, defined in rte_ethdev.h */
+	uint8_t pctype;
+	/**< Offset of the 1st field of the 1st couple to be swapped. */
+	uint8_t off0_src0;
+	/**< Offset of the 2nd field of the 1st couple to be swapped. */
+	uint8_t off0_src1;
+	/**< Field length of the first couple. */
+	uint8_t len0;
+	/**< Offset of the 1st field of the 2nd couple to be swapped. */
+	uint8_t off1_src0;
+	/**< Offset of the 2nd field of the 2nd couple to be swapped. */
+	uint8_t off1_src1;
+	/**< Field length of the second couple. */
+	uint8_t len1;
+};
+
+/**
+ * A structure used to set or get hash filter information, to support filter
+ * type of 'RTE_ETH_FILTER_HASH' and its operations.
+ */
+struct rte_eth_hash_filter_info {
+	enum rte_eth_hash_filter_info_type info_type; /**< Information type. */
+	/**< Details of hash filter infomation */
+	union {
+		/* For RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PCTYPE */
+		struct rte_eth_sym_hash_ena_info sym_hash_ena;
+		/* For RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP */
+		struct rte_eth_filter_swap_info filter_swap;
+		/* For RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PORT */
+		uint8_t enable;
+		/* For RTE_ETH_HASH_FILTER_INFO_TYPE_HASH_FUNCTION */
+		enum rte_eth_hash_function hash_function;
+	} info;
+};
+
 #ifdef __cplusplus
 }
 #endif
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v3 4/7] i40e: add hash filter control implementation
  2014-09-30  6:20 [dpdk-dev] [PATCH v3 0/7] Support configuring hash functions Helin Zhang
                   ` (2 preceding siblings ...)
  2014-09-30  6:20 ` [dpdk-dev] [PATCH v3 3/7] ethdev: add structures and enum for hash " Helin Zhang
@ 2014-09-30  6:20 ` Helin Zhang
  2014-09-30  6:20 ` [dpdk-dev] [PATCH v3 5/7] i40e: add hardware initialization Helin Zhang
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 71+ messages in thread
From: Helin Zhang @ 2014-09-30  6:20 UTC (permalink / raw)
  To: dev

Hash filter control has been implemented for i40e. It includes
getting/setting
- hash function type
- symmetric hash enable per pctype (packet classification type)
- symmetric hash enable per port
- filter swap configurations

v3 changes:
* Remove public header file specific for i40e.
* Use the re-designed filter control API, filter types,
  and operations.

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
Acked-by: Jingjing Wu <jingjing.wu@intel.com>
---
 lib/librte_pmd_i40e/i40e_ethdev.c | 402 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 402 insertions(+)

diff --git a/lib/librte_pmd_i40e/i40e_ethdev.c b/lib/librte_pmd_i40e/i40e_ethdev.c
index 26f1799..ee7c9de 100644
--- a/lib/librte_pmd_i40e/i40e_ethdev.c
+++ b/lib/librte_pmd_i40e/i40e_ethdev.c
@@ -205,6 +205,10 @@ static int i40e_dev_rss_hash_update(struct rte_eth_dev *dev,
 				    struct rte_eth_rss_conf *rss_conf);
 static int i40e_dev_rss_hash_conf_get(struct rte_eth_dev *dev,
 				      struct rte_eth_rss_conf *rss_conf);
+static int i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
+				enum rte_filter_type filter_type,
+				enum rte_filter_op filter_op,
+				void *arg);
 
 /* Default hash key buffer for RSS */
 static uint32_t rss_key_default[I40E_PFQF_HKEY_MAX_INDEX + 1];
@@ -256,6 +260,7 @@ static struct eth_dev_ops i40e_eth_dev_ops = {
 	.reta_query                   = i40e_dev_rss_reta_query,
 	.rss_hash_update              = i40e_dev_rss_hash_update,
 	.rss_hash_conf_get            = i40e_dev_rss_hash_conf_get,
+	.filter_ctrl                  = i40e_dev_filter_ctrl,
 };
 
 static struct eth_driver rte_i40e_pmd = {
@@ -4131,3 +4136,400 @@ i40e_pf_config_mq_rx(struct i40e_pf *pf)
 
 	return 0;
 }
+
+/* Get the symmetric hash enable configurations per PCTYPE */
+static int
+i40e_get_symmetric_hash_enable_per_pctype(struct i40e_hw *hw,
+			struct rte_eth_sym_hash_ena_info *info)
+{
+	uint32_t reg;
+
+	switch (info->pctype) {
+	case ETH_RSS_NONF_IPV4_UDP_SHIFT:
+	case ETH_RSS_NONF_IPV4_TCP_SHIFT:
+	case ETH_RSS_NONF_IPV4_SCTP_SHIFT:
+	case ETH_RSS_NONF_IPV4_OTHER_SHIFT:
+	case ETH_RSS_FRAG_IPV4_SHIFT:
+	case ETH_RSS_NONF_IPV6_UDP_SHIFT:
+	case ETH_RSS_NONF_IPV6_TCP_SHIFT:
+	case ETH_RSS_NONF_IPV6_SCTP_SHIFT:
+	case ETH_RSS_NONF_IPV6_OTHER_SHIFT:
+	case ETH_RSS_FRAG_IPV6_SHIFT:
+	case ETH_RSS_L2_PAYLOAD_SHIFT:
+		reg = I40E_READ_REG(hw, I40E_GLQF_HSYM(info->pctype));
+		info->enable = reg & I40E_GLQF_HSYM_SYMH_ENA_MASK ? 1 : 0;
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "PCTYPE[%u] not supported", info->pctype);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* Set the symmetric hash enable configurations per PCTYPE */
+static int
+i40e_set_symmetric_hash_enable_per_pctype(struct i40e_hw *hw,
+		const struct rte_eth_sym_hash_ena_info *info)
+{
+	uint32_t reg;
+
+	switch (info->pctype) {
+	case ETH_RSS_NONF_IPV4_UDP_SHIFT:
+	case ETH_RSS_NONF_IPV4_TCP_SHIFT:
+	case ETH_RSS_NONF_IPV4_SCTP_SHIFT:
+	case ETH_RSS_NONF_IPV4_OTHER_SHIFT:
+	case ETH_RSS_FRAG_IPV4_SHIFT:
+	case ETH_RSS_NONF_IPV6_UDP_SHIFT:
+	case ETH_RSS_NONF_IPV6_TCP_SHIFT:
+	case ETH_RSS_NONF_IPV6_SCTP_SHIFT:
+	case ETH_RSS_NONF_IPV6_OTHER_SHIFT:
+	case ETH_RSS_FRAG_IPV6_SHIFT:
+	case ETH_RSS_L2_PAYLOAD_SHIFT:
+		reg = info->enable ? I40E_GLQF_HSYM_SYMH_ENA_MASK : 0;
+		I40E_WRITE_REG(hw, I40E_GLQF_HSYM(info->pctype), reg);
+		I40E_WRITE_FLUSH(hw);
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "PCTYPE[%u] not supported", info->pctype);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* Get the symmetric hash enable configurations per port */
+static void
+i40e_get_symmetric_hash_enable_per_port(struct i40e_hw *hw, uint8_t *enable)
+{
+	uint32_t reg = I40E_READ_REG(hw, I40E_PRTQF_CTL_0);
+
+	*enable = reg & I40E_PRTQF_CTL_0_HSYM_ENA_MASK ? 1 : 0;
+}
+
+/* Set the symmetric hash enable configurations per port */
+static void
+i40e_set_symmetric_hash_enable_per_port(struct i40e_hw *hw, uint8_t enable)
+{
+	uint32_t reg = I40E_READ_REG(hw, I40E_PRTQF_CTL_0);
+
+	if (enable > 0) {
+		if (reg & I40E_PRTQF_CTL_0_HSYM_ENA_MASK) {
+			PMD_DRV_LOG(INFO, "Symmetric hash has already "
+							"been enabled");
+			return;
+		}
+		reg |= I40E_PRTQF_CTL_0_HSYM_ENA_MASK;
+	} else {
+		if (!(reg & I40E_PRTQF_CTL_0_HSYM_ENA_MASK)) {
+			PMD_DRV_LOG(INFO, "Symmetric hash has already "
+							"been disabled");
+			return;
+		}
+		reg &= ~I40E_PRTQF_CTL_0_HSYM_ENA_MASK;
+	}
+	I40E_WRITE_REG(hw, I40E_PRTQF_CTL_0, reg);
+	I40E_WRITE_FLUSH(hw);
+}
+
+/* Get filter swap configurations */
+static int
+i40e_get_filter_swap(struct i40e_hw *hw, struct rte_eth_filter_swap_info *info)
+{
+	uint32_t reg;
+
+	switch (info->pctype) {
+	case ETH_RSS_NONF_IPV4_UDP_SHIFT:
+	case ETH_RSS_NONF_IPV4_TCP_SHIFT:
+	case ETH_RSS_NONF_IPV4_SCTP_SHIFT:
+	case ETH_RSS_NONF_IPV4_OTHER_SHIFT:
+	case ETH_RSS_FRAG_IPV4_SHIFT:
+	case ETH_RSS_NONF_IPV6_UDP_SHIFT:
+	case ETH_RSS_NONF_IPV6_TCP_SHIFT:
+	case ETH_RSS_NONF_IPV6_SCTP_SHIFT:
+	case ETH_RSS_NONF_IPV6_OTHER_SHIFT:
+	case ETH_RSS_FRAG_IPV6_SHIFT:
+	case ETH_RSS_L2_PAYLOAD_SHIFT:
+		reg = I40E_READ_REG(hw, I40E_GLQF_SWAP(0, info->pctype));
+		PMD_DRV_LOG(DEBUG, "Value read from I40E_GLQF_SWAP[0,%d]: "
+						"0x%x", info->pctype, reg);
+
+		/**
+		 * The offset and length read from register in word unit,
+		 * which need to be converted in byte unit before being saved.
+		 */
+		info->off0_src0 =
+			(uint8_t)((reg & I40E_GLQF_SWAP_OFF0_SRC0_MASK) >>
+					I40E_GLQF_SWAP_OFF0_SRC0_SHIFT) << 1;
+		info->off0_src1 =
+			(uint8_t)((reg & I40E_GLQF_SWAP_OFF0_SRC1_MASK) >>
+					I40E_GLQF_SWAP_OFF0_SRC1_SHIFT) << 1;
+		info->len0 = (uint8_t)((reg & I40E_GLQF_SWAP_FLEN0_MASK) >>
+					I40E_GLQF_SWAP_FLEN0_SHIFT) << 1;
+		info->off1_src0 =
+			(uint8_t)((reg & I40E_GLQF_SWAP_OFF1_SRC0_MASK) >>
+					I40E_GLQF_SWAP_OFF1_SRC0_SHIFT) << 1;
+		info->off1_src1 =
+			(uint8_t)((reg & I40E_GLQF_SWAP_OFF1_SRC1_MASK) >>
+					I40E_GLQF_SWAP_OFF1_SRC1_SHIFT) << 1;
+		info->len1 = (uint8_t)((reg & I40E_GLQF_SWAP_FLEN1_MASK) >>
+					I40E_GLQF_SWAP_FLEN1_SHIFT) << 1;
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "PCTYPE[%u] not supported", info->pctype);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* Set filter swap configurations */
+static int
+i40e_set_filter_swap(struct i40e_hw *hw,
+		     const struct rte_eth_filter_swap_info *info)
+{
+#define I40E_FIELD_LEN_MAX 0x1f
+#define I40E_FIELD_OFFSET_MAX 0x7f
+	uint32_t reg;
+
+	switch (info->pctype) {
+	case ETH_RSS_NONF_IPV4_UDP_SHIFT:
+	case ETH_RSS_NONF_IPV4_TCP_SHIFT:
+	case ETH_RSS_NONF_IPV4_SCTP_SHIFT:
+	case ETH_RSS_NONF_IPV4_OTHER_SHIFT:
+	case ETH_RSS_FRAG_IPV4_SHIFT:
+	case ETH_RSS_NONF_IPV6_UDP_SHIFT:
+	case ETH_RSS_NONF_IPV6_TCP_SHIFT:
+	case ETH_RSS_NONF_IPV6_SCTP_SHIFT:
+	case ETH_RSS_NONF_IPV6_OTHER_SHIFT:
+	case ETH_RSS_FRAG_IPV6_SHIFT:
+	case ETH_RSS_L2_PAYLOAD_SHIFT:
+		if (info->off0_src0 > I40E_FIELD_OFFSET_MAX) {
+			PMD_DRV_LOG(ERR, "off0_src0 (0x%x) exceeds the "
+				"maximum of 0x%x", info->off0_src0,
+						I40E_FIELD_OFFSET_MAX);
+			return I40E_ERR_PARAM;
+		} else if (info->off0_src1 > I40E_FIELD_OFFSET_MAX) {
+			PMD_DRV_LOG(ERR, "off0_src1 (0x%x) exceeds the "
+				"maximum of 0x%x", info->off0_src1,
+						I40E_FIELD_OFFSET_MAX);
+			return I40E_ERR_PARAM;
+		} else if (info->len0 > I40E_FIELD_LEN_MAX) {
+			PMD_DRV_LOG(ERR, "len0 (0x%x) exceeds the maximum "
+				"of 0x%x", info->len0, I40E_FIELD_LEN_MAX);
+			return I40E_ERR_PARAM;
+		} else if (info->off1_src0 > I40E_FIELD_OFFSET_MAX) {
+			PMD_DRV_LOG(ERR, "off1_src0 (0x%x) exceeds the "
+				"maximum of 0x%x", info->off1_src0,
+						I40E_FIELD_OFFSET_MAX);
+			return I40E_ERR_PARAM;
+		} else if (info->off1_src1 > I40E_FIELD_OFFSET_MAX) {
+			PMD_DRV_LOG(ERR, "off1_src1 (0x%x) exceeds the "
+				"maximum of 0x%x", info->off1_src1,
+						I40E_FIELD_OFFSET_MAX);
+			return I40E_ERR_PARAM;
+		} else if (info->len1 > I40E_FIELD_LEN_MAX) {
+			PMD_DRV_LOG(ERR, "len1 (0x%x) exceeds the maximum "
+				"of 0x%x", info->len1, I40E_FIELD_LEN_MAX);
+			return I40E_ERR_PARAM;
+		}
+
+		/**
+		 * The offset and length given in byte unit, which need to be
+		 * converted in word unit before being written to the register,
+		 * as hardware requires it in word unit.
+		 */
+		reg = (info->off0_src0 >> 1) << I40E_GLQF_SWAP_OFF0_SRC0_SHIFT;
+		reg |= (info->off0_src1 >> 1) <<
+			I40E_GLQF_SWAP_OFF0_SRC1_SHIFT;
+		reg |= (info->len0 >> 1) << I40E_GLQF_SWAP_FLEN0_SHIFT;
+		reg |= (info->off1_src0 >> 1) <<
+			I40E_GLQF_SWAP_OFF1_SRC0_SHIFT;
+		reg |= (info->off1_src1 >> 1) <<
+			I40E_GLQF_SWAP_OFF1_SRC1_SHIFT;
+		reg |= (info->len1 >> 1) << I40E_GLQF_SWAP_FLEN1_SHIFT;
+
+		PMD_DRV_LOG(DEBUG, "Value to be written to "
+			"I40E_GLQF_SWAP[0,%d]: 0x%x", info->pctype, reg);
+		I40E_WRITE_REG(hw, I40E_GLQF_SWAP(0, info->pctype), reg);
+		I40E_WRITE_FLUSH(hw);
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "PCTYPE[%u] not supported", info->pctype);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* Get hash function type */
+static void
+i40e_get_hash_function(struct i40e_hw *hw, enum rte_eth_hash_function *hf)
+{
+	uint32_t reg = I40E_READ_REG(hw, I40E_GLQF_CTL);
+
+	if (reg & I40E_GLQF_CTL_HTOEP_MASK)
+		*hf = RTE_ETH_HASH_FUNCTION_TOEPLITZ;
+	else
+		*hf = RTE_ETH_HASH_FUNCTION_SIMPLE_XOR;
+
+	PMD_DRV_LOG(INFO, "Hash function is %s",
+		(reg & I40E_GLQF_CTL_HTOEP_MASK) ? "Toeplitz" : "Simple XOR");
+}
+
+/* Set hash function type */
+static int
+i40e_set_hash_function(struct i40e_hw *hw, enum rte_eth_hash_function hf)
+{
+	uint32_t reg = I40E_READ_REG(hw, I40E_GLQF_CTL);
+
+	if (hf == RTE_ETH_HASH_FUNCTION_TOEPLITZ) {
+		if (reg & I40E_GLQF_CTL_HTOEP_MASK) {
+			PMD_DRV_LOG(DEBUG, "Hash function already set to "
+								"Toeplitz");
+			return 0;
+		}
+		reg |= I40E_GLQF_CTL_HTOEP_MASK;
+	} else if (hf == RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) {
+		if (!(reg & I40E_GLQF_CTL_HTOEP_MASK)) {
+			PMD_DRV_LOG(DEBUG, "Hash function already set to "
+							"Simple XOR");
+			return 0;
+		}
+		reg &= ~I40E_GLQF_CTL_HTOEP_MASK;
+	} else {
+		PMD_DRV_LOG(ERR, "Unknown hash function type");
+		return -EINVAL;
+	}
+
+	PMD_DRV_LOG(INFO, "Hash function set to %s",
+		(reg & I40E_GLQF_CTL_HTOEP_MASK) ? "Toeplitz" : "Simple XOR");
+	I40E_WRITE_REG(hw, I40E_GLQF_CTL, reg);
+	I40E_WRITE_FLUSH(hw);
+
+	return 0;
+}
+
+static int
+i40e_hash_filter_get(struct i40e_hw *hw, struct rte_eth_hash_filter_info *info)
+{
+	int ret = 0;
+
+	if (!hw || !info) {
+		PMD_DRV_LOG(ERR, "Invalid pointer");
+		return -EFAULT;
+	}
+
+	switch (info->info_type) {
+	case RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PCTYPE:
+		ret = i40e_get_symmetric_hash_enable_per_pctype(hw,
+					&(info->info.sym_hash_ena));
+		break;
+	case RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PORT:
+		i40e_get_symmetric_hash_enable_per_port(hw,
+					&(info->info.enable));
+		break;
+	case RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP:
+		ret = i40e_get_filter_swap(hw, &(info->info.filter_swap));
+		break;
+	case RTE_ETH_HASH_FILTER_INFO_TYPE_HASH_FUNCTION:
+		i40e_get_hash_function(hw, &(info->info.hash_function));
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "Hash filter info type (%d) not supported",
+							info->info_type);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int
+i40e_hash_filter_set(struct i40e_hw *hw, struct rte_eth_hash_filter_info *info)
+{
+	int ret = 0;
+
+	if (!hw || !info) {
+		PMD_DRV_LOG(ERR, "Invalid pointer");
+		return -EFAULT;
+	}
+
+	switch (info->info_type) {
+	case RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PCTYPE:
+		ret = i40e_set_symmetric_hash_enable_per_pctype(hw,
+					&(info->info.sym_hash_ena));
+		break;
+	case RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PORT:
+		i40e_set_symmetric_hash_enable_per_port(hw, info->info.enable);
+		break;
+	case RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP:
+		ret = i40e_set_filter_swap(hw, &(info->info.filter_swap));
+		break;
+	case RTE_ETH_HASH_FILTER_INFO_TYPE_HASH_FUNCTION:
+		ret = i40e_set_hash_function(hw, info->info.hash_function);
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "Hash filter info type (%d) not supported",
+							info->info_type);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+/* Operations for hash function */
+static int
+i40e_hash_filter_ctrl(struct rte_eth_dev *dev,
+		      enum rte_filter_op filter_op,
+		      void *arg)
+{
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	int ret = 0;
+
+	switch (filter_op) {
+	case RTE_ETH_FILTER_OP_NONE:
+		break;
+	case RTE_ETH_FILTER_OP_GET:
+		ret = i40e_hash_filter_get(hw,
+			(struct rte_eth_hash_filter_info *)arg);
+		break;
+	case RTE_ETH_FILTER_OP_SET:
+		ret = i40e_hash_filter_set(hw,
+			(struct rte_eth_hash_filter_info *)arg);
+		break;
+	default:
+		PMD_DRV_LOG(WARNING, "Filter operation (%d) not supported",
+								filter_op);
+		ret = -ENOTSUP;
+		break;
+	}
+
+	return ret;
+}
+
+static int
+i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
+		     enum rte_filter_type filter_type,
+		     enum rte_filter_op filter_op,
+		     void *arg)
+{
+	int ret = -ENOTSUP;
+
+	switch (filter_type) {
+	case RTE_ETH_FILTER_HASH:
+		ret = i40e_hash_filter_ctrl(dev, filter_op, arg);
+		break;
+	case RTE_ETH_FILTER_FDIR:
+		break;
+	case RTE_ETH_FILTER_TUNNEL:
+		break;
+	default:
+		PMD_DRV_LOG(WARNING, "Filter type (%d) not supported",
+							filter_type);
+		break;
+	}
+
+	return ret;
+}
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v3 5/7] i40e: add hardware initialization
  2014-09-30  6:20 [dpdk-dev] [PATCH v3 0/7] Support configuring hash functions Helin Zhang
                   ` (3 preceding siblings ...)
  2014-09-30  6:20 ` [dpdk-dev] [PATCH v3 4/7] i40e: add hash filter control implementation Helin Zhang
@ 2014-09-30  6:20 ` Helin Zhang
  2014-09-30  6:20 ` [dpdk-dev] [PATCH v3 6/7] i40e: Use constant random hash keys Helin Zhang
  2014-09-30  6:20 ` [dpdk-dev] [PATCH v3 7/7] app/testpmd: add commands to support hash filter control Helin Zhang
  6 siblings, 0 replies; 71+ messages in thread
From: Helin Zhang @ 2014-09-30  6:20 UTC (permalink / raw)
  To: dev

As global registers will be reset only after a whole chip reset,
those registers might not be in an initial state after each
launching a physical port. The hardware initialization is added
to put specific global registers into an initial state.

v3 changes:
* Renamed hardware initialization function.
* Added initialization of register 'PFQF_CTL_0'.

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
Acked-by: Jingjing Wu <jingjing.wu@intel.com>
---
 lib/librte_pmd_i40e/i40e_ethdev.c | 78 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 78 insertions(+)

diff --git a/lib/librte_pmd_i40e/i40e_ethdev.c b/lib/librte_pmd_i40e/i40e_ethdev.c
index ee7c9de..f23e0bf 100644
--- a/lib/librte_pmd_i40e/i40e_ethdev.c
+++ b/lib/librte_pmd_i40e/i40e_ethdev.c
@@ -209,6 +209,7 @@ static int i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
 				enum rte_filter_type filter_type,
 				enum rte_filter_op filter_op,
 				void *arg);
+static void i40e_hw_init(struct i40e_hw *hw);
 
 /* Default hash key buffer for RSS */
 static uint32_t rss_key_default[I40E_PFQF_HKEY_MAX_INDEX + 1];
@@ -390,6 +391,9 @@ eth_i40e_dev_init(__rte_unused struct eth_driver *eth_drv,
 	/* Make sure all is clean before doing PF reset */
 	i40e_clear_hw(hw);
 
+	/* Initialize the hardware */
+	i40e_hw_init(hw);
+
 	/* Reset here to make sure all is clean for each PF */
 	ret = i40e_pf_reset(hw);
 	if (ret) {
@@ -4533,3 +4537,77 @@ i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
 
 	return ret;
 }
+
+/* Initialization for hash function */
+static void
+i40e_hash_function_hw_init(struct i40e_hw *hw)
+{
+	uint32_t i;
+	const struct rte_eth_sym_hash_ena_info sym_hash_ena_info[] = {
+		{ETH_RSS_NONF_IPV4_UDP_SHIFT, 0},
+		{ETH_RSS_NONF_IPV4_TCP_SHIFT, 0},
+		{ETH_RSS_NONF_IPV4_SCTP_SHIFT, 0},
+		{ETH_RSS_NONF_IPV4_OTHER_SHIFT, 0},
+		{ETH_RSS_FRAG_IPV4_SHIFT, 0},
+		{ETH_RSS_NONF_IPV6_UDP_SHIFT, 0},
+		{ETH_RSS_NONF_IPV6_TCP_SHIFT, 0},
+		{ETH_RSS_NONF_IPV6_SCTP_SHIFT, 0},
+		{ETH_RSS_NONF_IPV6_OTHER_SHIFT, 0},
+		{ETH_RSS_FRAG_IPV6_SHIFT, 0},
+		{ETH_RSS_L2_PAYLOAD_SHIFT, 0},
+	};
+	const struct rte_eth_filter_swap_info swap_info[] = {
+		{ETH_RSS_NONF_IPV4_UDP_SHIFT,
+			0x1e, 0x36, 0x04, 0x3a, 0x3c, 0x02},
+		{ETH_RSS_NONF_IPV4_TCP_SHIFT,
+			0x1e, 0x36, 0x04, 0x3a, 0x3c, 0x02},
+		{ETH_RSS_NONF_IPV4_SCTP_SHIFT,
+			0x1e, 0x36, 0x04, 0x00, 0x00, 0x00},
+		{ETH_RSS_NONF_IPV4_OTHER_SHIFT,
+			0x1e, 0x36, 0x04, 0x00, 0x00, 0x00},
+		{ETH_RSS_FRAG_IPV4_SHIFT,
+			0x1e, 0x36, 0x04, 0x00, 0x00, 0x00},
+		{ETH_RSS_NONF_IPV6_UDP_SHIFT,
+			0x1a, 0x2a, 0x10, 0x3a, 0x3c, 0x02},
+		{ETH_RSS_NONF_IPV6_TCP_SHIFT,
+			0x1a, 0x2a, 0x10, 0x3a, 0x3c, 0x02},
+		{ETH_RSS_NONF_IPV6_SCTP_SHIFT,
+			0x1a, 0x2a, 0x10, 0x00, 0x00, 0x00},
+		{ETH_RSS_NONF_IPV6_OTHER_SHIFT,
+			0x1a, 0x2a, 0x10, 0x00, 0x00, 0x00},
+		{ETH_RSS_FRAG_IPV6_SHIFT,
+			0x1a, 0x2a, 0x10, 0x00, 0x00, 0x00},
+		{ETH_RSS_L2_PAYLOAD_SHIFT,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+	};
+
+	/* Disable symmetric hash per PCTYPE */
+	for (i = 0; i < RTE_DIM(sym_hash_ena_info); i++)
+		i40e_set_symmetric_hash_enable_per_pctype(hw,
+					&sym_hash_ena_info[i]);
+
+	/* Disable symmetric hash per port */
+	i40e_set_symmetric_hash_enable_per_port(hw, 0);
+
+	/* Initialize filter swap */
+	for (i = 0; i < RTE_DIM(swap_info); i++)
+		i40e_set_filter_swap(hw, &swap_info[i]);
+
+	/* Set hash function to Toeplitz by default */
+	i40e_set_hash_function(hw, RTE_ETH_HASH_FUNCTION_TOEPLITZ);
+}
+
+/*
+ * As global registers wouldn't be reset unless a global hardware reset,
+ * hardware initialization is needed to put those registers into an
+ * expected initial state.
+ */
+static void
+i40e_hw_init(struct i40e_hw *hw)
+{
+	/* clear the PF Queue Filter control register */
+	I40E_WRITE_REG(hw, I40E_PFQF_CTL_0, 0);
+
+	/* Initialize hardware for hash function */
+	i40e_hash_function_hw_init(hw);
+}
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v3 6/7] i40e: Use constant random hash keys
  2014-09-30  6:20 [dpdk-dev] [PATCH v3 0/7] Support configuring hash functions Helin Zhang
                   ` (4 preceding siblings ...)
  2014-09-30  6:20 ` [dpdk-dev] [PATCH v3 5/7] i40e: add hardware initialization Helin Zhang
@ 2014-09-30  6:20 ` Helin Zhang
  2014-09-30  6:20 ` [dpdk-dev] [PATCH v3 7/7] app/testpmd: add commands to support hash filter control Helin Zhang
  6 siblings, 0 replies; 71+ messages in thread
From: Helin Zhang @ 2014-09-30  6:20 UTC (permalink / raw)
  To: dev

To be simpler, and remove the race condition, it uses prepared
constant random hash keys to replace runtime generating the
hash keys.

v3 changes:
* Use prepared random hash keys.

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
Acked-by: Jingjing Wu <jingjing.wu@intel.com>
---
 lib/librte_pmd_i40e/i40e_ethdev.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/lib/librte_pmd_i40e/i40e_ethdev.c b/lib/librte_pmd_i40e/i40e_ethdev.c
index f23e0bf..87a5f4d 100644
--- a/lib/librte_pmd_i40e/i40e_ethdev.c
+++ b/lib/librte_pmd_i40e/i40e_ethdev.c
@@ -211,9 +211,6 @@ static int i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
 				void *arg);
 static void i40e_hw_init(struct i40e_hw *hw);
 
-/* Default hash key buffer for RSS */
-static uint32_t rss_key_default[I40E_PFQF_HKEY_MAX_INDEX + 1];
-
 static struct rte_pci_id pci_id_i40e_map[] = {
 #define RTE_PCI_DEV_ID_DECL_I40E(vend, dev) {RTE_PCI_DEVICE(vend, dev)},
 #include "rte_pci_dev_ids.h"
@@ -4113,9 +4110,12 @@ i40e_pf_config_rss(struct i40e_pf *pf)
 	}
 	if (rss_conf.rss_key == NULL || rss_conf.rss_key_len <
 		(I40E_PFQF_HKEY_MAX_INDEX + 1) * sizeof(uint32_t)) {
-		/* Calculate the default hash key */
-		for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++)
-			rss_key_default[i] = (uint32_t)rte_rand();
+		/* Random default keys */
+		static uint32_t rss_key_default[] = {0x6b793944,
+			0x23504cb5, 0x5bea75b6, 0x309f4f12, 0x3dc0a2b8,
+			0x024ddcdf, 0x339b8ca0, 0x4c4af64a, 0x34fac605,
+			0x55d85839, 0x3a58997d, 0x2ec938e1, 0x66031581};
+
 		rss_conf.rss_key = (uint8_t *)rss_key_default;
 		rss_conf.rss_key_len = (I40E_PFQF_HKEY_MAX_INDEX + 1) *
 							sizeof(uint32_t);
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v3 7/7] app/testpmd: add commands to support hash filter control
  2014-09-30  6:20 [dpdk-dev] [PATCH v3 0/7] Support configuring hash functions Helin Zhang
                   ` (5 preceding siblings ...)
  2014-09-30  6:20 ` [dpdk-dev] [PATCH v3 6/7] i40e: Use constant random hash keys Helin Zhang
@ 2014-09-30  6:20 ` Helin Zhang
  6 siblings, 0 replies; 71+ messages in thread
From: Helin Zhang @ 2014-09-30  6:20 UTC (permalink / raw)
  To: dev

To demonstrate the hash filter control, commands are added.
They are
- get_sym_hash_ena_per_port
- set_sym_hash_ena_per_port
- get_sym_hash_ena_per_pctype
- set_sym_hash_ena_per_pctype
- get_filter_swap
- set_filter_swap
- get_hash_function
- set_hash_function

v3 changes:
* Renamed the command names.
* Used the re-designed filter control APIs and structures.

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
Acked-by: Jingjing Wu <jingjing.wu@intel.com>
---
 app/test-pmd/cmdline.c | 565 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 565 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 225f669..c8c0bcd 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -74,6 +74,7 @@
 #include <rte_ethdev.h>
 #include <rte_string_fns.h>
 #include <rte_devargs.h>
+#include <rte_eth_ctrl.h>
 
 #include <cmdline_rdline.h>
 #include <cmdline_parse.h>
@@ -660,6 +661,35 @@ static void cmd_help_long_parsed(void *parsed_result,
 
 			"get_flex_filter (port_id) index (idx)\n"
 			"    get info of a flex filter.\n\n"
+
+			"get_sym_hash_ena_per_port (port_id)\n"
+			"    get symmetric hash enable configuration per port.\n\n"
+
+			"set_sym_hash_ena_per_port (port_id)"
+			" (enable|disable)\n"
+			"    set symmetric hash enable configuration per port"
+			" to enable or disable.\n\n"
+
+			"get_sym_hash_ena_per_pctype (port_id) (pctype)\n"
+			"    get symmetric hash enable configuration per port\n\n"
+
+			"set_sym_hash_ena_per_pctype (port_id) (pctype)"
+			" (enable|disable)\n"
+			"    set symmetric hash enable configuration per"
+			" pctype to enable or disable.\n\n"
+
+			"get_filter_swap (port_id) (pctype)\n"
+			"    get filter swap configurations.\n\n"
+
+			"set_filter_swap (port_id) (pctype) (off0_src0) (off0_src1)"
+			" (len0) (off1_src0) (off1_src1) (len1)\n"
+			"    set filter swap configurations.\n\n"
+
+			"get_hash_function (port_id)\n"
+			"    get hash function of Toeplitz or Simple XOR.\n\n"
+
+			"set_hash_function (port_id) (toeplitz|simple_xor)\n"
+			"    set the hash function to Toeplitz or Simple XOR.\n\n"
 		);
 	}
 }
@@ -7411,6 +7441,533 @@ cmdline_parse_inst_t cmd_get_flex_filter = {
 	},
 };
 
+/* *** Classification Filters Control *** */
+
+/* *** Get symmetric hash enable per port *** */
+struct cmd_get_sym_hash_ena_per_port_result {
+	cmdline_fixed_string_t get_sym_hash_ena_per_port;
+	uint8_t port_id;
+};
+
+static void
+cmd_get_sym_hash_per_port_parsed(void *parsed_result,
+				 __rte_unused struct cmdline *cl,
+				 __rte_unused void *data)
+{
+	struct cmd_get_sym_hash_ena_per_port_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port: %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PORT;
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+					RTE_ETH_FILTER_OP_GET, &info);
+	if (ret < 0) {
+		printf("Cannot get symmetric hash enable per port "
+					"on port %u\n", res->port_id);
+		return;
+	}
+
+	printf("Symmetric hash is %s on port %u\n", info.info.enable ?
+				"enabled" : "disabled", res->port_id);
+}
+
+cmdline_parse_token_string_t cmd_get_sym_hash_ena_per_port_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_get_sym_hash_ena_per_port_result,
+		get_sym_hash_ena_per_port, "get_sym_hash_ena_per_port");
+cmdline_parse_token_num_t cmd_get_sym_hash_ena_per_port_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_get_sym_hash_ena_per_port_result,
+		port_id, UINT8);
+
+cmdline_parse_inst_t cmd_get_sym_hash_ena_per_port = {
+	.f = cmd_get_sym_hash_per_port_parsed,
+	.data = NULL,
+	.help_str = "get_sym_hash_ena_per_port port_id",
+	.tokens = {
+		(void *)&cmd_get_sym_hash_ena_per_port_all,
+		(void *)&cmd_get_sym_hash_ena_per_port_port_id,
+		NULL,
+	},
+};
+
+/* *** Set symmetric hash enable per port *** */
+struct cmd_set_sym_hash_ena_per_port_result {
+	cmdline_fixed_string_t set_sym_hash_ena_per_port;
+	cmdline_fixed_string_t enable;
+	uint8_t port_id;
+};
+
+static void
+cmd_set_sym_hash_per_port_parsed(void *parsed_result,
+				 __rte_unused struct cmdline *cl,
+				 __rte_unused void *data)
+{
+	struct cmd_set_sym_hash_ena_per_port_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port: %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	if (!strcmp(res->enable, "enable"))
+		info.info.enable = 1;
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+					RTE_ETH_FILTER_OP_SET, &info);
+	if (ret < 0) {
+		printf("Cannot set symmetric hash enable per port on "
+					"port %u\n", res->port_id);
+		return;
+	}
+
+	printf("Symmetric hash has been set to %s on port %u\n",
+					res->enable, res->port_id);
+}
+
+cmdline_parse_token_string_t cmd_set_sym_hash_ena_per_port_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_sym_hash_ena_per_port_result,
+		set_sym_hash_ena_per_port, "set_sym_hash_ena_per_port");
+cmdline_parse_token_num_t cmd_set_sym_hash_ena_per_port_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_sym_hash_ena_per_port_result,
+		port_id, UINT8);
+cmdline_parse_token_string_t cmd_set_sym_hash_ena_per_port_enable =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_sym_hash_ena_per_port_result,
+		enable, "enable#disable");
+
+cmdline_parse_inst_t cmd_set_sym_hash_ena_per_port = {
+	.f = cmd_set_sym_hash_per_port_parsed,
+	.data = NULL,
+	.help_str = "set_sym_hash_ena_per_port port_id enable|disable",
+	.tokens = {
+		(void *)&cmd_set_sym_hash_ena_per_port_all,
+		(void *)&cmd_set_sym_hash_ena_per_port_port_id,
+		(void *)&cmd_set_sym_hash_ena_per_port_enable,
+		NULL,
+	},
+};
+
+/* *** Get symmetric hash enable per pctype *** */
+struct cmd_get_sym_hash_ena_per_pctype_result {
+	cmdline_fixed_string_t get_sym_hash_ena_per_pctype;
+	uint8_t port_id;
+	uint8_t pctype;
+};
+
+static void
+cmd_get_sym_hash_per_pctype_parsed(void *parsed_result,
+				   __rte_unused struct cmdline *cl,
+				   __rte_unused void *data)
+{
+	struct cmd_get_sym_hash_ena_per_pctype_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port: %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PCTYPE;
+	info.info.sym_hash_ena.pctype = res->pctype;
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+					RTE_ETH_FILTER_OP_GET, &info);
+	if (ret < 0) {
+		printf("Cannot get symmetric hash enable per pctype on "
+			"port %u, pctype %u\n", res->port_id, res->pctype);
+		return;
+	}
+	printf("Symmetric hash is %s on port %u, pctype %u\n",
+			info.info.sym_hash_ena.enable ? "enabled" :
+			"disabled", res->port_id, res->pctype);
+}
+
+cmdline_parse_token_string_t cmd_get_sym_hash_ena_per_pctype_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_get_sym_hash_ena_per_pctype_result,
+		get_sym_hash_ena_per_pctype, "get_sym_hash_ena_per_pctype");
+cmdline_parse_token_num_t cmd_get_sym_hash_ena_per_pctype_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_get_sym_hash_ena_per_pctype_result,
+		port_id, UINT8);
+cmdline_parse_token_num_t cmd_get_sym_hash_ena_per_pctype_pctype =
+	TOKEN_NUM_INITIALIZER(struct cmd_get_sym_hash_ena_per_pctype_result,
+		pctype, UINT8);
+
+cmdline_parse_inst_t cmd_get_sym_hash_ena_per_pctype = {
+	.f = cmd_get_sym_hash_per_pctype_parsed,
+	.data = NULL,
+	.help_str = "get_sym_hash_ena_per_pctype port_id pctype",
+	.tokens = {
+		(void *)&cmd_get_sym_hash_ena_per_pctype_all,
+		(void *)&cmd_get_sym_hash_ena_per_pctype_port_id,
+		(void *)&cmd_get_sym_hash_ena_per_pctype_pctype,
+		NULL,
+	},
+};
+
+/* *** Set symmetric hash enable per pctype *** */
+struct cmd_set_sym_hash_ena_per_pctype_result {
+	cmdline_fixed_string_t set_sym_hash_ena_per_pctype;
+	cmdline_fixed_string_t enable;
+	uint8_t port_id;
+	uint8_t pctype;
+};
+
+static void
+cmd_set_sym_hash_per_pctype_parsed(void *parsed_result,
+				   __rte_unused struct cmdline *cl,
+				   __rte_unused void *data)
+{
+	struct cmd_set_sym_hash_ena_per_pctype_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port: %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PCTYPE;
+	info.info.sym_hash_ena.pctype = res->pctype;
+	if (!strcmp(res->enable, "enable"))
+		info.info.sym_hash_ena.enable = 1;
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+					RTE_ETH_FILTER_OP_SET, &info);
+	if (ret < 0) {
+		printf("Cannot set symmetric hash enable per pctype to %s "
+			"on port %u, pctype %u\n", res->enable ? "enabled" :
+				"disabled", res->port_id, res->pctype);
+		return;
+	}
+	printf("Symmetic hash has been set to %s on port %u, pctype %u\n",
+				res->enable, res->port_id, res->pctype);
+}
+
+cmdline_parse_token_string_t cmd_set_sym_hash_ena_per_pctype_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_sym_hash_ena_per_pctype_result,
+		set_sym_hash_ena_per_pctype, "set_sym_hash_ena_per_pctype");
+cmdline_parse_token_num_t cmd_set_sym_hash_ena_per_pctype_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_sym_hash_ena_per_pctype_result,
+		port_id, UINT8);
+cmdline_parse_token_num_t cmd_set_sym_hash_ena_per_pctype_pctype =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_sym_hash_ena_per_pctype_result,
+		pctype, UINT8);
+cmdline_parse_token_string_t cmd_set_sym_hash_ena_per_pctype_enable =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_sym_hash_ena_per_pctype_result,
+		enable, "enable#disable");
+
+cmdline_parse_inst_t cmd_set_sym_hash_ena_per_pctype = {
+	.f = cmd_set_sym_hash_per_pctype_parsed,
+	.data = NULL,
+	.help_str = "set_sym_hash_ena_per_pctype pord_id pctype "
+						"enable|disable",
+	.tokens = {
+		(void *)&cmd_set_sym_hash_ena_per_pctype_all,
+		(void *)&cmd_set_sym_hash_ena_per_pctype_port_id,
+		(void *)&cmd_set_sym_hash_ena_per_pctype_pctype,
+		(void *)&cmd_set_sym_hash_ena_per_pctype_enable,
+		NULL,
+	},
+};
+
+/* *** Get filter swap *** */
+struct cmd_get_filter_swap_result {
+	cmdline_fixed_string_t get_filter_swap;
+	uint8_t port_id;
+	uint8_t pctype;
+};
+
+static void
+cmd_get_filter_swap_parsed(void *parsed_result,
+			   __rte_unused struct cmdline *cl,
+			   __rte_unused void *data)
+{
+	struct cmd_get_filter_swap_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port: %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP;
+	info.info.filter_swap.pctype = res->pctype;
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+					RTE_ETH_FILTER_OP_GET, &info);
+	if (ret < 0) {
+		printf("Cannot get filter swap on port %u, pctype %u\n",
+						res->port_id, res->pctype);
+		return;
+	}
+	printf("Filter swap of port %u, pctype %u is configured as:\n"
+		"off0_src0: 0x%02x, off0_src1: 0x%02x, len0: 0x%02x\n"
+		"off1_src0: 0x%02x, off1_src1: 0x%02x, len1: 0x%02x\n",
+		res->port_id, res->pctype, info.info.filter_swap.off0_src0,
+		info.info.filter_swap.off0_src1, info.info.filter_swap.len0,
+		info.info.filter_swap.off1_src0,
+		info.info.filter_swap.off1_src1, info.info.filter_swap.len1);
+}
+
+cmdline_parse_token_string_t cmd_get_filter_swap_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_get_filter_swap_result,
+		get_filter_swap, "get_filter_swap");
+cmdline_parse_token_num_t cmd_get_filter_swap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_get_filter_swap_result,
+		port_id, UINT8);
+cmdline_parse_token_num_t cmd_get_filter_swap_pctype =
+	TOKEN_NUM_INITIALIZER(struct cmd_get_filter_swap_result,
+		pctype, UINT8);
+
+cmdline_parse_inst_t cmd_get_filter_swap = {
+	.f = cmd_get_filter_swap_parsed,
+	.data = NULL,
+	.help_str = "get_filter_swap port_id pctype",
+	.tokens = {
+		(void *)&cmd_get_filter_swap_all,
+		(void *)&cmd_get_filter_swap_port_id,
+		(void *)&cmd_get_filter_swap_pctype,
+		NULL,
+	},
+};
+
+/* *** Set filter swap *** */
+struct cmd_set_filter_swap_result {
+	cmdline_fixed_string_t set_filter_swap;
+	uint8_t port_id;
+	uint8_t pctype;
+	uint8_t off0_src0;
+	uint8_t off0_src1;
+	uint8_t len0;
+	uint8_t off1_src0;
+	uint8_t off1_src1;
+	uint8_t len1;
+};
+
+static void
+cmd_set_filter_swap_parsed(void *parsed_result,
+			   __rte_unused struct cmdline *cl,
+			   __rte_unused void *data)
+{
+	struct cmd_set_filter_swap_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port: %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP;
+	info.info.filter_swap.pctype = res->pctype;
+	info.info.filter_swap.off0_src0 = res->off0_src0;
+	info.info.filter_swap.off0_src1 = res->off0_src1;
+	info.info.filter_swap.len0 = res->len0;
+	info.info.filter_swap.off1_src0 = res->off1_src0;
+	info.info.filter_swap.off1_src1 = res->off1_src1;
+	info.info.filter_swap.len1 = res->len1;
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+					RTE_ETH_FILTER_OP_SET, &info);
+	if (ret < 0) {
+		printf("Cannot set filter swap on port %u, pctype %u\n",
+						res->port_id, res->pctype);
+		return;
+	}
+	printf("Filter swap of port %u, pctype %u has been set as:\n"
+		"off0_src0: 0x%02x, off0_src1: 0x%02x, len0: 0x%02x\n"
+		"off1_src0: 0x%02x, off1_src1: 0x%02x, len1: 0x%02x\n",
+		res->port_id, res->pctype, info.info.filter_swap.off0_src0,
+		info.info.filter_swap.off0_src1, info.info.filter_swap.len0,
+		info.info.filter_swap.off1_src0,
+		info.info.filter_swap.off1_src1, info.info.filter_swap.len1);
+}
+
+cmdline_parse_token_string_t cmd_set_filter_swap_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_filter_swap_result,
+		set_filter_swap, "set_filter_swap");
+cmdline_parse_token_num_t cmd_set_filter_swap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_filter_swap_result,
+		port_id, UINT8);
+cmdline_parse_token_num_t cmd_set_filter_swap_pctype =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_filter_swap_result,
+		pctype, UINT8);
+cmdline_parse_token_num_t cmd_set_filter_swap_off0_src0 =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_filter_swap_result,
+		off0_src0, UINT8);
+cmdline_parse_token_num_t cmd_set_filter_swap_off0_src1 =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_filter_swap_result,
+		off0_src1, UINT8);
+cmdline_parse_token_num_t cmd_set_filter_swap_len0 =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_filter_swap_result,
+		len0, UINT8);
+cmdline_parse_token_num_t cmd_set_filter_swap_off1_src0 =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_filter_swap_result,
+		off1_src0, UINT8);
+cmdline_parse_token_num_t cmd_set_filter_swap_off1_src1 =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_filter_swap_result,
+		off1_src1, UINT8);
+cmdline_parse_token_num_t cmd_set_filter_swap_len1 =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_filter_swap_result,
+		len1, UINT8);
+
+cmdline_parse_inst_t cmd_set_filter_swap = {
+	.f = cmd_set_filter_swap_parsed,
+	.data = NULL,
+	.help_str = "set_filter_swap port_id pctype off0_src0 off0_src1 "
+					"len0 off1_src0 off1_src1 len1",
+	.tokens = {
+		(void *)&cmd_set_filter_swap_all,
+		(void *)&cmd_set_filter_swap_port_id,
+		(void *)&cmd_set_filter_swap_pctype,
+		(void *)&cmd_set_filter_swap_off0_src0,
+		(void *)&cmd_set_filter_swap_off0_src1,
+		(void *)&cmd_set_filter_swap_len0,
+		(void *)&cmd_set_filter_swap_off1_src0,
+		(void *)&cmd_set_filter_swap_off1_src1,
+		(void *)&cmd_set_filter_swap_len1,
+		NULL,
+	},
+};
+
+/* Get hash function */
+struct cmd_get_hash_function_result {
+	cmdline_fixed_string_t get_hash_function;
+	uint8_t port_id;
+};
+
+static void
+cmd_get_hash_function_parsed(void *parsed_result,
+			     __rte_unused struct cmdline *cl,
+			     __rte_unused void *data)
+{
+	struct cmd_get_hash_function_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_INFO_TYPE_HASH_FUNCTION;
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+					RTE_ETH_FILTER_OP_GET, &info);
+	if (ret < 0) {
+		printf("Cannot get hash function on port %d\n", res->port_id);
+		return;
+	}
+	printf("Hash function is %s\n", info.info.hash_function ==
+		RTE_ETH_HASH_FUNCTION_TOEPLITZ ? "Toeplitz" : "Simple XOR");
+}
+
+cmdline_parse_token_string_t cmd_get_hash_function_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_get_hash_function_result,
+		get_hash_function, "get_hash_function");
+cmdline_parse_token_num_t cmd_get_hash_function_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_get_hash_function_result,
+		port_id, UINT8);
+
+cmdline_parse_inst_t cmd_get_hash_function = {
+	.f = cmd_get_hash_function_parsed,
+	.data = NULL,
+	.help_str = "get_hash_function port_id",
+	.tokens = {
+		(void *)&cmd_get_hash_function_all,
+		(void *)&cmd_get_hash_function_port_id,
+		NULL,
+	},
+};
+
+/* Set hash function of Hoeplitz or Simple XOR */
+struct cmd_set_hash_function_result {
+	cmdline_fixed_string_t set_hash_function;
+	uint8_t port_id;
+	cmdline_fixed_string_t hash_function;
+};
+
+static void
+cmd_set_hash_function_parsed(void *parsed_result,
+			     __rte_unused struct cmdline *cl,
+			     __rte_unused void *data)
+{
+	struct cmd_set_hash_function_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_INFO_TYPE_HASH_FUNCTION;
+	if (!strcmp(res->hash_function, "toeplitz"))
+		info.info.hash_function = RTE_ETH_HASH_FUNCTION_TOEPLITZ;
+	else if (!strcmp(res->hash_function, "simple_xor"))
+		info.info.hash_function = RTE_ETH_HASH_FUNCTION_SIMPLE_XOR;
+	else {
+		printf("Unsupported hash function %s\n", res->hash_function);
+		return;
+	}
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+					RTE_ETH_FILTER_OP_SET, &info);
+	if (ret < 0) {
+		printf("Cannot set hash function to %s on port %d\n",
+				res->hash_function, res->port_id);
+		return;
+	}
+	printf("Hash function has been successfully set to %s on port %d\n",
+					res->hash_function, res->port_id);
+}
+
+cmdline_parse_token_string_t cmd_set_hash_function_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_hash_function_result,
+		set_hash_function, "set_hash_function");
+cmdline_parse_token_num_t cmd_set_hash_function_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_hash_function_result,
+		port_id, UINT8);
+cmdline_parse_token_string_t cmd_set_hash_function_hash_function =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_hash_function_result,
+		hash_function, "toeplitz#simple_xor");
+
+cmdline_parse_inst_t cmd_set_hash_function = {
+	.f = cmd_set_hash_function_parsed,
+	.data = NULL,
+	.help_str = "set_hash_function port_id toeplitz|simple_xor",
+	.tokens = {
+		(void *)&cmd_set_hash_function_all,
+		(void *)&cmd_set_hash_function_port_id,
+		(void *)&cmd_set_hash_function_hash_function,
+		NULL,
+	},
+};
+
 /* ******************************************************************************** */
 
 /* list of instructions */
@@ -7537,6 +8094,14 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_add_flex_filter,
 	(cmdline_parse_inst_t *)&cmd_remove_flex_filter,
 	(cmdline_parse_inst_t *)&cmd_get_flex_filter,
+	(cmdline_parse_inst_t *)&cmd_get_sym_hash_ena_per_port,
+	(cmdline_parse_inst_t *)&cmd_set_sym_hash_ena_per_port,
+	(cmdline_parse_inst_t *)&cmd_get_sym_hash_ena_per_pctype,
+	(cmdline_parse_inst_t *)&cmd_set_sym_hash_ena_per_pctype,
+	(cmdline_parse_inst_t *)&cmd_get_filter_swap,
+	(cmdline_parse_inst_t *)&cmd_set_filter_swap,
+	(cmdline_parse_inst_t *)&cmd_set_hash_function,
+	(cmdline_parse_inst_t *)&cmd_get_hash_function,
 	NULL,
 };
 
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v4 0/7] Support configuring hash functions
  2014-09-30  6:20 ` [dpdk-dev] [PATCH v3 1/7] ethdev: add more annotations Helin Zhang
@ 2014-10-13  6:12   ` Helin Zhang
  2014-10-13  6:12     ` [dpdk-dev] [PATCH v4 1/7] ethdev: add more annotations Helin Zhang
                       ` (9 more replies)
  0 siblings, 10 replies; 71+ messages in thread
From: Helin Zhang @ 2014-10-13  6:12 UTC (permalink / raw)
  To: dev

These patches mainly support configuring hash functions.
In detail,
 - It can get or set hash functions.
 - It can configure symmetric hash functions.
   * Get/set symmetric hash enable per port.
   * Get/set symmetric hash enable per 'PCTYPE'.
   * Get/set filter swap configurations.
 - 'ethdev' level interfaces are added.
   * 'rte_eth_dev_filter_supported', to check if a filter control
     is supported on a port.
   * 'rte_eth_dev_filter_ctrl', a common API to execute
     specific filter control.
 - Six commands have been implemented in testpmd to support
   testing above.
   * get_sym_hash_ena_per_port
   * set_sym_hash_ena_per_port
   * get_sym_hash_ena_per_pctype
   * set_sym_hash_ena_per_pctype
   * get_filter_swap
   * set_filter_swap
   * get_hash_function
   * set_hash_function

Note that 'PCTYPE' means 'Packet Classification Type'.

v4 changes:
* Fixed a bug in testpmd to support 'set_sym_hash_ena_per_port'.

Helin Zhang (7):
  ethdev: add more annotations
  ethdev: add interfaces and relevant for filter control
  ethdev: add structures and enum for hash filter control
  i40e: add hash filter control implementation
  i40e: add hardware initialization
  i40e: Use constant random hash keys
  app/testpmd: add commands to support hash filter control

 app/test-pmd/cmdline.c            | 566 ++++++++++++++++++++++++++++++++++++++
 lib/librte_ether/Makefile         |   1 +
 lib/librte_ether/rte_eth_ctrl.h   | 154 +++++++++++
 lib/librte_ether/rte_ethdev.c     |  32 +++
 lib/librte_ether/rte_ethdev.h     |  53 +++-
 lib/librte_pmd_i40e/i40e_ethdev.c | 492 ++++++++++++++++++++++++++++++++-
 6 files changed, 1291 insertions(+), 7 deletions(-)
 create mode 100644 lib/librte_ether/rte_eth_ctrl.h

-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v4 1/7] ethdev: add more annotations
  2014-10-13  6:12   ` [dpdk-dev] [PATCH v4 0/7] Support configuring hash functions Helin Zhang
@ 2014-10-13  6:12     ` Helin Zhang
  2014-10-13  6:12     ` [dpdk-dev] [PATCH v4 2/7] ethdev: add interfaces and relevant for filter control Helin Zhang
                       ` (8 subsequent siblings)
  9 siblings, 0 replies; 71+ messages in thread
From: Helin Zhang @ 2014-10-13  6:12 UTC (permalink / raw)
  To: dev

Add more annotations about packet classification type.

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
---
 lib/librte_ether/rte_ethdev.h | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 13be711..1948594 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -334,7 +334,10 @@ struct rte_eth_rss_conf {
 	uint64_t rss_hf;     /**< Hash functions to apply - see below. */
 };
 
-/* Supported RSS offloads */
+/*
+ * Supported RSS offloads, below '_SHIFT' can also be used to represent
+ * the 'Packet Classification type (pctype)'.
+ */
 /* for 1G & 10G */
 #define ETH_RSS_IPV4_SHIFT                    0
 #define ETH_RSS_IPV4_TCP_SHIFT                1
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v4 2/7] ethdev: add interfaces and relevant for filter control
  2014-10-13  6:12   ` [dpdk-dev] [PATCH v4 0/7] Support configuring hash functions Helin Zhang
  2014-10-13  6:12     ` [dpdk-dev] [PATCH v4 1/7] ethdev: add more annotations Helin Zhang
@ 2014-10-13  6:12     ` Helin Zhang
  2014-10-13  6:12     ` [dpdk-dev] [PATCH v4 3/7] ethdev: add structures and enum for hash " Helin Zhang
                       ` (7 subsequent siblings)
  9 siblings, 0 replies; 71+ messages in thread
From: Helin Zhang @ 2014-10-13  6:12 UTC (permalink / raw)
  To: dev

To support flexible filter control, 'rte_eth_dev_filter_ctrl()'
and 'rte_eth_dev_filter_supported()' are added. In addition, filter
types and operations are defined in a newly added header file.

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
---
 lib/librte_ether/Makefile       |  1 +
 lib/librte_ether/rte_eth_ctrl.h | 80 +++++++++++++++++++++++++++++++++++++++++
 lib/librte_ether/rte_ethdev.c   | 32 +++++++++++++++++
 lib/librte_ether/rte_ethdev.h   | 48 +++++++++++++++++++++++++
 4 files changed, 161 insertions(+)
 create mode 100644 lib/librte_ether/rte_eth_ctrl.h

diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
index b310f8b..a461c31 100644
--- a/lib/librte_ether/Makefile
+++ b/lib/librte_ether/Makefile
@@ -46,6 +46,7 @@ SRCS-y += rte_ethdev.c
 #
 SYMLINK-y-include += rte_ether.h
 SYMLINK-y-include += rte_ethdev.h
+SYMLINK-y-include += rte_eth_ctrl.h
 
 # this lib depends upon:
 DEPDIRS-y += lib/librte_eal lib/librte_mempool lib/librte_ring lib/librte_mbuf
diff --git a/lib/librte_ether/rte_eth_ctrl.h b/lib/librte_ether/rte_eth_ctrl.h
new file mode 100644
index 0000000..aaea075
--- /dev/null
+++ b/lib/librte_ether/rte_eth_ctrl.h
@@ -0,0 +1,80 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RTE_ETH_CTRL_H_
+#define _RTE_ETH_CTRL_H_
+
+/**
+ * @file
+ *
+ * Ethernet device features and related data structures used
+ * by control APIs should be defined in this file.
+ *
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Feature filter types
+ */
+enum rte_filter_type {
+	RTE_ETH_FILTER_NONE = 0,
+	RTE_ETH_FILTER_HASH,
+	RTE_ETH_FILTER_FDIR,
+	RTE_ETH_FILTER_TUNNEL,
+	RTE_ETH_FILTER_MAX,
+};
+
+/**
+ * All generic operations to filters
+ */
+enum rte_filter_op {
+	/**< used to check whether the type filter is supported */
+	RTE_ETH_FILTER_OP_NONE = 0,
+	RTE_ETH_FILTER_OP_ADD,      /**< add filter entry */
+	RTE_ETH_FILTER_OP_UPDATE,   /**< update filter entry */
+	RTE_ETH_FILTER_OP_DELETE,   /**< delete filter entry */
+	RTE_ETH_FILTER_OP_GET,      /**< get filter entry */
+	RTE_ETH_FILTER_OP_SET,      /**< configurations */
+	/**< get information of filter, such as status or statistics */
+	RTE_ETH_FILTER_OP_GET_INFO,
+	RTE_ETH_FILTER_OP_MAX,
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_ETH_CTRL_H_ */
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index 1659340..1edc816 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -3148,3 +3148,35 @@ rte_eth_dev_get_flex_filter(uint8_t port_id, uint16_t index,
 	return (*dev->dev_ops->get_flex_filter)(dev, index, filter,
 						rx_queue);
 }
+
+int
+rte_eth_dev_filter_supported(uint8_t port_id, enum rte_filter_type filter_type)
+{
+	struct rte_eth_dev *dev;
+
+	if (port_id >= nb_ports) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->filter_ctrl, -ENOTSUP);
+	return (*dev->dev_ops->filter_ctrl)(dev, filter_type,
+				RTE_ETH_FILTER_OP_NONE, NULL);
+}
+
+int
+rte_eth_dev_filter_ctrl(uint8_t port_id, enum rte_filter_type filter_type,
+		       enum rte_filter_op filter_op, void *arg)
+{
+	struct rte_eth_dev *dev;
+
+	if (port_id >= nb_ports) {
+		PMD_DEBUG_TRACE("Invalid port_id=%d\n", port_id);
+		return -ENODEV;
+	}
+
+	dev = &rte_eth_devices[port_id];
+	FUNC_PTR_OR_ERR_RET(*dev->dev_ops->filter_ctrl, -ENOTSUP);
+	return (*dev->dev_ops->filter_ctrl)(dev, filter_type, filter_op, arg);
+}
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index 1948594..6491f8b 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -177,6 +177,7 @@ extern "C" {
 #include <rte_pci.h>
 #include <rte_mbuf.h>
 #include "rte_ether.h"
+#include "rte_eth_ctrl.h"
 
 /**
  * A structure used to retrieve statistics for an Ethernet port.
@@ -1388,6 +1389,12 @@ typedef int (*eth_get_flex_filter_t)(struct rte_eth_dev *dev,
 			uint16_t *rx_queue);
 /**< @internal Get a flex filter rule on an Ethernet device */
 
+typedef int (*eth_filter_ctrl_t)(struct rte_eth_dev *dev,
+				 enum rte_filter_type filter_type,
+				 enum rte_filter_op filter_op,
+				 void *arg);
+/**< @internal Take operations to assigned filter type on an Ethernet device */
+
 /**
  * @internal A structure containing the functions exported by an Ethernet driver.
  */
@@ -1496,6 +1503,7 @@ struct eth_dev_ops {
 	eth_add_flex_filter_t          add_flex_filter;      /**< add flex filter. */
 	eth_remove_flex_filter_t       remove_flex_filter;   /**< remove flex filter. */
 	eth_get_flex_filter_t          get_flex_filter;      /**< get flex filter. */
+	eth_filter_ctrl_t              filter_ctrl;          /**< common filter control*/
 };
 
 /**
@@ -3625,6 +3633,46 @@ int rte_eth_dev_remove_flex_filter(uint8_t port_id, uint16_t index);
 int rte_eth_dev_get_flex_filter(uint8_t port_id, uint16_t index,
 			struct rte_flex_filter *filter, uint16_t *rx_queue);
 
+/**
+ * Check whether the filter type is supported on an Ethernet device.
+ * All the supported filter types are defined in 'rte_eth_ctrl.h'.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param filter_type
+ *   filter type.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support this filter type.
+ *   - (-ENODEV) if *port_id* invalid.
+ */
+int rte_eth_dev_filter_supported(uint8_t port_id,
+				 enum rte_filter_type filter_type);
+
+/**
+ * Take operations to assigned filter type on an Ethernet device.
+ * All the supported operations and filter types are defined in
+ * 'rte_eth_ctrl.h'.
+ *
+ * @param port_id
+ *   The port identifier of the Ethernet device.
+ * @param filter_type
+ *   filter type.
+  * @param filter_op
+ *   The operation taken to assigned filter.
+ * @param arg
+ *   A pointer to arguments defined specifically for the operation.
+ * @return
+ *   - (0) if successful.
+ *   - (-ENOTSUP) if hardware doesn't support.
+ *   - (-ENODEV) if *port_id* invalid.
+ *   - others depends on the specific operations implementation.
+ */
+int rte_eth_dev_filter_ctrl(uint8_t port_id,
+			    enum rte_filter_type filter_type,
+			    enum rte_filter_op filter_op,
+			    void *arg);
+
 #ifdef __cplusplus
 }
 #endif
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v4 3/7] ethdev: add structures and enum for hash filter control
  2014-10-13  6:12   ` [dpdk-dev] [PATCH v4 0/7] Support configuring hash functions Helin Zhang
  2014-10-13  6:12     ` [dpdk-dev] [PATCH v4 1/7] ethdev: add more annotations Helin Zhang
  2014-10-13  6:12     ` [dpdk-dev] [PATCH v4 2/7] ethdev: add interfaces and relevant for filter control Helin Zhang
@ 2014-10-13  6:12     ` Helin Zhang
  2014-10-13  6:12     ` [dpdk-dev] [PATCH v4 4/7] i40e: add hash filter control implementation Helin Zhang
                       ` (6 subsequent siblings)
  9 siblings, 0 replies; 71+ messages in thread
From: Helin Zhang @ 2014-10-13  6:12 UTC (permalink / raw)
  To: dev

Structures and enum are added in rte_eth_ctrl.h to support hash
filter control.

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
---
 lib/librte_ether/rte_eth_ctrl.h | 74 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 74 insertions(+)

diff --git a/lib/librte_ether/rte_eth_ctrl.h b/lib/librte_ether/rte_eth_ctrl.h
index aaea075..10197fc 100644
--- a/lib/librte_ether/rte_eth_ctrl.h
+++ b/lib/librte_ether/rte_eth_ctrl.h
@@ -73,6 +73,80 @@ enum rte_filter_op {
 	RTE_ETH_FILTER_OP_MAX,
 };
 
+/**
+ * Hash filter information types.
+ */
+enum rte_eth_hash_filter_info_type {
+	RTE_ETH_HASH_FILTER_INFO_TYPE_UNKNOWN = 0,
+	RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PCTYPE,
+	RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PORT,
+	RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP,
+	RTE_ETH_HASH_FILTER_INFO_TYPE_HASH_FUNCTION,
+	RTE_ETH_HASH_FILTER_INFO_TYPE_MAX,
+};
+
+/**
+ * Hash function types.
+ */
+enum rte_eth_hash_function {
+	RTE_ETH_HASH_FUNCTION_UNKNOWN = 0,
+	RTE_ETH_HASH_FUNCTION_TOEPLITZ,
+	RTE_ETH_HASH_FUNCTION_SIMPLE_XOR,
+	RTE_ETH_HASH_FUNCTION_MAX,
+};
+
+/**
+ * A structure used to set or get symmetric hash enable information, to support
+ * 'RTE_ETH_FILTER_HASH', 'RTE_ETH_FILTER_OP_GET/RTE_ETH_FILTER_OP_SET', with
+ * information type 'RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PCTYPE'.
+ */
+struct rte_eth_sym_hash_ena_info {
+	/**< packet classification type, defined in rte_ethdev.h */
+	uint8_t pctype;
+	uint8_t enable; /**< enable or disable flag */
+};
+
+/**
+ * A structure used to set or get filter swap information, to support
+ * 'RTE_ETH_FILTER_HASH', 'RTE_ETH_FILTER_OP_GET/RTE_ETH_FILTER_OP_SET',
+ * with information type 'RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP'.
+ */
+struct rte_eth_filter_swap_info {
+	/**< Packet classification type, defined in rte_ethdev.h */
+	uint8_t pctype;
+	/**< Offset of the 1st field of the 1st couple to be swapped. */
+	uint8_t off0_src0;
+	/**< Offset of the 2nd field of the 1st couple to be swapped. */
+	uint8_t off0_src1;
+	/**< Field length of the first couple. */
+	uint8_t len0;
+	/**< Offset of the 1st field of the 2nd couple to be swapped. */
+	uint8_t off1_src0;
+	/**< Offset of the 2nd field of the 2nd couple to be swapped. */
+	uint8_t off1_src1;
+	/**< Field length of the second couple. */
+	uint8_t len1;
+};
+
+/**
+ * A structure used to set or get hash filter information, to support filter
+ * type of 'RTE_ETH_FILTER_HASH' and its operations.
+ */
+struct rte_eth_hash_filter_info {
+	enum rte_eth_hash_filter_info_type info_type; /**< Information type. */
+	/**< Details of hash filter infomation */
+	union {
+		/* For RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PCTYPE */
+		struct rte_eth_sym_hash_ena_info sym_hash_ena;
+		/* For RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP */
+		struct rte_eth_filter_swap_info filter_swap;
+		/* For RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PORT */
+		uint8_t enable;
+		/* For RTE_ETH_HASH_FILTER_INFO_TYPE_HASH_FUNCTION */
+		enum rte_eth_hash_function hash_function;
+	} info;
+};
+
 #ifdef __cplusplus
 }
 #endif
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v4 4/7] i40e: add hash filter control implementation
  2014-10-13  6:12   ` [dpdk-dev] [PATCH v4 0/7] Support configuring hash functions Helin Zhang
                       ` (2 preceding siblings ...)
  2014-10-13  6:12     ` [dpdk-dev] [PATCH v4 3/7] ethdev: add structures and enum for hash " Helin Zhang
@ 2014-10-13  6:12     ` Helin Zhang
  2014-10-13 10:23       ` Chilikin, Andrey
  2014-10-13  6:12     ` [dpdk-dev] [PATCH v4 5/7] i40e: add hardware initialization Helin Zhang
                       ` (5 subsequent siblings)
  9 siblings, 1 reply; 71+ messages in thread
From: Helin Zhang @ 2014-10-13  6:12 UTC (permalink / raw)
  To: dev

Hash filter control has been implemented for i40e. It includes
getting/setting
- hash function type
- symmetric hash enable per pctype (packet classification type)
- symmetric hash enable per port
- filter swap configuration

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
---
 lib/librte_pmd_i40e/i40e_ethdev.c | 402 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 402 insertions(+)

diff --git a/lib/librte_pmd_i40e/i40e_ethdev.c b/lib/librte_pmd_i40e/i40e_ethdev.c
index 46c43a7..60b619b 100644
--- a/lib/librte_pmd_i40e/i40e_ethdev.c
+++ b/lib/librte_pmd_i40e/i40e_ethdev.c
@@ -216,6 +216,10 @@ static int i40e_dev_rss_hash_update(struct rte_eth_dev *dev,
 				    struct rte_eth_rss_conf *rss_conf);
 static int i40e_dev_rss_hash_conf_get(struct rte_eth_dev *dev,
 				      struct rte_eth_rss_conf *rss_conf);
+static int i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
+				enum rte_filter_type filter_type,
+				enum rte_filter_op filter_op,
+				void *arg);
 
 /* Default hash key buffer for RSS */
 static uint32_t rss_key_default[I40E_PFQF_HKEY_MAX_INDEX + 1];
@@ -267,6 +271,7 @@ static struct eth_dev_ops i40e_eth_dev_ops = {
 	.reta_query                   = i40e_dev_rss_reta_query,
 	.rss_hash_update              = i40e_dev_rss_hash_update,
 	.rss_hash_conf_get            = i40e_dev_rss_hash_conf_get,
+	.filter_ctrl                  = i40e_dev_filter_ctrl,
 };
 
 static struct eth_driver rte_i40e_pmd = {
@@ -4162,3 +4167,400 @@ i40e_pf_config_mq_rx(struct i40e_pf *pf)
 
 	return 0;
 }
+
+/* Get the symmetric hash enable configurations per PCTYPE */
+static int
+i40e_get_symmetric_hash_enable_per_pctype(struct i40e_hw *hw,
+			struct rte_eth_sym_hash_ena_info *info)
+{
+	uint32_t reg;
+
+	switch (info->pctype) {
+	case ETH_RSS_NONF_IPV4_UDP_SHIFT:
+	case ETH_RSS_NONF_IPV4_TCP_SHIFT:
+	case ETH_RSS_NONF_IPV4_SCTP_SHIFT:
+	case ETH_RSS_NONF_IPV4_OTHER_SHIFT:
+	case ETH_RSS_FRAG_IPV4_SHIFT:
+	case ETH_RSS_NONF_IPV6_UDP_SHIFT:
+	case ETH_RSS_NONF_IPV6_TCP_SHIFT:
+	case ETH_RSS_NONF_IPV6_SCTP_SHIFT:
+	case ETH_RSS_NONF_IPV6_OTHER_SHIFT:
+	case ETH_RSS_FRAG_IPV6_SHIFT:
+	case ETH_RSS_L2_PAYLOAD_SHIFT:
+		reg = I40E_READ_REG(hw, I40E_GLQF_HSYM(info->pctype));
+		info->enable = reg & I40E_GLQF_HSYM_SYMH_ENA_MASK ? 1 : 0;
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "PCTYPE[%u] not supported", info->pctype);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* Set the symmetric hash enable configurations per PCTYPE */
+static int
+i40e_set_symmetric_hash_enable_per_pctype(struct i40e_hw *hw,
+		const struct rte_eth_sym_hash_ena_info *info)
+{
+	uint32_t reg;
+
+	switch (info->pctype) {
+	case ETH_RSS_NONF_IPV4_UDP_SHIFT:
+	case ETH_RSS_NONF_IPV4_TCP_SHIFT:
+	case ETH_RSS_NONF_IPV4_SCTP_SHIFT:
+	case ETH_RSS_NONF_IPV4_OTHER_SHIFT:
+	case ETH_RSS_FRAG_IPV4_SHIFT:
+	case ETH_RSS_NONF_IPV6_UDP_SHIFT:
+	case ETH_RSS_NONF_IPV6_TCP_SHIFT:
+	case ETH_RSS_NONF_IPV6_SCTP_SHIFT:
+	case ETH_RSS_NONF_IPV6_OTHER_SHIFT:
+	case ETH_RSS_FRAG_IPV6_SHIFT:
+	case ETH_RSS_L2_PAYLOAD_SHIFT:
+		reg = info->enable ? I40E_GLQF_HSYM_SYMH_ENA_MASK : 0;
+		I40E_WRITE_REG(hw, I40E_GLQF_HSYM(info->pctype), reg);
+		I40E_WRITE_FLUSH(hw);
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "PCTYPE[%u] not supported", info->pctype);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* Get the symmetric hash enable configurations per port */
+static void
+i40e_get_symmetric_hash_enable_per_port(struct i40e_hw *hw, uint8_t *enable)
+{
+	uint32_t reg = I40E_READ_REG(hw, I40E_PRTQF_CTL_0);
+
+	*enable = reg & I40E_PRTQF_CTL_0_HSYM_ENA_MASK ? 1 : 0;
+}
+
+/* Set the symmetric hash enable configurations per port */
+static void
+i40e_set_symmetric_hash_enable_per_port(struct i40e_hw *hw, uint8_t enable)
+{
+	uint32_t reg = I40E_READ_REG(hw, I40E_PRTQF_CTL_0);
+
+	if (enable > 0) {
+		if (reg & I40E_PRTQF_CTL_0_HSYM_ENA_MASK) {
+			PMD_DRV_LOG(INFO, "Symmetric hash has already "
+							"been enabled");
+			return;
+		}
+		reg |= I40E_PRTQF_CTL_0_HSYM_ENA_MASK;
+	} else {
+		if (!(reg & I40E_PRTQF_CTL_0_HSYM_ENA_MASK)) {
+			PMD_DRV_LOG(INFO, "Symmetric hash has already "
+							"been disabled");
+			return;
+		}
+		reg &= ~I40E_PRTQF_CTL_0_HSYM_ENA_MASK;
+	}
+	I40E_WRITE_REG(hw, I40E_PRTQF_CTL_0, reg);
+	I40E_WRITE_FLUSH(hw);
+}
+
+/* Get filter swap configurations */
+static int
+i40e_get_filter_swap(struct i40e_hw *hw, struct rte_eth_filter_swap_info *info)
+{
+	uint32_t reg;
+
+	switch (info->pctype) {
+	case ETH_RSS_NONF_IPV4_UDP_SHIFT:
+	case ETH_RSS_NONF_IPV4_TCP_SHIFT:
+	case ETH_RSS_NONF_IPV4_SCTP_SHIFT:
+	case ETH_RSS_NONF_IPV4_OTHER_SHIFT:
+	case ETH_RSS_FRAG_IPV4_SHIFT:
+	case ETH_RSS_NONF_IPV6_UDP_SHIFT:
+	case ETH_RSS_NONF_IPV6_TCP_SHIFT:
+	case ETH_RSS_NONF_IPV6_SCTP_SHIFT:
+	case ETH_RSS_NONF_IPV6_OTHER_SHIFT:
+	case ETH_RSS_FRAG_IPV6_SHIFT:
+	case ETH_RSS_L2_PAYLOAD_SHIFT:
+		reg = I40E_READ_REG(hw, I40E_GLQF_SWAP(0, info->pctype));
+		PMD_DRV_LOG(DEBUG, "Value read from I40E_GLQF_SWAP[0,%d]: "
+						"0x%x", info->pctype, reg);
+
+		/**
+		 * The offset and length read from register in word unit,
+		 * which need to be converted in byte unit before being saved.
+		 */
+		info->off0_src0 =
+			(uint8_t)((reg & I40E_GLQF_SWAP_OFF0_SRC0_MASK) >>
+					I40E_GLQF_SWAP_OFF0_SRC0_SHIFT) << 1;
+		info->off0_src1 =
+			(uint8_t)((reg & I40E_GLQF_SWAP_OFF0_SRC1_MASK) >>
+					I40E_GLQF_SWAP_OFF0_SRC1_SHIFT) << 1;
+		info->len0 = (uint8_t)((reg & I40E_GLQF_SWAP_FLEN0_MASK) >>
+					I40E_GLQF_SWAP_FLEN0_SHIFT) << 1;
+		info->off1_src0 =
+			(uint8_t)((reg & I40E_GLQF_SWAP_OFF1_SRC0_MASK) >>
+					I40E_GLQF_SWAP_OFF1_SRC0_SHIFT) << 1;
+		info->off1_src1 =
+			(uint8_t)((reg & I40E_GLQF_SWAP_OFF1_SRC1_MASK) >>
+					I40E_GLQF_SWAP_OFF1_SRC1_SHIFT) << 1;
+		info->len1 = (uint8_t)((reg & I40E_GLQF_SWAP_FLEN1_MASK) >>
+					I40E_GLQF_SWAP_FLEN1_SHIFT) << 1;
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "PCTYPE[%u] not supported", info->pctype);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* Set filter swap configurations */
+static int
+i40e_set_filter_swap(struct i40e_hw *hw,
+		     const struct rte_eth_filter_swap_info *info)
+{
+#define I40E_FIELD_LEN_MAX 0x1f
+#define I40E_FIELD_OFFSET_MAX 0x7f
+	uint32_t reg;
+
+	switch (info->pctype) {
+	case ETH_RSS_NONF_IPV4_UDP_SHIFT:
+	case ETH_RSS_NONF_IPV4_TCP_SHIFT:
+	case ETH_RSS_NONF_IPV4_SCTP_SHIFT:
+	case ETH_RSS_NONF_IPV4_OTHER_SHIFT:
+	case ETH_RSS_FRAG_IPV4_SHIFT:
+	case ETH_RSS_NONF_IPV6_UDP_SHIFT:
+	case ETH_RSS_NONF_IPV6_TCP_SHIFT:
+	case ETH_RSS_NONF_IPV6_SCTP_SHIFT:
+	case ETH_RSS_NONF_IPV6_OTHER_SHIFT:
+	case ETH_RSS_FRAG_IPV6_SHIFT:
+	case ETH_RSS_L2_PAYLOAD_SHIFT:
+		if (info->off0_src0 > I40E_FIELD_OFFSET_MAX) {
+			PMD_DRV_LOG(ERR, "off0_src0 (0x%x) exceeds the "
+				"maximum of 0x%x", info->off0_src0,
+						I40E_FIELD_OFFSET_MAX);
+			return I40E_ERR_PARAM;
+		} else if (info->off0_src1 > I40E_FIELD_OFFSET_MAX) {
+			PMD_DRV_LOG(ERR, "off0_src1 (0x%x) exceeds the "
+				"maximum of 0x%x", info->off0_src1,
+						I40E_FIELD_OFFSET_MAX);
+			return I40E_ERR_PARAM;
+		} else if (info->len0 > I40E_FIELD_LEN_MAX) {
+			PMD_DRV_LOG(ERR, "len0 (0x%x) exceeds the maximum "
+				"of 0x%x", info->len0, I40E_FIELD_LEN_MAX);
+			return I40E_ERR_PARAM;
+		} else if (info->off1_src0 > I40E_FIELD_OFFSET_MAX) {
+			PMD_DRV_LOG(ERR, "off1_src0 (0x%x) exceeds the "
+				"maximum of 0x%x", info->off1_src0,
+						I40E_FIELD_OFFSET_MAX);
+			return I40E_ERR_PARAM;
+		} else if (info->off1_src1 > I40E_FIELD_OFFSET_MAX) {
+			PMD_DRV_LOG(ERR, "off1_src1 (0x%x) exceeds the "
+				"maximum of 0x%x", info->off1_src1,
+						I40E_FIELD_OFFSET_MAX);
+			return I40E_ERR_PARAM;
+		} else if (info->len1 > I40E_FIELD_LEN_MAX) {
+			PMD_DRV_LOG(ERR, "len1 (0x%x) exceeds the maximum "
+				"of 0x%x", info->len1, I40E_FIELD_LEN_MAX);
+			return I40E_ERR_PARAM;
+		}
+
+		/**
+		 * The offset and length given in byte unit, which need to be
+		 * converted in word unit before being written to the register,
+		 * as hardware requires it in word unit.
+		 */
+		reg = (info->off0_src0 >> 1) << I40E_GLQF_SWAP_OFF0_SRC0_SHIFT;
+		reg |= (info->off0_src1 >> 1) <<
+			I40E_GLQF_SWAP_OFF0_SRC1_SHIFT;
+		reg |= (info->len0 >> 1) << I40E_GLQF_SWAP_FLEN0_SHIFT;
+		reg |= (info->off1_src0 >> 1) <<
+			I40E_GLQF_SWAP_OFF1_SRC0_SHIFT;
+		reg |= (info->off1_src1 >> 1) <<
+			I40E_GLQF_SWAP_OFF1_SRC1_SHIFT;
+		reg |= (info->len1 >> 1) << I40E_GLQF_SWAP_FLEN1_SHIFT;
+
+		PMD_DRV_LOG(DEBUG, "Value to be written to "
+			"I40E_GLQF_SWAP[0,%d]: 0x%x", info->pctype, reg);
+		I40E_WRITE_REG(hw, I40E_GLQF_SWAP(0, info->pctype), reg);
+		I40E_WRITE_FLUSH(hw);
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "PCTYPE[%u] not supported", info->pctype);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* Get hash function type */
+static void
+i40e_get_hash_function(struct i40e_hw *hw, enum rte_eth_hash_function *hf)
+{
+	uint32_t reg = I40E_READ_REG(hw, I40E_GLQF_CTL);
+
+	if (reg & I40E_GLQF_CTL_HTOEP_MASK)
+		*hf = RTE_ETH_HASH_FUNCTION_TOEPLITZ;
+	else
+		*hf = RTE_ETH_HASH_FUNCTION_SIMPLE_XOR;
+
+	PMD_DRV_LOG(INFO, "Hash function is %s",
+		(reg & I40E_GLQF_CTL_HTOEP_MASK) ? "Toeplitz" : "Simple XOR");
+}
+
+/* Set hash function type */
+static int
+i40e_set_hash_function(struct i40e_hw *hw, enum rte_eth_hash_function hf)
+{
+	uint32_t reg = I40E_READ_REG(hw, I40E_GLQF_CTL);
+
+	if (hf == RTE_ETH_HASH_FUNCTION_TOEPLITZ) {
+		if (reg & I40E_GLQF_CTL_HTOEP_MASK) {
+			PMD_DRV_LOG(DEBUG, "Hash function already set to "
+								"Toeplitz");
+			return 0;
+		}
+		reg |= I40E_GLQF_CTL_HTOEP_MASK;
+	} else if (hf == RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) {
+		if (!(reg & I40E_GLQF_CTL_HTOEP_MASK)) {
+			PMD_DRV_LOG(DEBUG, "Hash function already set to "
+							"Simple XOR");
+			return 0;
+		}
+		reg &= ~I40E_GLQF_CTL_HTOEP_MASK;
+	} else {
+		PMD_DRV_LOG(ERR, "Unknown hash function type");
+		return -EINVAL;
+	}
+
+	PMD_DRV_LOG(INFO, "Hash function set to %s",
+		(reg & I40E_GLQF_CTL_HTOEP_MASK) ? "Toeplitz" : "Simple XOR");
+	I40E_WRITE_REG(hw, I40E_GLQF_CTL, reg);
+	I40E_WRITE_FLUSH(hw);
+
+	return 0;
+}
+
+static int
+i40e_hash_filter_get(struct i40e_hw *hw, struct rte_eth_hash_filter_info *info)
+{
+	int ret = 0;
+
+	if (!hw || !info) {
+		PMD_DRV_LOG(ERR, "Invalid pointer");
+		return -EFAULT;
+	}
+
+	switch (info->info_type) {
+	case RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PCTYPE:
+		ret = i40e_get_symmetric_hash_enable_per_pctype(hw,
+					&(info->info.sym_hash_ena));
+		break;
+	case RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PORT:
+		i40e_get_symmetric_hash_enable_per_port(hw,
+					&(info->info.enable));
+		break;
+	case RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP:
+		ret = i40e_get_filter_swap(hw, &(info->info.filter_swap));
+		break;
+	case RTE_ETH_HASH_FILTER_INFO_TYPE_HASH_FUNCTION:
+		i40e_get_hash_function(hw, &(info->info.hash_function));
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "Hash filter info type (%d) not supported",
+							info->info_type);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int
+i40e_hash_filter_set(struct i40e_hw *hw, struct rte_eth_hash_filter_info *info)
+{
+	int ret = 0;
+
+	if (!hw || !info) {
+		PMD_DRV_LOG(ERR, "Invalid pointer");
+		return -EFAULT;
+	}
+
+	switch (info->info_type) {
+	case RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PCTYPE:
+		ret = i40e_set_symmetric_hash_enable_per_pctype(hw,
+					&(info->info.sym_hash_ena));
+		break;
+	case RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PORT:
+		i40e_set_symmetric_hash_enable_per_port(hw, info->info.enable);
+		break;
+	case RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP:
+		ret = i40e_set_filter_swap(hw, &(info->info.filter_swap));
+		break;
+	case RTE_ETH_HASH_FILTER_INFO_TYPE_HASH_FUNCTION:
+		ret = i40e_set_hash_function(hw, info->info.hash_function);
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "Hash filter info type (%d) not supported",
+							info->info_type);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+/* Operations for hash function */
+static int
+i40e_hash_filter_ctrl(struct rte_eth_dev *dev,
+		      enum rte_filter_op filter_op,
+		      void *arg)
+{
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	int ret = 0;
+
+	switch (filter_op) {
+	case RTE_ETH_FILTER_OP_NONE:
+		break;
+	case RTE_ETH_FILTER_OP_GET:
+		ret = i40e_hash_filter_get(hw,
+			(struct rte_eth_hash_filter_info *)arg);
+		break;
+	case RTE_ETH_FILTER_OP_SET:
+		ret = i40e_hash_filter_set(hw,
+			(struct rte_eth_hash_filter_info *)arg);
+		break;
+	default:
+		PMD_DRV_LOG(WARNING, "Filter operation (%d) not supported",
+								filter_op);
+		ret = -ENOTSUP;
+		break;
+	}
+
+	return ret;
+}
+
+static int
+i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
+		     enum rte_filter_type filter_type,
+		     enum rte_filter_op filter_op,
+		     void *arg)
+{
+	int ret = -ENOTSUP;
+
+	switch (filter_type) {
+	case RTE_ETH_FILTER_HASH:
+		ret = i40e_hash_filter_ctrl(dev, filter_op, arg);
+		break;
+	case RTE_ETH_FILTER_FDIR:
+		break;
+	case RTE_ETH_FILTER_TUNNEL:
+		break;
+	default:
+		PMD_DRV_LOG(WARNING, "Filter type (%d) not supported",
+							filter_type);
+		break;
+	}
+
+	return ret;
+}
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v4 5/7] i40e: add hardware initialization
  2014-10-13  6:12   ` [dpdk-dev] [PATCH v4 0/7] Support configuring hash functions Helin Zhang
                       ` (3 preceding siblings ...)
  2014-10-13  6:12     ` [dpdk-dev] [PATCH v4 4/7] i40e: add hash filter control implementation Helin Zhang
@ 2014-10-13  6:12     ` Helin Zhang
  2014-10-13  6:12     ` [dpdk-dev] [PATCH v4 6/7] i40e: Use constant random hash keys Helin Zhang
                       ` (4 subsequent siblings)
  9 siblings, 0 replies; 71+ messages in thread
From: Helin Zhang @ 2014-10-13  6:12 UTC (permalink / raw)
  To: dev

As global registers will be reset only after a whole chip reset,
those registers might not be in an initial state after each
launching a physical port. The hardware initialization is added
to put specific global registers into an initial state.

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
---
 lib/librte_pmd_i40e/i40e_ethdev.c | 78 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 78 insertions(+)

diff --git a/lib/librte_pmd_i40e/i40e_ethdev.c b/lib/librte_pmd_i40e/i40e_ethdev.c
index 60b619b..ce80f27 100644
--- a/lib/librte_pmd_i40e/i40e_ethdev.c
+++ b/lib/librte_pmd_i40e/i40e_ethdev.c
@@ -220,6 +220,7 @@ static int i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
 				enum rte_filter_type filter_type,
 				enum rte_filter_op filter_op,
 				void *arg);
+static void i40e_hw_init(struct i40e_hw *hw);
 
 /* Default hash key buffer for RSS */
 static uint32_t rss_key_default[I40E_PFQF_HKEY_MAX_INDEX + 1];
@@ -401,6 +402,9 @@ eth_i40e_dev_init(__rte_unused struct eth_driver *eth_drv,
 	/* Make sure all is clean before doing PF reset */
 	i40e_clear_hw(hw);
 
+	/* Initialize the hardware */
+	i40e_hw_init(hw);
+
 	/* Reset here to make sure all is clean for each PF */
 	ret = i40e_pf_reset(hw);
 	if (ret) {
@@ -4564,3 +4568,77 @@ i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
 
 	return ret;
 }
+
+/* Initialization for hash function */
+static void
+i40e_hash_function_hw_init(struct i40e_hw *hw)
+{
+	uint32_t i;
+	const struct rte_eth_sym_hash_ena_info sym_hash_ena_info[] = {
+		{ETH_RSS_NONF_IPV4_UDP_SHIFT, 0},
+		{ETH_RSS_NONF_IPV4_TCP_SHIFT, 0},
+		{ETH_RSS_NONF_IPV4_SCTP_SHIFT, 0},
+		{ETH_RSS_NONF_IPV4_OTHER_SHIFT, 0},
+		{ETH_RSS_FRAG_IPV4_SHIFT, 0},
+		{ETH_RSS_NONF_IPV6_UDP_SHIFT, 0},
+		{ETH_RSS_NONF_IPV6_TCP_SHIFT, 0},
+		{ETH_RSS_NONF_IPV6_SCTP_SHIFT, 0},
+		{ETH_RSS_NONF_IPV6_OTHER_SHIFT, 0},
+		{ETH_RSS_FRAG_IPV6_SHIFT, 0},
+		{ETH_RSS_L2_PAYLOAD_SHIFT, 0},
+	};
+	const struct rte_eth_filter_swap_info swap_info[] = {
+		{ETH_RSS_NONF_IPV4_UDP_SHIFT,
+			0x1e, 0x36, 0x04, 0x3a, 0x3c, 0x02},
+		{ETH_RSS_NONF_IPV4_TCP_SHIFT,
+			0x1e, 0x36, 0x04, 0x3a, 0x3c, 0x02},
+		{ETH_RSS_NONF_IPV4_SCTP_SHIFT,
+			0x1e, 0x36, 0x04, 0x00, 0x00, 0x00},
+		{ETH_RSS_NONF_IPV4_OTHER_SHIFT,
+			0x1e, 0x36, 0x04, 0x00, 0x00, 0x00},
+		{ETH_RSS_FRAG_IPV4_SHIFT,
+			0x1e, 0x36, 0x04, 0x00, 0x00, 0x00},
+		{ETH_RSS_NONF_IPV6_UDP_SHIFT,
+			0x1a, 0x2a, 0x10, 0x3a, 0x3c, 0x02},
+		{ETH_RSS_NONF_IPV6_TCP_SHIFT,
+			0x1a, 0x2a, 0x10, 0x3a, 0x3c, 0x02},
+		{ETH_RSS_NONF_IPV6_SCTP_SHIFT,
+			0x1a, 0x2a, 0x10, 0x00, 0x00, 0x00},
+		{ETH_RSS_NONF_IPV6_OTHER_SHIFT,
+			0x1a, 0x2a, 0x10, 0x00, 0x00, 0x00},
+		{ETH_RSS_FRAG_IPV6_SHIFT,
+			0x1a, 0x2a, 0x10, 0x00, 0x00, 0x00},
+		{ETH_RSS_L2_PAYLOAD_SHIFT,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+	};
+
+	/* Disable symmetric hash per PCTYPE */
+	for (i = 0; i < RTE_DIM(sym_hash_ena_info); i++)
+		i40e_set_symmetric_hash_enable_per_pctype(hw,
+					&sym_hash_ena_info[i]);
+
+	/* Disable symmetric hash per port */
+	i40e_set_symmetric_hash_enable_per_port(hw, 0);
+
+	/* Initialize filter swap */
+	for (i = 0; i < RTE_DIM(swap_info); i++)
+		i40e_set_filter_swap(hw, &swap_info[i]);
+
+	/* Set hash function to Toeplitz by default */
+	i40e_set_hash_function(hw, RTE_ETH_HASH_FUNCTION_TOEPLITZ);
+}
+
+/*
+ * As global registers wouldn't be reset unless a global hardware reset,
+ * hardware initialization is needed to put those registers into an
+ * expected initial state.
+ */
+static void
+i40e_hw_init(struct i40e_hw *hw)
+{
+	/* clear the PF Queue Filter control register */
+	I40E_WRITE_REG(hw, I40E_PFQF_CTL_0, 0);
+
+	/* Initialize hardware for hash function */
+	i40e_hash_function_hw_init(hw);
+}
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v4 6/7] i40e: Use constant random hash keys
  2014-10-13  6:12   ` [dpdk-dev] [PATCH v4 0/7] Support configuring hash functions Helin Zhang
                       ` (4 preceding siblings ...)
  2014-10-13  6:12     ` [dpdk-dev] [PATCH v4 5/7] i40e: add hardware initialization Helin Zhang
@ 2014-10-13  6:12     ` Helin Zhang
  2014-10-13  6:12     ` [dpdk-dev] [PATCH v4 7/7] app/testpmd: add commands to support hash filter control Helin Zhang
                       ` (3 subsequent siblings)
  9 siblings, 0 replies; 71+ messages in thread
From: Helin Zhang @ 2014-10-13  6:12 UTC (permalink / raw)
  To: dev

To be simpler, and remove the race condition, it uses prepared
constant random hash keys to replace runtime generating the
hash keys.

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
---
 lib/librte_pmd_i40e/i40e_ethdev.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/lib/librte_pmd_i40e/i40e_ethdev.c b/lib/librte_pmd_i40e/i40e_ethdev.c
index ce80f27..95132d5 100644
--- a/lib/librte_pmd_i40e/i40e_ethdev.c
+++ b/lib/librte_pmd_i40e/i40e_ethdev.c
@@ -222,9 +222,6 @@ static int i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
 				void *arg);
 static void i40e_hw_init(struct i40e_hw *hw);
 
-/* Default hash key buffer for RSS */
-static uint32_t rss_key_default[I40E_PFQF_HKEY_MAX_INDEX + 1];
-
 static struct rte_pci_id pci_id_i40e_map[] = {
 #define RTE_PCI_DEV_ID_DECL_I40E(vend, dev) {RTE_PCI_DEVICE(vend, dev)},
 #include "rte_pci_dev_ids.h"
@@ -4144,9 +4141,12 @@ i40e_pf_config_rss(struct i40e_pf *pf)
 	}
 	if (rss_conf.rss_key == NULL || rss_conf.rss_key_len <
 		(I40E_PFQF_HKEY_MAX_INDEX + 1) * sizeof(uint32_t)) {
-		/* Calculate the default hash key */
-		for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++)
-			rss_key_default[i] = (uint32_t)rte_rand();
+		/* Random default keys */
+		static uint32_t rss_key_default[] = {0x6b793944,
+			0x23504cb5, 0x5bea75b6, 0x309f4f12, 0x3dc0a2b8,
+			0x024ddcdf, 0x339b8ca0, 0x4c4af64a, 0x34fac605,
+			0x55d85839, 0x3a58997d, 0x2ec938e1, 0x66031581};
+
 		rss_conf.rss_key = (uint8_t *)rss_key_default;
 		rss_conf.rss_key_len = (I40E_PFQF_HKEY_MAX_INDEX + 1) *
 							sizeof(uint32_t);
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v4 7/7] app/testpmd: add commands to support hash filter control
  2014-10-13  6:12   ` [dpdk-dev] [PATCH v4 0/7] Support configuring hash functions Helin Zhang
                       ` (5 preceding siblings ...)
  2014-10-13  6:12     ` [dpdk-dev] [PATCH v4 6/7] i40e: Use constant random hash keys Helin Zhang
@ 2014-10-13  6:12     ` Helin Zhang
  2014-10-13 12:27     ` [dpdk-dev] [PATCH v4 0/7] Support configuring hash functions Zhan, Zhaochen
                       ` (2 subsequent siblings)
  9 siblings, 0 replies; 71+ messages in thread
From: Helin Zhang @ 2014-10-13  6:12 UTC (permalink / raw)
  To: dev

To demonstrate the hash filter control, commands are added.
They are
- get_sym_hash_ena_per_port
- set_sym_hash_ena_per_port
- get_sym_hash_ena_per_pctype
- set_sym_hash_ena_per_pctype
- get_filter_swap
- set_filter_swap
- get_hash_function
- set_hash_function

v4 changes:
* Fixed a bug in testpmd for 'set_sym_hash_ena_per_port'.

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
---
 app/test-pmd/cmdline.c | 566 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 566 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 0b972f9..bea88d1 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -74,6 +74,7 @@
 #include <rte_ethdev.h>
 #include <rte_string_fns.h>
 #include <rte_devargs.h>
+#include <rte_eth_ctrl.h>
 
 #include <cmdline_rdline.h>
 #include <cmdline_parse.h>
@@ -660,6 +661,35 @@ static void cmd_help_long_parsed(void *parsed_result,
 
 			"get_flex_filter (port_id) index (idx)\n"
 			"    get info of a flex filter.\n\n"
+
+			"get_sym_hash_ena_per_port (port_id)\n"
+			"    get symmetric hash enable configuration per port.\n\n"
+
+			"set_sym_hash_ena_per_port (port_id)"
+			" (enable|disable)\n"
+			"    set symmetric hash enable configuration per port"
+			" to enable or disable.\n\n"
+
+			"get_sym_hash_ena_per_pctype (port_id) (pctype)\n"
+			"    get symmetric hash enable configuration per port\n\n"
+
+			"set_sym_hash_ena_per_pctype (port_id) (pctype)"
+			" (enable|disable)\n"
+			"    set symmetric hash enable configuration per"
+			" pctype to enable or disable.\n\n"
+
+			"get_filter_swap (port_id) (pctype)\n"
+			"    get filter swap configurations.\n\n"
+
+			"set_filter_swap (port_id) (pctype) (off0_src0) (off0_src1)"
+			" (len0) (off1_src0) (off1_src1) (len1)\n"
+			"    set filter swap configurations.\n\n"
+
+			"get_hash_function (port_id)\n"
+			"    get hash function of Toeplitz or Simple XOR.\n\n"
+
+			"set_hash_function (port_id) (toeplitz|simple_xor)\n"
+			"    set the hash function to Toeplitz or Simple XOR.\n\n"
 		);
 	}
 }
@@ -7415,6 +7445,534 @@ cmdline_parse_inst_t cmd_get_flex_filter = {
 	},
 };
 
+/* *** Classification Filters Control *** */
+
+/* *** Get symmetric hash enable per port *** */
+struct cmd_get_sym_hash_ena_per_port_result {
+	cmdline_fixed_string_t get_sym_hash_ena_per_port;
+	uint8_t port_id;
+};
+
+static void
+cmd_get_sym_hash_per_port_parsed(void *parsed_result,
+				 __rte_unused struct cmdline *cl,
+				 __rte_unused void *data)
+{
+	struct cmd_get_sym_hash_ena_per_port_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port: %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PORT;
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+					RTE_ETH_FILTER_OP_GET, &info);
+	if (ret < 0) {
+		printf("Cannot get symmetric hash enable per port "
+					"on port %u\n", res->port_id);
+		return;
+	}
+
+	printf("Symmetric hash is %s on port %u\n", info.info.enable ?
+				"enabled" : "disabled", res->port_id);
+}
+
+cmdline_parse_token_string_t cmd_get_sym_hash_ena_per_port_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_get_sym_hash_ena_per_port_result,
+		get_sym_hash_ena_per_port, "get_sym_hash_ena_per_port");
+cmdline_parse_token_num_t cmd_get_sym_hash_ena_per_port_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_get_sym_hash_ena_per_port_result,
+		port_id, UINT8);
+
+cmdline_parse_inst_t cmd_get_sym_hash_ena_per_port = {
+	.f = cmd_get_sym_hash_per_port_parsed,
+	.data = NULL,
+	.help_str = "get_sym_hash_ena_per_port port_id",
+	.tokens = {
+		(void *)&cmd_get_sym_hash_ena_per_port_all,
+		(void *)&cmd_get_sym_hash_ena_per_port_port_id,
+		NULL,
+	},
+};
+
+/* *** Set symmetric hash enable per port *** */
+struct cmd_set_sym_hash_ena_per_port_result {
+	cmdline_fixed_string_t set_sym_hash_ena_per_port;
+	cmdline_fixed_string_t enable;
+	uint8_t port_id;
+};
+
+static void
+cmd_set_sym_hash_per_port_parsed(void *parsed_result,
+				 __rte_unused struct cmdline *cl,
+				 __rte_unused void *data)
+{
+	struct cmd_set_sym_hash_ena_per_port_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port: %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PORT;
+	if (!strcmp(res->enable, "enable"))
+		info.info.enable = 1;
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+					RTE_ETH_FILTER_OP_SET, &info);
+	if (ret < 0) {
+		printf("Cannot set symmetric hash enable per port on "
+					"port %u\n", res->port_id);
+		return;
+	}
+
+	printf("Symmetric hash has been set to %s on port %u\n",
+					res->enable, res->port_id);
+}
+
+cmdline_parse_token_string_t cmd_set_sym_hash_ena_per_port_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_sym_hash_ena_per_port_result,
+		set_sym_hash_ena_per_port, "set_sym_hash_ena_per_port");
+cmdline_parse_token_num_t cmd_set_sym_hash_ena_per_port_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_sym_hash_ena_per_port_result,
+		port_id, UINT8);
+cmdline_parse_token_string_t cmd_set_sym_hash_ena_per_port_enable =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_sym_hash_ena_per_port_result,
+		enable, "enable#disable");
+
+cmdline_parse_inst_t cmd_set_sym_hash_ena_per_port = {
+	.f = cmd_set_sym_hash_per_port_parsed,
+	.data = NULL,
+	.help_str = "set_sym_hash_ena_per_port port_id enable|disable",
+	.tokens = {
+		(void *)&cmd_set_sym_hash_ena_per_port_all,
+		(void *)&cmd_set_sym_hash_ena_per_port_port_id,
+		(void *)&cmd_set_sym_hash_ena_per_port_enable,
+		NULL,
+	},
+};
+
+/* *** Get symmetric hash enable per pctype *** */
+struct cmd_get_sym_hash_ena_per_pctype_result {
+	cmdline_fixed_string_t get_sym_hash_ena_per_pctype;
+	uint8_t port_id;
+	uint8_t pctype;
+};
+
+static void
+cmd_get_sym_hash_per_pctype_parsed(void *parsed_result,
+				   __rte_unused struct cmdline *cl,
+				   __rte_unused void *data)
+{
+	struct cmd_get_sym_hash_ena_per_pctype_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port: %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PCTYPE;
+	info.info.sym_hash_ena.pctype = res->pctype;
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+					RTE_ETH_FILTER_OP_GET, &info);
+	if (ret < 0) {
+		printf("Cannot get symmetric hash enable per pctype on "
+			"port %u, pctype %u\n", res->port_id, res->pctype);
+		return;
+	}
+	printf("Symmetric hash is %s on port %u, pctype %u\n",
+			info.info.sym_hash_ena.enable ? "enabled" :
+			"disabled", res->port_id, res->pctype);
+}
+
+cmdline_parse_token_string_t cmd_get_sym_hash_ena_per_pctype_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_get_sym_hash_ena_per_pctype_result,
+		get_sym_hash_ena_per_pctype, "get_sym_hash_ena_per_pctype");
+cmdline_parse_token_num_t cmd_get_sym_hash_ena_per_pctype_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_get_sym_hash_ena_per_pctype_result,
+		port_id, UINT8);
+cmdline_parse_token_num_t cmd_get_sym_hash_ena_per_pctype_pctype =
+	TOKEN_NUM_INITIALIZER(struct cmd_get_sym_hash_ena_per_pctype_result,
+		pctype, UINT8);
+
+cmdline_parse_inst_t cmd_get_sym_hash_ena_per_pctype = {
+	.f = cmd_get_sym_hash_per_pctype_parsed,
+	.data = NULL,
+	.help_str = "get_sym_hash_ena_per_pctype port_id pctype",
+	.tokens = {
+		(void *)&cmd_get_sym_hash_ena_per_pctype_all,
+		(void *)&cmd_get_sym_hash_ena_per_pctype_port_id,
+		(void *)&cmd_get_sym_hash_ena_per_pctype_pctype,
+		NULL,
+	},
+};
+
+/* *** Set symmetric hash enable per pctype *** */
+struct cmd_set_sym_hash_ena_per_pctype_result {
+	cmdline_fixed_string_t set_sym_hash_ena_per_pctype;
+	cmdline_fixed_string_t enable;
+	uint8_t port_id;
+	uint8_t pctype;
+};
+
+static void
+cmd_set_sym_hash_per_pctype_parsed(void *parsed_result,
+				   __rte_unused struct cmdline *cl,
+				   __rte_unused void *data)
+{
+	struct cmd_set_sym_hash_ena_per_pctype_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port: %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PCTYPE;
+	info.info.sym_hash_ena.pctype = res->pctype;
+	if (!strcmp(res->enable, "enable"))
+		info.info.sym_hash_ena.enable = 1;
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+					RTE_ETH_FILTER_OP_SET, &info);
+	if (ret < 0) {
+		printf("Cannot set symmetric hash enable per pctype to %s "
+			"on port %u, pctype %u\n", res->enable ? "enabled" :
+				"disabled", res->port_id, res->pctype);
+		return;
+	}
+	printf("Symmetic hash has been set to %s on port %u, pctype %u\n",
+				res->enable, res->port_id, res->pctype);
+}
+
+cmdline_parse_token_string_t cmd_set_sym_hash_ena_per_pctype_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_sym_hash_ena_per_pctype_result,
+		set_sym_hash_ena_per_pctype, "set_sym_hash_ena_per_pctype");
+cmdline_parse_token_num_t cmd_set_sym_hash_ena_per_pctype_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_sym_hash_ena_per_pctype_result,
+		port_id, UINT8);
+cmdline_parse_token_num_t cmd_set_sym_hash_ena_per_pctype_pctype =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_sym_hash_ena_per_pctype_result,
+		pctype, UINT8);
+cmdline_parse_token_string_t cmd_set_sym_hash_ena_per_pctype_enable =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_sym_hash_ena_per_pctype_result,
+		enable, "enable#disable");
+
+cmdline_parse_inst_t cmd_set_sym_hash_ena_per_pctype = {
+	.f = cmd_set_sym_hash_per_pctype_parsed,
+	.data = NULL,
+	.help_str = "set_sym_hash_ena_per_pctype pord_id pctype "
+						"enable|disable",
+	.tokens = {
+		(void *)&cmd_set_sym_hash_ena_per_pctype_all,
+		(void *)&cmd_set_sym_hash_ena_per_pctype_port_id,
+		(void *)&cmd_set_sym_hash_ena_per_pctype_pctype,
+		(void *)&cmd_set_sym_hash_ena_per_pctype_enable,
+		NULL,
+	},
+};
+
+/* *** Get filter swap *** */
+struct cmd_get_filter_swap_result {
+	cmdline_fixed_string_t get_filter_swap;
+	uint8_t port_id;
+	uint8_t pctype;
+};
+
+static void
+cmd_get_filter_swap_parsed(void *parsed_result,
+			   __rte_unused struct cmdline *cl,
+			   __rte_unused void *data)
+{
+	struct cmd_get_filter_swap_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port: %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP;
+	info.info.filter_swap.pctype = res->pctype;
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+					RTE_ETH_FILTER_OP_GET, &info);
+	if (ret < 0) {
+		printf("Cannot get filter swap on port %u, pctype %u\n",
+						res->port_id, res->pctype);
+		return;
+	}
+	printf("Filter swap of port %u, pctype %u is configured as:\n"
+		"off0_src0: 0x%02x, off0_src1: 0x%02x, len0: 0x%02x\n"
+		"off1_src0: 0x%02x, off1_src1: 0x%02x, len1: 0x%02x\n",
+		res->port_id, res->pctype, info.info.filter_swap.off0_src0,
+		info.info.filter_swap.off0_src1, info.info.filter_swap.len0,
+		info.info.filter_swap.off1_src0,
+		info.info.filter_swap.off1_src1, info.info.filter_swap.len1);
+}
+
+cmdline_parse_token_string_t cmd_get_filter_swap_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_get_filter_swap_result,
+		get_filter_swap, "get_filter_swap");
+cmdline_parse_token_num_t cmd_get_filter_swap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_get_filter_swap_result,
+		port_id, UINT8);
+cmdline_parse_token_num_t cmd_get_filter_swap_pctype =
+	TOKEN_NUM_INITIALIZER(struct cmd_get_filter_swap_result,
+		pctype, UINT8);
+
+cmdline_parse_inst_t cmd_get_filter_swap = {
+	.f = cmd_get_filter_swap_parsed,
+	.data = NULL,
+	.help_str = "get_filter_swap port_id pctype",
+	.tokens = {
+		(void *)&cmd_get_filter_swap_all,
+		(void *)&cmd_get_filter_swap_port_id,
+		(void *)&cmd_get_filter_swap_pctype,
+		NULL,
+	},
+};
+
+/* *** Set filter swap *** */
+struct cmd_set_filter_swap_result {
+	cmdline_fixed_string_t set_filter_swap;
+	uint8_t port_id;
+	uint8_t pctype;
+	uint8_t off0_src0;
+	uint8_t off0_src1;
+	uint8_t len0;
+	uint8_t off1_src0;
+	uint8_t off1_src1;
+	uint8_t len1;
+};
+
+static void
+cmd_set_filter_swap_parsed(void *parsed_result,
+			   __rte_unused struct cmdline *cl,
+			   __rte_unused void *data)
+{
+	struct cmd_set_filter_swap_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port: %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP;
+	info.info.filter_swap.pctype = res->pctype;
+	info.info.filter_swap.off0_src0 = res->off0_src0;
+	info.info.filter_swap.off0_src1 = res->off0_src1;
+	info.info.filter_swap.len0 = res->len0;
+	info.info.filter_swap.off1_src0 = res->off1_src0;
+	info.info.filter_swap.off1_src1 = res->off1_src1;
+	info.info.filter_swap.len1 = res->len1;
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+					RTE_ETH_FILTER_OP_SET, &info);
+	if (ret < 0) {
+		printf("Cannot set filter swap on port %u, pctype %u\n",
+						res->port_id, res->pctype);
+		return;
+	}
+	printf("Filter swap of port %u, pctype %u has been set as:\n"
+		"off0_src0: 0x%02x, off0_src1: 0x%02x, len0: 0x%02x\n"
+		"off1_src0: 0x%02x, off1_src1: 0x%02x, len1: 0x%02x\n",
+		res->port_id, res->pctype, info.info.filter_swap.off0_src0,
+		info.info.filter_swap.off0_src1, info.info.filter_swap.len0,
+		info.info.filter_swap.off1_src0,
+		info.info.filter_swap.off1_src1, info.info.filter_swap.len1);
+}
+
+cmdline_parse_token_string_t cmd_set_filter_swap_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_filter_swap_result,
+		set_filter_swap, "set_filter_swap");
+cmdline_parse_token_num_t cmd_set_filter_swap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_filter_swap_result,
+		port_id, UINT8);
+cmdline_parse_token_num_t cmd_set_filter_swap_pctype =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_filter_swap_result,
+		pctype, UINT8);
+cmdline_parse_token_num_t cmd_set_filter_swap_off0_src0 =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_filter_swap_result,
+		off0_src0, UINT8);
+cmdline_parse_token_num_t cmd_set_filter_swap_off0_src1 =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_filter_swap_result,
+		off0_src1, UINT8);
+cmdline_parse_token_num_t cmd_set_filter_swap_len0 =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_filter_swap_result,
+		len0, UINT8);
+cmdline_parse_token_num_t cmd_set_filter_swap_off1_src0 =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_filter_swap_result,
+		off1_src0, UINT8);
+cmdline_parse_token_num_t cmd_set_filter_swap_off1_src1 =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_filter_swap_result,
+		off1_src1, UINT8);
+cmdline_parse_token_num_t cmd_set_filter_swap_len1 =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_filter_swap_result,
+		len1, UINT8);
+
+cmdline_parse_inst_t cmd_set_filter_swap = {
+	.f = cmd_set_filter_swap_parsed,
+	.data = NULL,
+	.help_str = "set_filter_swap port_id pctype off0_src0 off0_src1 "
+					"len0 off1_src0 off1_src1 len1",
+	.tokens = {
+		(void *)&cmd_set_filter_swap_all,
+		(void *)&cmd_set_filter_swap_port_id,
+		(void *)&cmd_set_filter_swap_pctype,
+		(void *)&cmd_set_filter_swap_off0_src0,
+		(void *)&cmd_set_filter_swap_off0_src1,
+		(void *)&cmd_set_filter_swap_len0,
+		(void *)&cmd_set_filter_swap_off1_src0,
+		(void *)&cmd_set_filter_swap_off1_src1,
+		(void *)&cmd_set_filter_swap_len1,
+		NULL,
+	},
+};
+
+/* Get hash function */
+struct cmd_get_hash_function_result {
+	cmdline_fixed_string_t get_hash_function;
+	uint8_t port_id;
+};
+
+static void
+cmd_get_hash_function_parsed(void *parsed_result,
+			     __rte_unused struct cmdline *cl,
+			     __rte_unused void *data)
+{
+	struct cmd_get_hash_function_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_INFO_TYPE_HASH_FUNCTION;
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+					RTE_ETH_FILTER_OP_GET, &info);
+	if (ret < 0) {
+		printf("Cannot get hash function on port %d\n", res->port_id);
+		return;
+	}
+	printf("Hash function is %s\n", info.info.hash_function ==
+		RTE_ETH_HASH_FUNCTION_TOEPLITZ ? "Toeplitz" : "Simple XOR");
+}
+
+cmdline_parse_token_string_t cmd_get_hash_function_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_get_hash_function_result,
+		get_hash_function, "get_hash_function");
+cmdline_parse_token_num_t cmd_get_hash_function_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_get_hash_function_result,
+		port_id, UINT8);
+
+cmdline_parse_inst_t cmd_get_hash_function = {
+	.f = cmd_get_hash_function_parsed,
+	.data = NULL,
+	.help_str = "get_hash_function port_id",
+	.tokens = {
+		(void *)&cmd_get_hash_function_all,
+		(void *)&cmd_get_hash_function_port_id,
+		NULL,
+	},
+};
+
+/* Set hash function of Hoeplitz or Simple XOR */
+struct cmd_set_hash_function_result {
+	cmdline_fixed_string_t set_hash_function;
+	uint8_t port_id;
+	cmdline_fixed_string_t hash_function;
+};
+
+static void
+cmd_set_hash_function_parsed(void *parsed_result,
+			     __rte_unused struct cmdline *cl,
+			     __rte_unused void *data)
+{
+	struct cmd_set_hash_function_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_INFO_TYPE_HASH_FUNCTION;
+	if (!strcmp(res->hash_function, "toeplitz"))
+		info.info.hash_function = RTE_ETH_HASH_FUNCTION_TOEPLITZ;
+	else if (!strcmp(res->hash_function, "simple_xor"))
+		info.info.hash_function = RTE_ETH_HASH_FUNCTION_SIMPLE_XOR;
+	else {
+		printf("Unsupported hash function %s\n", res->hash_function);
+		return;
+	}
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+					RTE_ETH_FILTER_OP_SET, &info);
+	if (ret < 0) {
+		printf("Cannot set hash function to %s on port %d\n",
+				res->hash_function, res->port_id);
+		return;
+	}
+	printf("Hash function has been successfully set to %s on port %d\n",
+					res->hash_function, res->port_id);
+}
+
+cmdline_parse_token_string_t cmd_set_hash_function_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_hash_function_result,
+		set_hash_function, "set_hash_function");
+cmdline_parse_token_num_t cmd_set_hash_function_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_hash_function_result,
+		port_id, UINT8);
+cmdline_parse_token_string_t cmd_set_hash_function_hash_function =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_hash_function_result,
+		hash_function, "toeplitz#simple_xor");
+
+cmdline_parse_inst_t cmd_set_hash_function = {
+	.f = cmd_set_hash_function_parsed,
+	.data = NULL,
+	.help_str = "set_hash_function port_id toeplitz|simple_xor",
+	.tokens = {
+		(void *)&cmd_set_hash_function_all,
+		(void *)&cmd_set_hash_function_port_id,
+		(void *)&cmd_set_hash_function_hash_function,
+		NULL,
+	},
+};
+
 /* ******************************************************************************** */
 
 /* list of instructions */
@@ -7541,6 +8099,14 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_add_flex_filter,
 	(cmdline_parse_inst_t *)&cmd_remove_flex_filter,
 	(cmdline_parse_inst_t *)&cmd_get_flex_filter,
+	(cmdline_parse_inst_t *)&cmd_get_sym_hash_ena_per_port,
+	(cmdline_parse_inst_t *)&cmd_set_sym_hash_ena_per_port,
+	(cmdline_parse_inst_t *)&cmd_get_sym_hash_ena_per_pctype,
+	(cmdline_parse_inst_t *)&cmd_set_sym_hash_ena_per_pctype,
+	(cmdline_parse_inst_t *)&cmd_get_filter_swap,
+	(cmdline_parse_inst_t *)&cmd_set_filter_swap,
+	(cmdline_parse_inst_t *)&cmd_set_hash_function,
+	(cmdline_parse_inst_t *)&cmd_get_hash_function,
 	NULL,
 };
 
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [dpdk-dev] [PATCH v4 4/7] i40e: add hash filter control implementation
  2014-10-13  6:12     ` [dpdk-dev] [PATCH v4 4/7] i40e: add hash filter control implementation Helin Zhang
@ 2014-10-13 10:23       ` Chilikin, Andrey
  2014-10-14  0:42         ` Zhang, Helin
  0 siblings, 1 reply; 71+ messages in thread
From: Chilikin, Andrey @ 2014-10-13 10:23 UTC (permalink / raw)
  To: Zhang, Helin, dev

Hi Helin,

Should we define packet classification types separately and do not reuse bit shifts for RSS register as pctypes?
Packet classification is a global index table which used by RSS Hash Enable registers, not vice versa.
For example, there is no Packet classification named "ETH_RSS_NONF_IPV4_UDP_SHIFT" in Table 7-15 of XL710 Datasheet,  it is  "PCTYPE_NONF_IPV4_UDP", so

switch (info->pctype) {
	case PCTYPE_NONF_IPV4_UDP:
	case PCTYPE_NONF_IPV4_TCP:
	...
Is more clean and readable for me than

switch (info->pctype) {
	case ETH_RSS_NONF_IPV4_UDP_SHIFT:
	case ETH_RSS_NONF_IPV4_TCP_SHIFT:

We can rerefine ETH_RSS_* using PCTYPE_* though:

#define ETH_RSS_NONF_IPV4_UDP_SHIFT PCTYPE_NONF_IPV4_UDP
and so one

Regards,
Andrey

-----Original Message-----
From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Helin Zhang
Sent: Monday, October 13, 2014 7:13 AM
To: dev@dpdk.org
Subject: [dpdk-dev] [PATCH v4 4/7] i40e: add hash filter control implementation

Hash filter control has been implemented for i40e. It includes getting/setting
- hash function type
- symmetric hash enable per pctype (packet classification type)
- symmetric hash enable per port
- filter swap configuration

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
---
 lib/librte_pmd_i40e/i40e_ethdev.c | 402 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 402 insertions(+)

diff --git a/lib/librte_pmd_i40e/i40e_ethdev.c b/lib/librte_pmd_i40e/i40e_ethdev.c
index 46c43a7..60b619b 100644
--- a/lib/librte_pmd_i40e/i40e_ethdev.c
+++ b/lib/librte_pmd_i40e/i40e_ethdev.c
@@ -216,6 +216,10 @@ static int i40e_dev_rss_hash_update(struct rte_eth_dev *dev,
 				    struct rte_eth_rss_conf *rss_conf);  static int i40e_dev_rss_hash_conf_get(struct rte_eth_dev *dev,
 				      struct rte_eth_rss_conf *rss_conf);
+static int i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
+				enum rte_filter_type filter_type,
+				enum rte_filter_op filter_op,
+				void *arg);
 
 /* Default hash key buffer for RSS */
 static uint32_t rss_key_default[I40E_PFQF_HKEY_MAX_INDEX + 1]; @@ -267,6 +271,7 @@ static struct eth_dev_ops i40e_eth_dev_ops = {
 	.reta_query                   = i40e_dev_rss_reta_query,
 	.rss_hash_update              = i40e_dev_rss_hash_update,
 	.rss_hash_conf_get            = i40e_dev_rss_hash_conf_get,
+	.filter_ctrl                  = i40e_dev_filter_ctrl,
 };
 
 static struct eth_driver rte_i40e_pmd = { @@ -4162,3 +4167,400 @@ i40e_pf_config_mq_rx(struct i40e_pf *pf)
 
 	return 0;
 }
+
+/* Get the symmetric hash enable configurations per PCTYPE */ static 
+int i40e_get_symmetric_hash_enable_per_pctype(struct i40e_hw *hw,
+			struct rte_eth_sym_hash_ena_info *info) {
+	uint32_t reg;
+
+	switch (info->pctype) {
+	case ETH_RSS_NONF_IPV4_UDP_SHIFT:
+	case ETH_RSS_NONF_IPV4_TCP_SHIFT:
+	case ETH_RSS_NONF_IPV4_SCTP_SHIFT:
+	case ETH_RSS_NONF_IPV4_OTHER_SHIFT:
+	case ETH_RSS_FRAG_IPV4_SHIFT:
+	case ETH_RSS_NONF_IPV6_UDP_SHIFT:
+	case ETH_RSS_NONF_IPV6_TCP_SHIFT:
+	case ETH_RSS_NONF_IPV6_SCTP_SHIFT:
+	case ETH_RSS_NONF_IPV6_OTHER_SHIFT:
+	case ETH_RSS_FRAG_IPV6_SHIFT:
+	case ETH_RSS_L2_PAYLOAD_SHIFT:
+		reg = I40E_READ_REG(hw, I40E_GLQF_HSYM(info->pctype));
+		info->enable = reg & I40E_GLQF_HSYM_SYMH_ENA_MASK ? 1 : 0;
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "PCTYPE[%u] not supported", info->pctype);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* Set the symmetric hash enable configurations per PCTYPE */ static 
+int i40e_set_symmetric_hash_enable_per_pctype(struct i40e_hw *hw,
+		const struct rte_eth_sym_hash_ena_info *info) {
+	uint32_t reg;
+
+	switch (info->pctype) {
+	case ETH_RSS_NONF_IPV4_UDP_SHIFT:
+	case ETH_RSS_NONF_IPV4_TCP_SHIFT:
+	case ETH_RSS_NONF_IPV4_SCTP_SHIFT:
+	case ETH_RSS_NONF_IPV4_OTHER_SHIFT:
+	case ETH_RSS_FRAG_IPV4_SHIFT:
+	case ETH_RSS_NONF_IPV6_UDP_SHIFT:
+	case ETH_RSS_NONF_IPV6_TCP_SHIFT:
+	case ETH_RSS_NONF_IPV6_SCTP_SHIFT:
+	case ETH_RSS_NONF_IPV6_OTHER_SHIFT:
+	case ETH_RSS_FRAG_IPV6_SHIFT:
+	case ETH_RSS_L2_PAYLOAD_SHIFT:
+		reg = info->enable ? I40E_GLQF_HSYM_SYMH_ENA_MASK : 0;
+		I40E_WRITE_REG(hw, I40E_GLQF_HSYM(info->pctype), reg);
+		I40E_WRITE_FLUSH(hw);
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "PCTYPE[%u] not supported", info->pctype);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* Get the symmetric hash enable configurations per port */ static void 
+i40e_get_symmetric_hash_enable_per_port(struct i40e_hw *hw, uint8_t 
+*enable) {
+	uint32_t reg = I40E_READ_REG(hw, I40E_PRTQF_CTL_0);
+
+	*enable = reg & I40E_PRTQF_CTL_0_HSYM_ENA_MASK ? 1 : 0; }
+
+/* Set the symmetric hash enable configurations per port */ static void 
+i40e_set_symmetric_hash_enable_per_port(struct i40e_hw *hw, uint8_t 
+enable) {
+	uint32_t reg = I40E_READ_REG(hw, I40E_PRTQF_CTL_0);
+
+	if (enable > 0) {
+		if (reg & I40E_PRTQF_CTL_0_HSYM_ENA_MASK) {
+			PMD_DRV_LOG(INFO, "Symmetric hash has already "
+							"been enabled");
+			return;
+		}
+		reg |= I40E_PRTQF_CTL_0_HSYM_ENA_MASK;
+	} else {
+		if (!(reg & I40E_PRTQF_CTL_0_HSYM_ENA_MASK)) {
+			PMD_DRV_LOG(INFO, "Symmetric hash has already "
+							"been disabled");
+			return;
+		}
+		reg &= ~I40E_PRTQF_CTL_0_HSYM_ENA_MASK;
+	}
+	I40E_WRITE_REG(hw, I40E_PRTQF_CTL_0, reg);
+	I40E_WRITE_FLUSH(hw);
+}
+
+/* Get filter swap configurations */
+static int
+i40e_get_filter_swap(struct i40e_hw *hw, struct 
+rte_eth_filter_swap_info *info) {
+	uint32_t reg;
+
+	switch (info->pctype) {
+	case ETH_RSS_NONF_IPV4_UDP_SHIFT:
+	case ETH_RSS_NONF_IPV4_TCP_SHIFT:
+	case ETH_RSS_NONF_IPV4_SCTP_SHIFT:
+	case ETH_RSS_NONF_IPV4_OTHER_SHIFT:
+	case ETH_RSS_FRAG_IPV4_SHIFT:
+	case ETH_RSS_NONF_IPV6_UDP_SHIFT:
+	case ETH_RSS_NONF_IPV6_TCP_SHIFT:
+	case ETH_RSS_NONF_IPV6_SCTP_SHIFT:
+	case ETH_RSS_NONF_IPV6_OTHER_SHIFT:
+	case ETH_RSS_FRAG_IPV6_SHIFT:
+	case ETH_RSS_L2_PAYLOAD_SHIFT:
+		reg = I40E_READ_REG(hw, I40E_GLQF_SWAP(0, info->pctype));
+		PMD_DRV_LOG(DEBUG, "Value read from I40E_GLQF_SWAP[0,%d]: "
+						"0x%x", info->pctype, reg);
+
+		/**
+		 * The offset and length read from register in word unit,
+		 * which need to be converted in byte unit before being saved.
+		 */
+		info->off0_src0 =
+			(uint8_t)((reg & I40E_GLQF_SWAP_OFF0_SRC0_MASK) >>
+					I40E_GLQF_SWAP_OFF0_SRC0_SHIFT) << 1;
+		info->off0_src1 =
+			(uint8_t)((reg & I40E_GLQF_SWAP_OFF0_SRC1_MASK) >>
+					I40E_GLQF_SWAP_OFF0_SRC1_SHIFT) << 1;
+		info->len0 = (uint8_t)((reg & I40E_GLQF_SWAP_FLEN0_MASK) >>
+					I40E_GLQF_SWAP_FLEN0_SHIFT) << 1;
+		info->off1_src0 =
+			(uint8_t)((reg & I40E_GLQF_SWAP_OFF1_SRC0_MASK) >>
+					I40E_GLQF_SWAP_OFF1_SRC0_SHIFT) << 1;
+		info->off1_src1 =
+			(uint8_t)((reg & I40E_GLQF_SWAP_OFF1_SRC1_MASK) >>
+					I40E_GLQF_SWAP_OFF1_SRC1_SHIFT) << 1;
+		info->len1 = (uint8_t)((reg & I40E_GLQF_SWAP_FLEN1_MASK) >>
+					I40E_GLQF_SWAP_FLEN1_SHIFT) << 1;
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "PCTYPE[%u] not supported", info->pctype);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* Set filter swap configurations */
+static int
+i40e_set_filter_swap(struct i40e_hw *hw,
+		     const struct rte_eth_filter_swap_info *info) { #define 
+I40E_FIELD_LEN_MAX 0x1f #define I40E_FIELD_OFFSET_MAX 0x7f
+	uint32_t reg;
+
+	switch (info->pctype) {
+	case ETH_RSS_NONF_IPV4_UDP_SHIFT:
+	case ETH_RSS_NONF_IPV4_TCP_SHIFT:
+	case ETH_RSS_NONF_IPV4_SCTP_SHIFT:
+	case ETH_RSS_NONF_IPV4_OTHER_SHIFT:
+	case ETH_RSS_FRAG_IPV4_SHIFT:
+	case ETH_RSS_NONF_IPV6_UDP_SHIFT:
+	case ETH_RSS_NONF_IPV6_TCP_SHIFT:
+	case ETH_RSS_NONF_IPV6_SCTP_SHIFT:
+	case ETH_RSS_NONF_IPV6_OTHER_SHIFT:
+	case ETH_RSS_FRAG_IPV6_SHIFT:
+	case ETH_RSS_L2_PAYLOAD_SHIFT:
+		if (info->off0_src0 > I40E_FIELD_OFFSET_MAX) {
+			PMD_DRV_LOG(ERR, "off0_src0 (0x%x) exceeds the "
+				"maximum of 0x%x", info->off0_src0,
+						I40E_FIELD_OFFSET_MAX);
+			return I40E_ERR_PARAM;
+		} else if (info->off0_src1 > I40E_FIELD_OFFSET_MAX) {
+			PMD_DRV_LOG(ERR, "off0_src1 (0x%x) exceeds the "
+				"maximum of 0x%x", info->off0_src1,
+						I40E_FIELD_OFFSET_MAX);
+			return I40E_ERR_PARAM;
+		} else if (info->len0 > I40E_FIELD_LEN_MAX) {
+			PMD_DRV_LOG(ERR, "len0 (0x%x) exceeds the maximum "
+				"of 0x%x", info->len0, I40E_FIELD_LEN_MAX);
+			return I40E_ERR_PARAM;
+		} else if (info->off1_src0 > I40E_FIELD_OFFSET_MAX) {
+			PMD_DRV_LOG(ERR, "off1_src0 (0x%x) exceeds the "
+				"maximum of 0x%x", info->off1_src0,
+						I40E_FIELD_OFFSET_MAX);
+			return I40E_ERR_PARAM;
+		} else if (info->off1_src1 > I40E_FIELD_OFFSET_MAX) {
+			PMD_DRV_LOG(ERR, "off1_src1 (0x%x) exceeds the "
+				"maximum of 0x%x", info->off1_src1,
+						I40E_FIELD_OFFSET_MAX);
+			return I40E_ERR_PARAM;
+		} else if (info->len1 > I40E_FIELD_LEN_MAX) {
+			PMD_DRV_LOG(ERR, "len1 (0x%x) exceeds the maximum "
+				"of 0x%x", info->len1, I40E_FIELD_LEN_MAX);
+			return I40E_ERR_PARAM;
+		}
+
+		/**
+		 * The offset and length given in byte unit, which need to be
+		 * converted in word unit before being written to the register,
+		 * as hardware requires it in word unit.
+		 */
+		reg = (info->off0_src0 >> 1) << I40E_GLQF_SWAP_OFF0_SRC0_SHIFT;
+		reg |= (info->off0_src1 >> 1) <<
+			I40E_GLQF_SWAP_OFF0_SRC1_SHIFT;
+		reg |= (info->len0 >> 1) << I40E_GLQF_SWAP_FLEN0_SHIFT;
+		reg |= (info->off1_src0 >> 1) <<
+			I40E_GLQF_SWAP_OFF1_SRC0_SHIFT;
+		reg |= (info->off1_src1 >> 1) <<
+			I40E_GLQF_SWAP_OFF1_SRC1_SHIFT;
+		reg |= (info->len1 >> 1) << I40E_GLQF_SWAP_FLEN1_SHIFT;
+
+		PMD_DRV_LOG(DEBUG, "Value to be written to "
+			"I40E_GLQF_SWAP[0,%d]: 0x%x", info->pctype, reg);
+		I40E_WRITE_REG(hw, I40E_GLQF_SWAP(0, info->pctype), reg);
+		I40E_WRITE_FLUSH(hw);
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "PCTYPE[%u] not supported", info->pctype);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* Get hash function type */
+static void
+i40e_get_hash_function(struct i40e_hw *hw, enum rte_eth_hash_function 
+*hf) {
+	uint32_t reg = I40E_READ_REG(hw, I40E_GLQF_CTL);
+
+	if (reg & I40E_GLQF_CTL_HTOEP_MASK)
+		*hf = RTE_ETH_HASH_FUNCTION_TOEPLITZ;
+	else
+		*hf = RTE_ETH_HASH_FUNCTION_SIMPLE_XOR;
+
+	PMD_DRV_LOG(INFO, "Hash function is %s",
+		(reg & I40E_GLQF_CTL_HTOEP_MASK) ? "Toeplitz" : "Simple XOR"); }
+
+/* Set hash function type */
+static int
+i40e_set_hash_function(struct i40e_hw *hw, enum rte_eth_hash_function 
+hf) {
+	uint32_t reg = I40E_READ_REG(hw, I40E_GLQF_CTL);
+
+	if (hf == RTE_ETH_HASH_FUNCTION_TOEPLITZ) {
+		if (reg & I40E_GLQF_CTL_HTOEP_MASK) {
+			PMD_DRV_LOG(DEBUG, "Hash function already set to "
+								"Toeplitz");
+			return 0;
+		}
+		reg |= I40E_GLQF_CTL_HTOEP_MASK;
+	} else if (hf == RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) {
+		if (!(reg & I40E_GLQF_CTL_HTOEP_MASK)) {
+			PMD_DRV_LOG(DEBUG, "Hash function already set to "
+							"Simple XOR");
+			return 0;
+		}
+		reg &= ~I40E_GLQF_CTL_HTOEP_MASK;
+	} else {
+		PMD_DRV_LOG(ERR, "Unknown hash function type");
+		return -EINVAL;
+	}
+
+	PMD_DRV_LOG(INFO, "Hash function set to %s",
+		(reg & I40E_GLQF_CTL_HTOEP_MASK) ? "Toeplitz" : "Simple XOR");
+	I40E_WRITE_REG(hw, I40E_GLQF_CTL, reg);
+	I40E_WRITE_FLUSH(hw);
+
+	return 0;
+}
+
+static int
+i40e_hash_filter_get(struct i40e_hw *hw, struct 
+rte_eth_hash_filter_info *info) {
+	int ret = 0;
+
+	if (!hw || !info) {
+		PMD_DRV_LOG(ERR, "Invalid pointer");
+		return -EFAULT;
+	}
+
+	switch (info->info_type) {
+	case RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PCTYPE:
+		ret = i40e_get_symmetric_hash_enable_per_pctype(hw,
+					&(info->info.sym_hash_ena));
+		break;
+	case RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PORT:
+		i40e_get_symmetric_hash_enable_per_port(hw,
+					&(info->info.enable));
+		break;
+	case RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP:
+		ret = i40e_get_filter_swap(hw, &(info->info.filter_swap));
+		break;
+	case RTE_ETH_HASH_FILTER_INFO_TYPE_HASH_FUNCTION:
+		i40e_get_hash_function(hw, &(info->info.hash_function));
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "Hash filter info type (%d) not supported",
+							info->info_type);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int
+i40e_hash_filter_set(struct i40e_hw *hw, struct 
+rte_eth_hash_filter_info *info) {
+	int ret = 0;
+
+	if (!hw || !info) {
+		PMD_DRV_LOG(ERR, "Invalid pointer");
+		return -EFAULT;
+	}
+
+	switch (info->info_type) {
+	case RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PCTYPE:
+		ret = i40e_set_symmetric_hash_enable_per_pctype(hw,
+					&(info->info.sym_hash_ena));
+		break;
+	case RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PORT:
+		i40e_set_symmetric_hash_enable_per_port(hw, info->info.enable);
+		break;
+	case RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP:
+		ret = i40e_set_filter_swap(hw, &(info->info.filter_swap));
+		break;
+	case RTE_ETH_HASH_FILTER_INFO_TYPE_HASH_FUNCTION:
+		ret = i40e_set_hash_function(hw, info->info.hash_function);
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "Hash filter info type (%d) not supported",
+							info->info_type);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+/* Operations for hash function */
+static int
+i40e_hash_filter_ctrl(struct rte_eth_dev *dev,
+		      enum rte_filter_op filter_op,
+		      void *arg)
+{
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	int ret = 0;
+
+	switch (filter_op) {
+	case RTE_ETH_FILTER_OP_NONE:
+		break;
+	case RTE_ETH_FILTER_OP_GET:
+		ret = i40e_hash_filter_get(hw,
+			(struct rte_eth_hash_filter_info *)arg);
+		break;
+	case RTE_ETH_FILTER_OP_SET:
+		ret = i40e_hash_filter_set(hw,
+			(struct rte_eth_hash_filter_info *)arg);
+		break;
+	default:
+		PMD_DRV_LOG(WARNING, "Filter operation (%d) not supported",
+								filter_op);
+		ret = -ENOTSUP;
+		break;
+	}
+
+	return ret;
+}
+
+static int
+i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
+		     enum rte_filter_type filter_type,
+		     enum rte_filter_op filter_op,
+		     void *arg)
+{
+	int ret = -ENOTSUP;
+
+	switch (filter_type) {
+	case RTE_ETH_FILTER_HASH:
+		ret = i40e_hash_filter_ctrl(dev, filter_op, arg);
+		break;
+	case RTE_ETH_FILTER_FDIR:
+		break;
+	case RTE_ETH_FILTER_TUNNEL:
+		break;
+	default:
+		PMD_DRV_LOG(WARNING, "Filter type (%d) not supported",
+							filter_type);
+		break;
+	}
+
+	return ret;
+}
--
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [dpdk-dev] [PATCH v4 0/7] Support configuring hash functions
  2014-10-13  6:12   ` [dpdk-dev] [PATCH v4 0/7] Support configuring hash functions Helin Zhang
                       ` (6 preceding siblings ...)
  2014-10-13  6:12     ` [dpdk-dev] [PATCH v4 7/7] app/testpmd: add commands to support hash filter control Helin Zhang
@ 2014-10-13 12:27     ` Zhan, Zhaochen
  2014-10-14  3:32     ` Wu, Jingjing
  2014-10-21  3:14     ` [dpdk-dev] [PATCH v5 0/5] " Helin Zhang
  9 siblings, 0 replies; 71+ messages in thread
From: Zhan, Zhaochen @ 2014-10-13 12:27 UTC (permalink / raw)
  To: Zhang, Helin, dev

> These patches mainly support configuring hash functions.

Tested-by: Zhaochen Zhan <zhaochen.zhan@intel.com>

This patch has been verified on three kinds of Fortville NICs.

Base commit: 23fcffe8ffaccf8a2901050e7daa4979597141ed
CPU: Intel(R) Xeon(R) CPU E5-2680 v2 @ 2.80GHz
OS: Linux fc20 3.11.10-301.fc20.x86_64
GCC: 4.8.2
NIC: 4*10G(fortville_eagle), 2*40G(fortville_spirit), 1*40G(fortville_spirit_single)

==================================================================
Fortville RSS full support - Support configuring hash functions
==================================================================
This document provides test plan for testing the function of Fortville:
Support configuring hash functions.

Prerequisites
-------------
2x Intel(r) 82599 (Niantic) NICs (2x 10GbE full duplex optical ports per NIC)
1x Fortville_eagle NIC (4x 10G)
1x Fortville_spirit NIC (2x 40G)
2x Fortville_spirit_single NIC (1x 40G)

The four ports of the 82599 connect to the Fortville_eagle;
The two ports of Fortville_spirit connect to Fortville_spirit_single.
The three kinds of NICs are the target NICs. the connected NICs can send packets
to these three NICs using scapy.

Network Traffic
---------------
The RSS feature is designed to improve networking performance by load balancing
the packets received from a NIC port to multiple NIC RX queues, with each queue
handled by a different logical core.

#1. The receive packet is parsed into the header fields used by the hash
operation (such as IP addresses, TCP port, etc.)

#2. A hash calculation is performed. The Fortville  supports four hash function:
Toeplitz, simple XOR and their Symmetric RSS.

#3. The seven LSBs of the hash result are used as an index into a 128/512 entry
'redirection table'. Each entry provides a 4-bit RSS output index.

#4. There are four cases to test the four hash function.

Test Case:  test_toeplitz
=========================

Testpmd configuration - 16 RX/TX queues per port
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#1. set up testpmd with fortville NICs::
  ./testpmd -c fffff -n %d -- -i --coremask=0xffffe --rxq=16 --txq=16

#2. Reta Configuration.  128 reta entries configuration::
  testpmd command: port config 0 rss reta (hash_index,queue_id)

#3. PMD fwd only receive the packets::
  testpmd command: set fwd rxonly

#4. rss received package type configuration two received packet types configuration::
  testpmd command: port config 0 rss ip/udp

#5. verbose configuration::
  testpmd command: set verbose 8

#6. set hash functions, can choose symmetric or not, chose port and packet type::
  set_hash_function 0 toeplitz

#7. start packet receive::
  testpmd command: start

tester Configuration
--------------------

#1. set up scapy

#2. send packets with different type ipv4/ipv4 with tcp/ipv4 with udp/
    ipv6/ipv6 with tcp/ipv6 with udp::
    sendp([Ether(dst="90:e2:ba:36:99:3c")/IP(src="192.168.0.4", dst="192.168.0.5")], iface="eth3")

test result
-----------
The testpmd will print the hash value and actual queue of every packet.

#1. Calaute the queue id: hash value%128or512, then refer to the redirection table
    to get the theoretical queue id.

#2. Compare the theoretical queue id with the actual queue id. 

Test Case:  test_toeplitz_symmetric
===================================
The same with the above steps, pay attention to "set hash function", should use::
  set_hash_function 0 toeplitz
  set_sym_hash_ena_per_port 0 enable
  set_sym_hash_ena_per_pctype 0 35 enable

And send packets with the same flow in different direction::
  sendp([Ether(dst="90:e2:ba:36:99:3c")/IP(src="192.168.0.4", dst="192.168.0.5")], iface="eth3")
  sendp([Ether(dst="90:e2:ba:36:99:3c")/IP(src="192.168.0.5", dst="192.168.0.4")], iface="eth3")

And the hash value and queue should be the same for these two flow .

Test Case:  test_simple
=======================
The same as the above two test cases. Just pay attention to set the hash function to "simple xor"

Test Case:  test_simple_symmetric
=================================
The same as the above two test cases. Just pay attention to set the hash function to "simple xor"

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [dpdk-dev] [PATCH v4 4/7] i40e: add hash filter control implementation
  2014-10-13 10:23       ` Chilikin, Andrey
@ 2014-10-14  0:42         ` Zhang, Helin
  0 siblings, 0 replies; 71+ messages in thread
From: Zhang, Helin @ 2014-10-14  0:42 UTC (permalink / raw)
  To: Chilikin, Andrey, dev

Hi Andrey

Yes, you are right. Actually I tried to rename those macros to more readable. For now, I'd like to put those renaming into another patches after all current feature patches merged. Thank you very much!

Regards,
Helin

> -----Original Message-----
> From: Chilikin, Andrey
> Sent: Monday, October 13, 2014 6:23 PM
> To: Zhang, Helin; dev@dpdk.org
> Subject: RE: [dpdk-dev] [PATCH v4 4/7] i40e: add hash filter control
> implementation
> 
> Hi Helin,
> 
> Should we define packet classification types separately and do not reuse bit
> shifts for RSS register as pctypes?
> Packet classification is a global index table which used by RSS Hash Enable
> registers, not vice versa.
> For example, there is no Packet classification named
> "ETH_RSS_NONF_IPV4_UDP_SHIFT" in Table 7-15 of XL710 Datasheet,  it is
> "PCTYPE_NONF_IPV4_UDP", so
> 
> switch (info->pctype) {
> 	case PCTYPE_NONF_IPV4_UDP:
> 	case PCTYPE_NONF_IPV4_TCP:
> 	...
> Is more clean and readable for me than
> 
> switch (info->pctype) {
> 	case ETH_RSS_NONF_IPV4_UDP_SHIFT:
> 	case ETH_RSS_NONF_IPV4_TCP_SHIFT:
> 
> We can rerefine ETH_RSS_* using PCTYPE_* though:
> 
> #define ETH_RSS_NONF_IPV4_UDP_SHIFT PCTYPE_NONF_IPV4_UDP and so
> one
> 
> Regards,
> Andrey
> 
> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Helin Zhang
> Sent: Monday, October 13, 2014 7:13 AM
> To: dev@dpdk.org
> Subject: [dpdk-dev] [PATCH v4 4/7] i40e: add hash filter control implementation
> 
> Hash filter control has been implemented for i40e. It includes getting/setting
> - hash function type
> - symmetric hash enable per pctype (packet classification type)
> - symmetric hash enable per port
> - filter swap configuration
> 
> Signed-off-by: Helin Zhang <helin.zhang@intel.com>
> ---
>  lib/librte_pmd_i40e/i40e_ethdev.c | 402
> ++++++++++++++++++++++++++++++++++++++
>  1 file changed, 402 insertions(+)
> 
> diff --git a/lib/librte_pmd_i40e/i40e_ethdev.c
> b/lib/librte_pmd_i40e/i40e_ethdev.c
> index 46c43a7..60b619b 100644
> --- a/lib/librte_pmd_i40e/i40e_ethdev.c
> +++ b/lib/librte_pmd_i40e/i40e_ethdev.c
> @@ -216,6 +216,10 @@ static int i40e_dev_rss_hash_update(struct
> rte_eth_dev *dev,
>  				    struct rte_eth_rss_conf *rss_conf);  static int
> i40e_dev_rss_hash_conf_get(struct rte_eth_dev *dev,
>  				      struct rte_eth_rss_conf *rss_conf);
> +static int i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
> +				enum rte_filter_type filter_type,
> +				enum rte_filter_op filter_op,
> +				void *arg);
> 
>  /* Default hash key buffer for RSS */
>  static uint32_t rss_key_default[I40E_PFQF_HKEY_MAX_INDEX + 1]; @@
> -267,6 +271,7 @@ static struct eth_dev_ops i40e_eth_dev_ops = {
>  	.reta_query                   = i40e_dev_rss_reta_query,
>  	.rss_hash_update              = i40e_dev_rss_hash_update,
>  	.rss_hash_conf_get            = i40e_dev_rss_hash_conf_get,
> +	.filter_ctrl                  = i40e_dev_filter_ctrl,
>  };
> 
>  static struct eth_driver rte_i40e_pmd = { @@ -4162,3 +4167,400 @@
> i40e_pf_config_mq_rx(struct i40e_pf *pf)
> 
>  	return 0;
>  }
> +
> +/* Get the symmetric hash enable configurations per PCTYPE */ static
> +int i40e_get_symmetric_hash_enable_per_pctype(struct i40e_hw *hw,
> +			struct rte_eth_sym_hash_ena_info *info) {
> +	uint32_t reg;
> +
> +	switch (info->pctype) {
> +	case ETH_RSS_NONF_IPV4_UDP_SHIFT:
> +	case ETH_RSS_NONF_IPV4_TCP_SHIFT:
> +	case ETH_RSS_NONF_IPV4_SCTP_SHIFT:
> +	case ETH_RSS_NONF_IPV4_OTHER_SHIFT:
> +	case ETH_RSS_FRAG_IPV4_SHIFT:
> +	case ETH_RSS_NONF_IPV6_UDP_SHIFT:
> +	case ETH_RSS_NONF_IPV6_TCP_SHIFT:
> +	case ETH_RSS_NONF_IPV6_SCTP_SHIFT:
> +	case ETH_RSS_NONF_IPV6_OTHER_SHIFT:
> +	case ETH_RSS_FRAG_IPV6_SHIFT:
> +	case ETH_RSS_L2_PAYLOAD_SHIFT:
> +		reg = I40E_READ_REG(hw, I40E_GLQF_HSYM(info->pctype));
> +		info->enable = reg & I40E_GLQF_HSYM_SYMH_ENA_MASK ? 1 : 0;
> +		break;
> +	default:
> +		PMD_DRV_LOG(ERR, "PCTYPE[%u] not supported", info->pctype);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +/* Set the symmetric hash enable configurations per PCTYPE */ static
> +int i40e_set_symmetric_hash_enable_per_pctype(struct i40e_hw *hw,
> +		const struct rte_eth_sym_hash_ena_info *info) {
> +	uint32_t reg;
> +
> +	switch (info->pctype) {
> +	case ETH_RSS_NONF_IPV4_UDP_SHIFT:
> +	case ETH_RSS_NONF_IPV4_TCP_SHIFT:
> +	case ETH_RSS_NONF_IPV4_SCTP_SHIFT:
> +	case ETH_RSS_NONF_IPV4_OTHER_SHIFT:
> +	case ETH_RSS_FRAG_IPV4_SHIFT:
> +	case ETH_RSS_NONF_IPV6_UDP_SHIFT:
> +	case ETH_RSS_NONF_IPV6_TCP_SHIFT:
> +	case ETH_RSS_NONF_IPV6_SCTP_SHIFT:
> +	case ETH_RSS_NONF_IPV6_OTHER_SHIFT:
> +	case ETH_RSS_FRAG_IPV6_SHIFT:
> +	case ETH_RSS_L2_PAYLOAD_SHIFT:
> +		reg = info->enable ? I40E_GLQF_HSYM_SYMH_ENA_MASK : 0;
> +		I40E_WRITE_REG(hw, I40E_GLQF_HSYM(info->pctype), reg);
> +		I40E_WRITE_FLUSH(hw);
> +		break;
> +	default:
> +		PMD_DRV_LOG(ERR, "PCTYPE[%u] not supported", info->pctype);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +/* Get the symmetric hash enable configurations per port */ static void
> +i40e_get_symmetric_hash_enable_per_port(struct i40e_hw *hw, uint8_t
> +*enable) {
> +	uint32_t reg = I40E_READ_REG(hw, I40E_PRTQF_CTL_0);
> +
> +	*enable = reg & I40E_PRTQF_CTL_0_HSYM_ENA_MASK ? 1 : 0; }
> +
> +/* Set the symmetric hash enable configurations per port */ static void
> +i40e_set_symmetric_hash_enable_per_port(struct i40e_hw *hw, uint8_t
> +enable) {
> +	uint32_t reg = I40E_READ_REG(hw, I40E_PRTQF_CTL_0);
> +
> +	if (enable > 0) {
> +		if (reg & I40E_PRTQF_CTL_0_HSYM_ENA_MASK) {
> +			PMD_DRV_LOG(INFO, "Symmetric hash has already "
> +							"been enabled");
> +			return;
> +		}
> +		reg |= I40E_PRTQF_CTL_0_HSYM_ENA_MASK;
> +	} else {
> +		if (!(reg & I40E_PRTQF_CTL_0_HSYM_ENA_MASK)) {
> +			PMD_DRV_LOG(INFO, "Symmetric hash has already "
> +							"been disabled");
> +			return;
> +		}
> +		reg &= ~I40E_PRTQF_CTL_0_HSYM_ENA_MASK;
> +	}
> +	I40E_WRITE_REG(hw, I40E_PRTQF_CTL_0, reg);
> +	I40E_WRITE_FLUSH(hw);
> +}
> +
> +/* Get filter swap configurations */
> +static int
> +i40e_get_filter_swap(struct i40e_hw *hw, struct
> +rte_eth_filter_swap_info *info) {
> +	uint32_t reg;
> +
> +	switch (info->pctype) {
> +	case ETH_RSS_NONF_IPV4_UDP_SHIFT:
> +	case ETH_RSS_NONF_IPV4_TCP_SHIFT:
> +	case ETH_RSS_NONF_IPV4_SCTP_SHIFT:
> +	case ETH_RSS_NONF_IPV4_OTHER_SHIFT:
> +	case ETH_RSS_FRAG_IPV4_SHIFT:
> +	case ETH_RSS_NONF_IPV6_UDP_SHIFT:
> +	case ETH_RSS_NONF_IPV6_TCP_SHIFT:
> +	case ETH_RSS_NONF_IPV6_SCTP_SHIFT:
> +	case ETH_RSS_NONF_IPV6_OTHER_SHIFT:
> +	case ETH_RSS_FRAG_IPV6_SHIFT:
> +	case ETH_RSS_L2_PAYLOAD_SHIFT:
> +		reg = I40E_READ_REG(hw, I40E_GLQF_SWAP(0, info->pctype));
> +		PMD_DRV_LOG(DEBUG, "Value read from I40E_GLQF_SWAP[0,%d]: "
> +						"0x%x", info->pctype, reg);
> +
> +		/**
> +		 * The offset and length read from register in word unit,
> +		 * which need to be converted in byte unit before being saved.
> +		 */
> +		info->off0_src0 =
> +			(uint8_t)((reg & I40E_GLQF_SWAP_OFF0_SRC0_MASK) >>
> +					I40E_GLQF_SWAP_OFF0_SRC0_SHIFT) << 1;
> +		info->off0_src1 =
> +			(uint8_t)((reg & I40E_GLQF_SWAP_OFF0_SRC1_MASK) >>
> +					I40E_GLQF_SWAP_OFF0_SRC1_SHIFT) << 1;
> +		info->len0 = (uint8_t)((reg & I40E_GLQF_SWAP_FLEN0_MASK) >>
> +					I40E_GLQF_SWAP_FLEN0_SHIFT) << 1;
> +		info->off1_src0 =
> +			(uint8_t)((reg & I40E_GLQF_SWAP_OFF1_SRC0_MASK) >>
> +					I40E_GLQF_SWAP_OFF1_SRC0_SHIFT) << 1;
> +		info->off1_src1 =
> +			(uint8_t)((reg & I40E_GLQF_SWAP_OFF1_SRC1_MASK) >>
> +					I40E_GLQF_SWAP_OFF1_SRC1_SHIFT) << 1;
> +		info->len1 = (uint8_t)((reg & I40E_GLQF_SWAP_FLEN1_MASK) >>
> +					I40E_GLQF_SWAP_FLEN1_SHIFT) << 1;
> +		break;
> +	default:
> +		PMD_DRV_LOG(ERR, "PCTYPE[%u] not supported", info->pctype);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +/* Set filter swap configurations */
> +static int
> +i40e_set_filter_swap(struct i40e_hw *hw,
> +		     const struct rte_eth_filter_swap_info *info) { #define
> +I40E_FIELD_LEN_MAX 0x1f #define I40E_FIELD_OFFSET_MAX 0x7f
> +	uint32_t reg;
> +
> +	switch (info->pctype) {
> +	case ETH_RSS_NONF_IPV4_UDP_SHIFT:
> +	case ETH_RSS_NONF_IPV4_TCP_SHIFT:
> +	case ETH_RSS_NONF_IPV4_SCTP_SHIFT:
> +	case ETH_RSS_NONF_IPV4_OTHER_SHIFT:
> +	case ETH_RSS_FRAG_IPV4_SHIFT:
> +	case ETH_RSS_NONF_IPV6_UDP_SHIFT:
> +	case ETH_RSS_NONF_IPV6_TCP_SHIFT:
> +	case ETH_RSS_NONF_IPV6_SCTP_SHIFT:
> +	case ETH_RSS_NONF_IPV6_OTHER_SHIFT:
> +	case ETH_RSS_FRAG_IPV6_SHIFT:
> +	case ETH_RSS_L2_PAYLOAD_SHIFT:
> +		if (info->off0_src0 > I40E_FIELD_OFFSET_MAX) {
> +			PMD_DRV_LOG(ERR, "off0_src0 (0x%x) exceeds the "
> +				"maximum of 0x%x", info->off0_src0,
> +						I40E_FIELD_OFFSET_MAX);
> +			return I40E_ERR_PARAM;
> +		} else if (info->off0_src1 > I40E_FIELD_OFFSET_MAX) {
> +			PMD_DRV_LOG(ERR, "off0_src1 (0x%x) exceeds the "
> +				"maximum of 0x%x", info->off0_src1,
> +						I40E_FIELD_OFFSET_MAX);
> +			return I40E_ERR_PARAM;
> +		} else if (info->len0 > I40E_FIELD_LEN_MAX) {
> +			PMD_DRV_LOG(ERR, "len0 (0x%x) exceeds the maximum "
> +				"of 0x%x", info->len0, I40E_FIELD_LEN_MAX);
> +			return I40E_ERR_PARAM;
> +		} else if (info->off1_src0 > I40E_FIELD_OFFSET_MAX) {
> +			PMD_DRV_LOG(ERR, "off1_src0 (0x%x) exceeds the "
> +				"maximum of 0x%x", info->off1_src0,
> +						I40E_FIELD_OFFSET_MAX);
> +			return I40E_ERR_PARAM;
> +		} else if (info->off1_src1 > I40E_FIELD_OFFSET_MAX) {
> +			PMD_DRV_LOG(ERR, "off1_src1 (0x%x) exceeds the "
> +				"maximum of 0x%x", info->off1_src1,
> +						I40E_FIELD_OFFSET_MAX);
> +			return I40E_ERR_PARAM;
> +		} else if (info->len1 > I40E_FIELD_LEN_MAX) {
> +			PMD_DRV_LOG(ERR, "len1 (0x%x) exceeds the maximum "
> +				"of 0x%x", info->len1, I40E_FIELD_LEN_MAX);
> +			return I40E_ERR_PARAM;
> +		}
> +
> +		/**
> +		 * The offset and length given in byte unit, which need to be
> +		 * converted in word unit before being written to the register,
> +		 * as hardware requires it in word unit.
> +		 */
> +		reg = (info->off0_src0 >> 1) << I40E_GLQF_SWAP_OFF0_SRC0_SHIFT;
> +		reg |= (info->off0_src1 >> 1) <<
> +			I40E_GLQF_SWAP_OFF0_SRC1_SHIFT;
> +		reg |= (info->len0 >> 1) << I40E_GLQF_SWAP_FLEN0_SHIFT;
> +		reg |= (info->off1_src0 >> 1) <<
> +			I40E_GLQF_SWAP_OFF1_SRC0_SHIFT;
> +		reg |= (info->off1_src1 >> 1) <<
> +			I40E_GLQF_SWAP_OFF1_SRC1_SHIFT;
> +		reg |= (info->len1 >> 1) << I40E_GLQF_SWAP_FLEN1_SHIFT;
> +
> +		PMD_DRV_LOG(DEBUG, "Value to be written to "
> +			"I40E_GLQF_SWAP[0,%d]: 0x%x", info->pctype, reg);
> +		I40E_WRITE_REG(hw, I40E_GLQF_SWAP(0, info->pctype), reg);
> +		I40E_WRITE_FLUSH(hw);
> +		break;
> +	default:
> +		PMD_DRV_LOG(ERR, "PCTYPE[%u] not supported", info->pctype);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +/* Get hash function type */
> +static void
> +i40e_get_hash_function(struct i40e_hw *hw, enum rte_eth_hash_function
> +*hf) {
> +	uint32_t reg = I40E_READ_REG(hw, I40E_GLQF_CTL);
> +
> +	if (reg & I40E_GLQF_CTL_HTOEP_MASK)
> +		*hf = RTE_ETH_HASH_FUNCTION_TOEPLITZ;
> +	else
> +		*hf = RTE_ETH_HASH_FUNCTION_SIMPLE_XOR;
> +
> +	PMD_DRV_LOG(INFO, "Hash function is %s",
> +		(reg & I40E_GLQF_CTL_HTOEP_MASK) ? "Toeplitz" : "Simple XOR"); }
> +
> +/* Set hash function type */
> +static int
> +i40e_set_hash_function(struct i40e_hw *hw, enum rte_eth_hash_function
> +hf) {
> +	uint32_t reg = I40E_READ_REG(hw, I40E_GLQF_CTL);
> +
> +	if (hf == RTE_ETH_HASH_FUNCTION_TOEPLITZ) {
> +		if (reg & I40E_GLQF_CTL_HTOEP_MASK) {
> +			PMD_DRV_LOG(DEBUG, "Hash function already set to "
> +								"Toeplitz");
> +			return 0;
> +		}
> +		reg |= I40E_GLQF_CTL_HTOEP_MASK;
> +	} else if (hf == RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) {
> +		if (!(reg & I40E_GLQF_CTL_HTOEP_MASK)) {
> +			PMD_DRV_LOG(DEBUG, "Hash function already set to "
> +							"Simple XOR");
> +			return 0;
> +		}
> +		reg &= ~I40E_GLQF_CTL_HTOEP_MASK;
> +	} else {
> +		PMD_DRV_LOG(ERR, "Unknown hash function type");
> +		return -EINVAL;
> +	}
> +
> +	PMD_DRV_LOG(INFO, "Hash function set to %s",
> +		(reg & I40E_GLQF_CTL_HTOEP_MASK) ? "Toeplitz" : "Simple XOR");
> +	I40E_WRITE_REG(hw, I40E_GLQF_CTL, reg);
> +	I40E_WRITE_FLUSH(hw);
> +
> +	return 0;
> +}
> +
> +static int
> +i40e_hash_filter_get(struct i40e_hw *hw, struct
> +rte_eth_hash_filter_info *info) {
> +	int ret = 0;
> +
> +	if (!hw || !info) {
> +		PMD_DRV_LOG(ERR, "Invalid pointer");
> +		return -EFAULT;
> +	}
> +
> +	switch (info->info_type) {
> +	case RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PCTYPE:
> +		ret = i40e_get_symmetric_hash_enable_per_pctype(hw,
> +					&(info->info.sym_hash_ena));
> +		break;
> +	case RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PORT:
> +		i40e_get_symmetric_hash_enable_per_port(hw,
> +					&(info->info.enable));
> +		break;
> +	case RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP:
> +		ret = i40e_get_filter_swap(hw, &(info->info.filter_swap));
> +		break;
> +	case RTE_ETH_HASH_FILTER_INFO_TYPE_HASH_FUNCTION:
> +		i40e_get_hash_function(hw, &(info->info.hash_function));
> +		break;
> +	default:
> +		PMD_DRV_LOG(ERR, "Hash filter info type (%d) not supported",
> +							info->info_type);
> +		ret = -EINVAL;
> +		break;
> +	}
> +
> +	return ret;
> +}
> +
> +static int
> +i40e_hash_filter_set(struct i40e_hw *hw, struct
> +rte_eth_hash_filter_info *info) {
> +	int ret = 0;
> +
> +	if (!hw || !info) {
> +		PMD_DRV_LOG(ERR, "Invalid pointer");
> +		return -EFAULT;
> +	}
> +
> +	switch (info->info_type) {
> +	case RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PCTYPE:
> +		ret = i40e_set_symmetric_hash_enable_per_pctype(hw,
> +					&(info->info.sym_hash_ena));
> +		break;
> +	case RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PORT:
> +		i40e_set_symmetric_hash_enable_per_port(hw, info->info.enable);
> +		break;
> +	case RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP:
> +		ret = i40e_set_filter_swap(hw, &(info->info.filter_swap));
> +		break;
> +	case RTE_ETH_HASH_FILTER_INFO_TYPE_HASH_FUNCTION:
> +		ret = i40e_set_hash_function(hw, info->info.hash_function);
> +		break;
> +	default:
> +		PMD_DRV_LOG(ERR, "Hash filter info type (%d) not supported",
> +							info->info_type);
> +		ret = -EINVAL;
> +		break;
> +	}
> +
> +	return ret;
> +}
> +
> +/* Operations for hash function */
> +static int
> +i40e_hash_filter_ctrl(struct rte_eth_dev *dev,
> +		      enum rte_filter_op filter_op,
> +		      void *arg)
> +{
> +	struct i40e_hw *hw =
> I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
> +	int ret = 0;
> +
> +	switch (filter_op) {
> +	case RTE_ETH_FILTER_OP_NONE:
> +		break;
> +	case RTE_ETH_FILTER_OP_GET:
> +		ret = i40e_hash_filter_get(hw,
> +			(struct rte_eth_hash_filter_info *)arg);
> +		break;
> +	case RTE_ETH_FILTER_OP_SET:
> +		ret = i40e_hash_filter_set(hw,
> +			(struct rte_eth_hash_filter_info *)arg);
> +		break;
> +	default:
> +		PMD_DRV_LOG(WARNING, "Filter operation (%d) not supported",
> +								filter_op);
> +		ret = -ENOTSUP;
> +		break;
> +	}
> +
> +	return ret;
> +}
> +
> +static int
> +i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
> +		     enum rte_filter_type filter_type,
> +		     enum rte_filter_op filter_op,
> +		     void *arg)
> +{
> +	int ret = -ENOTSUP;
> +
> +	switch (filter_type) {
> +	case RTE_ETH_FILTER_HASH:
> +		ret = i40e_hash_filter_ctrl(dev, filter_op, arg);
> +		break;
> +	case RTE_ETH_FILTER_FDIR:
> +		break;
> +	case RTE_ETH_FILTER_TUNNEL:
> +		break;
> +	default:
> +		PMD_DRV_LOG(WARNING, "Filter type (%d) not supported",
> +							filter_type);
> +		break;
> +	}
> +
> +	return ret;
> +}
> --
> 1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [dpdk-dev] [PATCH v4 0/7] Support configuring hash functions
  2014-10-13  6:12   ` [dpdk-dev] [PATCH v4 0/7] Support configuring hash functions Helin Zhang
                       ` (7 preceding siblings ...)
  2014-10-13 12:27     ` [dpdk-dev] [PATCH v4 0/7] Support configuring hash functions Zhan, Zhaochen
@ 2014-10-14  3:32     ` Wu, Jingjing
  2014-10-21  3:14     ` [dpdk-dev] [PATCH v5 0/5] " Helin Zhang
  9 siblings, 0 replies; 71+ messages in thread
From: Wu, Jingjing @ 2014-10-14  3:32 UTC (permalink / raw)
  To: Zhang, Helin, dev

Acked-by: Jingjing Wu <jingjing.wu@intel.com>

> -----Original Message-----
> From: Zhang, Helin
> Sent: Monday, October 13, 2014 2:13 PM
> To: dev@dpdk.org
> Cc: Zhan, Zhaochen; Cao, Waterman; Zhang, Helin
> Subject: [PATCH v4 0/7] Support configuring hash functions
> 
> These patches mainly support configuring hash functions.
> In detail,
>  - It can get or set hash functions.
>  - It can configure symmetric hash functions.
>    * Get/set symmetric hash enable per port.
>    * Get/set symmetric hash enable per 'PCTYPE'.
>    * Get/set filter swap configurations.
>  - 'ethdev' level interfaces are added.
>    * 'rte_eth_dev_filter_supported', to check if a filter control
>      is supported on a port.
>    * 'rte_eth_dev_filter_ctrl', a common API to execute
>      specific filter control.
>  - Six commands have been implemented in testpmd to support
>    testing above.
>    * get_sym_hash_ena_per_port
>    * set_sym_hash_ena_per_port
>    * get_sym_hash_ena_per_pctype
>    * set_sym_hash_ena_per_pctype
>    * get_filter_swap
>    * set_filter_swap
>    * get_hash_function
>    * set_hash_function
> 
> Note that 'PCTYPE' means 'Packet Classification Type'.
> 
> v4 changes:
> * Fixed a bug in testpmd to support 'set_sym_hash_ena_per_port'.
> 
> Helin Zhang (7):
>   ethdev: add more annotations
>   ethdev: add interfaces and relevant for filter control
>   ethdev: add structures and enum for hash filter control
>   i40e: add hash filter control implementation
>   i40e: add hardware initialization
>   i40e: Use constant random hash keys
>   app/testpmd: add commands to support hash filter control
> 
>  app/test-pmd/cmdline.c            | 566
> ++++++++++++++++++++++++++++++++++++++
>  lib/librte_ether/Makefile         |   1 +
>  lib/librte_ether/rte_eth_ctrl.h   | 154 +++++++++++
>  lib/librte_ether/rte_ethdev.c     |  32 +++
>  lib/librte_ether/rte_ethdev.h     |  53 +++-
>  lib/librte_pmd_i40e/i40e_ethdev.c | 492
> ++++++++++++++++++++++++++++++++-
>  6 files changed, 1291 insertions(+), 7 deletions(-)  create mode 100644
> lib/librte_ether/rte_eth_ctrl.h
> 
> --
> 1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v5 0/5] Support configuring hash functions
  2014-10-13  6:12   ` [dpdk-dev] [PATCH v4 0/7] Support configuring hash functions Helin Zhang
                       ` (8 preceding siblings ...)
  2014-10-14  3:32     ` Wu, Jingjing
@ 2014-10-21  3:14     ` Helin Zhang
  2014-10-21  3:14       ` [dpdk-dev] [PATCH v5 1/5] i40e: Use constant random hash keys Helin Zhang
                         ` (7 more replies)
  9 siblings, 8 replies; 71+ messages in thread
From: Helin Zhang @ 2014-10-21  3:14 UTC (permalink / raw)
  To: dev

These patches mainly support configuring hash functions.
In detail,
 - It can get or set hash functions.
 - It can configure symmetric hash functions.
   * Get/set symmetric hash enable per port.
   * Get/set symmetric hash enable per 'PCTYPE'.
   * Get/set filter swap configurations.
 - Six commands have been implemented in testpmd to support
   testing above.
   * get_sym_hash_ena_per_port
   * set_sym_hash_ena_per_port
   * get_sym_hash_ena_per_pctype
   * set_sym_hash_ena_per_pctype
   * get_filter_swap
   * set_filter_swap
   * get_hash_function
   * set_hash_function
Note that 'PCTYPE' means 'Packet Classification Type'.

It also uses prepared constant hash keys to replace runtime
generating hash keys. Global initialization is added to put
global registers to an initial state, as global registers
can be reset by global reset only.

v3 changes:
* Removed renamings in rte_ethdev.h.
* Redesigned filter control API and its relevant structures/enums.
* Renamed header file from rte_eth_features.h to rte_eth_ctrol.h.
* Remove public header file of rte_i40e.h specific for i40e.
* Added hardware initialization function during port init.
* Used constant random hash keys in i40e PF.
* renamed the commands in testpmd based on the redesigned filter
  control API.

v4 changes:
* Fixed a bug in testpmd to support 'set_sym_hash_ena_per_port'.

v5 changes:
* Integrated with filter API defined recently.
* Remove all for filter API definition, as it has already defined
  and merged recently.

Helin Zhang (5):
  i40e: Use constant random hash keys
  ethdev: add enum type and relevant structures for hash filter control
  i40e: add hash filter control implementation
  i40e: add hardware initialization
  app/testpmd: add commands to support hash filter

 app/test-pmd/cmdline.c            | 566 ++++++++++++++++++++++++++++++++++++++
 lib/librte_ether/rte_eth_ctrl.h   |  75 +++++
 lib/librte_pmd_i40e/i40e_ethdev.c | 467 ++++++++++++++++++++++++++++++-
 3 files changed, 1100 insertions(+), 8 deletions(-)

-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v5 1/5] i40e: Use constant random hash keys
  2014-10-21  3:14     ` [dpdk-dev] [PATCH v5 0/5] " Helin Zhang
@ 2014-10-21  3:14       ` Helin Zhang
  2014-11-03  7:49         ` Thomas Monjalon
  2014-10-21  3:14       ` [dpdk-dev] [PATCH v5 2/5] ethdev: add enum type and relevant structures for hash filter control Helin Zhang
                         ` (6 subsequent siblings)
  7 siblings, 1 reply; 71+ messages in thread
From: Helin Zhang @ 2014-10-21  3:14 UTC (permalink / raw)
  To: dev

To be simpler, and remove the race condition, it uses prepared
constant random hash keys to replace runtime generating the hash
keys.

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
---
 lib/librte_pmd_i40e/i40e_ethdev.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/lib/librte_pmd_i40e/i40e_ethdev.c b/lib/librte_pmd_i40e/i40e_ethdev.c
index 3b75f0f..5e5cfbe 100644
--- a/lib/librte_pmd_i40e/i40e_ethdev.c
+++ b/lib/librte_pmd_i40e/i40e_ethdev.c
@@ -191,9 +191,6 @@ static int i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
 				enum rte_filter_op filter_op,
 				void *arg);
 
-/* Default hash key buffer for RSS */
-static uint32_t rss_key_default[I40E_PFQF_HKEY_MAX_INDEX + 1];
-
 static struct rte_pci_id pci_id_i40e_map[] = {
 #define RTE_PCI_DEV_ID_DECL_I40E(vend, dev) {RTE_PCI_DEVICE(vend, dev)},
 #include "rte_pci_dev_ids.h"
@@ -4117,9 +4114,12 @@ i40e_pf_config_rss(struct i40e_pf *pf)
 	}
 	if (rss_conf.rss_key == NULL || rss_conf.rss_key_len <
 		(I40E_PFQF_HKEY_MAX_INDEX + 1) * sizeof(uint32_t)) {
-		/* Calculate the default hash key */
-		for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++)
-			rss_key_default[i] = (uint32_t)rte_rand();
+		/* Random default keys */
+		static uint32_t rss_key_default[] = {0x6b793944,
+			0x23504cb5, 0x5bea75b6, 0x309f4f12, 0x3dc0a2b8,
+			0x024ddcdf, 0x339b8ca0, 0x4c4af64a, 0x34fac605,
+			0x55d85839, 0x3a58997d, 0x2ec938e1, 0x66031581};
+
 		rss_conf.rss_key = (uint8_t *)rss_key_default;
 		rss_conf.rss_key_len = (I40E_PFQF_HKEY_MAX_INDEX + 1) *
 							sizeof(uint32_t);
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v5 2/5] ethdev: add enum type and relevant structures for hash filter control
  2014-10-21  3:14     ` [dpdk-dev] [PATCH v5 0/5] " Helin Zhang
  2014-10-21  3:14       ` [dpdk-dev] [PATCH v5 1/5] i40e: Use constant random hash keys Helin Zhang
@ 2014-10-21  3:14       ` Helin Zhang
  2014-11-03  7:57         ` Thomas Monjalon
  2014-10-21  3:14       ` [dpdk-dev] [PATCH v5 3/5] i40e: add hash filter control implementation Helin Zhang
                         ` (5 subsequent siblings)
  7 siblings, 1 reply; 71+ messages in thread
From: Helin Zhang @ 2014-10-21  3:14 UTC (permalink / raw)
  To: dev

enum type and relevant structures are added in rte_eth_ctrl.h to
support hash filter control.

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
---
 lib/librte_ether/rte_eth_ctrl.h | 75 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 75 insertions(+)

v5 changes:
* Integrated with filter API defined recently.

diff --git a/lib/librte_ether/rte_eth_ctrl.h b/lib/librte_ether/rte_eth_ctrl.h
index df21ac6..c469b57 100644
--- a/lib/librte_ether/rte_eth_ctrl.h
+++ b/lib/librte_ether/rte_eth_ctrl.h
@@ -51,6 +51,7 @@ extern "C" {
  */
 enum rte_filter_type {
 	RTE_ETH_FILTER_NONE = 0,
+	RTE_ETH_FILTER_HASH,
 	RTE_ETH_FILTER_MAX
 };
 
@@ -71,6 +72,80 @@ enum rte_filter_op {
 	RTE_ETH_FILTER_OP_MAX
 };
 
+/**
+ * Hash filter information types.
+ */
+enum rte_eth_hash_filter_info_type {
+	RTE_ETH_HASH_FILTER_INFO_TYPE_UNKNOWN = 0,
+	RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PCTYPE,
+	RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PORT,
+	RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP,
+	RTE_ETH_HASH_FILTER_INFO_TYPE_HASH_FUNCTION,
+	RTE_ETH_HASH_FILTER_INFO_TYPE_MAX,
+};
+
+/**
+ * Hash function types.
+ */
+enum rte_eth_hash_function {
+	RTE_ETH_HASH_FUNCTION_UNKNOWN = 0,
+	RTE_ETH_HASH_FUNCTION_TOEPLITZ,
+	RTE_ETH_HASH_FUNCTION_SIMPLE_XOR,
+	RTE_ETH_HASH_FUNCTION_MAX,
+};
+
+/**
+ * A structure used to set or get symmetric hash enable information, to support
+ * 'RTE_ETH_FILTER_HASH', 'RTE_ETH_FILTER_GET/RTE_ETH_FILTER_SET', with
+ * information type 'RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PCTYPE'.
+ */
+struct rte_eth_sym_hash_ena_info {
+	/**< packet classification type, defined in rte_ethdev.h */
+	uint8_t pctype;
+	uint8_t enable; /**< enable or disable flag */
+};
+
+/**
+ * A structure used to set or get filter swap information, to support
+ * 'RTE_ETH_FILTER_HASH', 'RTE_ETH_FILTER_GET/RTE_ETH_FILTER_SET',
+ * with information type 'RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP'.
+ */
+struct rte_eth_filter_swap_info {
+	/**< Packet classification type, defined in rte_ethdev.h */
+	uint8_t pctype;
+	/**< Offset of the 1st field of the 1st couple to be swapped. */
+	uint8_t off0_src0;
+	/**< Offset of the 2nd field of the 1st couple to be swapped. */
+	uint8_t off0_src1;
+	/**< Field length of the first couple. */
+	uint8_t len0;
+	/**< Offset of the 1st field of the 2nd couple to be swapped. */
+	uint8_t off1_src0;
+	/**< Offset of the 2nd field of the 2nd couple to be swapped. */
+	uint8_t off1_src1;
+	/**< Field length of the second couple. */
+	uint8_t len1;
+};
+
+/**
+ * A structure used to set or get hash filter information, to support filter
+ * type of 'RTE_ETH_FILTER_HASH' and its operations.
+ */
+struct rte_eth_hash_filter_info {
+	enum rte_eth_hash_filter_info_type info_type; /**< Information type. */
+	/**< Details of hash filter infomation */
+	union {
+		/* For RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PCTYPE */
+		struct rte_eth_sym_hash_ena_info sym_hash_ena;
+		/* For RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP */
+		struct rte_eth_filter_swap_info filter_swap;
+		/* For RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PORT */
+		uint8_t enable;
+		/* For RTE_ETH_HASH_FILTER_INFO_TYPE_HASH_FUNCTION */
+		enum rte_eth_hash_function hash_function;
+	} info;
+};
+
 #ifdef __cplusplus
 }
 #endif
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v5 3/5] i40e: add hash filter control implementation
  2014-10-21  3:14     ` [dpdk-dev] [PATCH v5 0/5] " Helin Zhang
  2014-10-21  3:14       ` [dpdk-dev] [PATCH v5 1/5] i40e: Use constant random hash keys Helin Zhang
  2014-10-21  3:14       ` [dpdk-dev] [PATCH v5 2/5] ethdev: add enum type and relevant structures for hash filter control Helin Zhang
@ 2014-10-21  3:14       ` Helin Zhang
  2014-10-21  3:14       ` [dpdk-dev] [PATCH v5 4/5] i40e: add hardware initialization Helin Zhang
                         ` (4 subsequent siblings)
  7 siblings, 0 replies; 71+ messages in thread
From: Helin Zhang @ 2014-10-21  3:14 UTC (permalink / raw)
  To: dev

Hash filter control has been implemented for i40e. It includes
getting/setting,
- hash function type
- symmetric hash enable per pctype (packet classification type)
- symmetric hash enable per port
- filter swap configuration

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
---
 lib/librte_pmd_i40e/i40e_ethdev.c | 377 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 375 insertions(+), 2 deletions(-)

v5 changes:
* Integrated with filter API defined recently.

diff --git a/lib/librte_pmd_i40e/i40e_ethdev.c b/lib/librte_pmd_i40e/i40e_ethdev.c
index 5e5cfbe..7531e3c 100644
--- a/lib/librte_pmd_i40e/i40e_ethdev.c
+++ b/lib/librte_pmd_i40e/i40e_ethdev.c
@@ -4145,6 +4145,378 @@ i40e_pf_config_mq_rx(struct i40e_pf *pf)
 	return 0;
 }
 
+/* Get the symmetric hash enable configurations per PCTYPE */
+static int
+i40e_get_symmetric_hash_enable_per_pctype(struct i40e_hw *hw,
+			struct rte_eth_sym_hash_ena_info *info)
+{
+	uint32_t reg;
+
+	switch (info->pctype) {
+	case ETH_RSS_NONF_IPV4_UDP_SHIFT:
+	case ETH_RSS_NONF_IPV4_TCP_SHIFT:
+	case ETH_RSS_NONF_IPV4_SCTP_SHIFT:
+	case ETH_RSS_NONF_IPV4_OTHER_SHIFT:
+	case ETH_RSS_FRAG_IPV4_SHIFT:
+	case ETH_RSS_NONF_IPV6_UDP_SHIFT:
+	case ETH_RSS_NONF_IPV6_TCP_SHIFT:
+	case ETH_RSS_NONF_IPV6_SCTP_SHIFT:
+	case ETH_RSS_NONF_IPV6_OTHER_SHIFT:
+	case ETH_RSS_FRAG_IPV6_SHIFT:
+	case ETH_RSS_L2_PAYLOAD_SHIFT:
+		reg = I40E_READ_REG(hw, I40E_GLQF_HSYM(info->pctype));
+		info->enable = reg & I40E_GLQF_HSYM_SYMH_ENA_MASK ? 1 : 0;
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "PCTYPE[%u] not supported", info->pctype);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* Set the symmetric hash enable configurations per PCTYPE */
+static int
+i40e_set_symmetric_hash_enable_per_pctype(struct i40e_hw *hw,
+		const struct rte_eth_sym_hash_ena_info *info)
+{
+	uint32_t reg;
+
+	switch (info->pctype) {
+	case ETH_RSS_NONF_IPV4_UDP_SHIFT:
+	case ETH_RSS_NONF_IPV4_TCP_SHIFT:
+	case ETH_RSS_NONF_IPV4_SCTP_SHIFT:
+	case ETH_RSS_NONF_IPV4_OTHER_SHIFT:
+	case ETH_RSS_FRAG_IPV4_SHIFT:
+	case ETH_RSS_NONF_IPV6_UDP_SHIFT:
+	case ETH_RSS_NONF_IPV6_TCP_SHIFT:
+	case ETH_RSS_NONF_IPV6_SCTP_SHIFT:
+	case ETH_RSS_NONF_IPV6_OTHER_SHIFT:
+	case ETH_RSS_FRAG_IPV6_SHIFT:
+	case ETH_RSS_L2_PAYLOAD_SHIFT:
+		reg = info->enable ? I40E_GLQF_HSYM_SYMH_ENA_MASK : 0;
+		I40E_WRITE_REG(hw, I40E_GLQF_HSYM(info->pctype), reg);
+		I40E_WRITE_FLUSH(hw);
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "PCTYPE[%u] not supported", info->pctype);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* Get the symmetric hash enable configurations per port */
+static void
+i40e_get_symmetric_hash_enable_per_port(struct i40e_hw *hw, uint8_t *enable)
+{
+	uint32_t reg = I40E_READ_REG(hw, I40E_PRTQF_CTL_0);
+
+	*enable = reg & I40E_PRTQF_CTL_0_HSYM_ENA_MASK ? 1 : 0;
+}
+
+/* Set the symmetric hash enable configurations per port */
+static void
+i40e_set_symmetric_hash_enable_per_port(struct i40e_hw *hw, uint8_t enable)
+{
+	uint32_t reg = I40E_READ_REG(hw, I40E_PRTQF_CTL_0);
+
+	if (enable > 0) {
+		if (reg & I40E_PRTQF_CTL_0_HSYM_ENA_MASK) {
+			PMD_DRV_LOG(INFO, "Symmetric hash has already "
+							"been enabled");
+			return;
+		}
+		reg |= I40E_PRTQF_CTL_0_HSYM_ENA_MASK;
+	} else {
+		if (!(reg & I40E_PRTQF_CTL_0_HSYM_ENA_MASK)) {
+			PMD_DRV_LOG(INFO, "Symmetric hash has already "
+							"been disabled");
+			return;
+		}
+		reg &= ~I40E_PRTQF_CTL_0_HSYM_ENA_MASK;
+	}
+	I40E_WRITE_REG(hw, I40E_PRTQF_CTL_0, reg);
+	I40E_WRITE_FLUSH(hw);
+}
+
+/* Get filter swap configurations */
+static int
+i40e_get_filter_swap(struct i40e_hw *hw, struct rte_eth_filter_swap_info *info)
+{
+	uint32_t reg;
+
+	switch (info->pctype) {
+	case ETH_RSS_NONF_IPV4_UDP_SHIFT:
+	case ETH_RSS_NONF_IPV4_TCP_SHIFT:
+	case ETH_RSS_NONF_IPV4_SCTP_SHIFT:
+	case ETH_RSS_NONF_IPV4_OTHER_SHIFT:
+	case ETH_RSS_FRAG_IPV4_SHIFT:
+	case ETH_RSS_NONF_IPV6_UDP_SHIFT:
+	case ETH_RSS_NONF_IPV6_TCP_SHIFT:
+	case ETH_RSS_NONF_IPV6_SCTP_SHIFT:
+	case ETH_RSS_NONF_IPV6_OTHER_SHIFT:
+	case ETH_RSS_FRAG_IPV6_SHIFT:
+	case ETH_RSS_L2_PAYLOAD_SHIFT:
+		reg = I40E_READ_REG(hw, I40E_GLQF_SWAP(0, info->pctype));
+		PMD_DRV_LOG(DEBUG, "Value read from I40E_GLQF_SWAP[0,%d]: "
+						"0x%x", info->pctype, reg);
+
+		/**
+		 * The offset and length read from register in word unit,
+		 * which need to be converted in byte unit before being saved.
+		 */
+		info->off0_src0 =
+			(uint8_t)((reg & I40E_GLQF_SWAP_OFF0_SRC0_MASK) >>
+					I40E_GLQF_SWAP_OFF0_SRC0_SHIFT) << 1;
+		info->off0_src1 =
+			(uint8_t)((reg & I40E_GLQF_SWAP_OFF0_SRC1_MASK) >>
+					I40E_GLQF_SWAP_OFF0_SRC1_SHIFT) << 1;
+		info->len0 = (uint8_t)((reg & I40E_GLQF_SWAP_FLEN0_MASK) >>
+					I40E_GLQF_SWAP_FLEN0_SHIFT) << 1;
+		info->off1_src0 =
+			(uint8_t)((reg & I40E_GLQF_SWAP_OFF1_SRC0_MASK) >>
+					I40E_GLQF_SWAP_OFF1_SRC0_SHIFT) << 1;
+		info->off1_src1 =
+			(uint8_t)((reg & I40E_GLQF_SWAP_OFF1_SRC1_MASK) >>
+					I40E_GLQF_SWAP_OFF1_SRC1_SHIFT) << 1;
+		info->len1 = (uint8_t)((reg & I40E_GLQF_SWAP_FLEN1_MASK) >>
+					I40E_GLQF_SWAP_FLEN1_SHIFT) << 1;
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "PCTYPE[%u] not supported", info->pctype);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* Set filter swap configurations */
+static int
+i40e_set_filter_swap(struct i40e_hw *hw,
+		     const struct rte_eth_filter_swap_info *info)
+{
+#define I40E_FIELD_LEN_MAX 0x1f
+#define I40E_FIELD_OFFSET_MAX 0x7f
+	uint32_t reg;
+
+	switch (info->pctype) {
+	case ETH_RSS_NONF_IPV4_UDP_SHIFT:
+	case ETH_RSS_NONF_IPV4_TCP_SHIFT:
+	case ETH_RSS_NONF_IPV4_SCTP_SHIFT:
+	case ETH_RSS_NONF_IPV4_OTHER_SHIFT:
+	case ETH_RSS_FRAG_IPV4_SHIFT:
+	case ETH_RSS_NONF_IPV6_UDP_SHIFT:
+	case ETH_RSS_NONF_IPV6_TCP_SHIFT:
+	case ETH_RSS_NONF_IPV6_SCTP_SHIFT:
+	case ETH_RSS_NONF_IPV6_OTHER_SHIFT:
+	case ETH_RSS_FRAG_IPV6_SHIFT:
+	case ETH_RSS_L2_PAYLOAD_SHIFT:
+		if (info->off0_src0 > I40E_FIELD_OFFSET_MAX) {
+			PMD_DRV_LOG(ERR, "off0_src0 (0x%x) exceeds the "
+				"maximum of 0x%x", info->off0_src0,
+						I40E_FIELD_OFFSET_MAX);
+			return I40E_ERR_PARAM;
+		} else if (info->off0_src1 > I40E_FIELD_OFFSET_MAX) {
+			PMD_DRV_LOG(ERR, "off0_src1 (0x%x) exceeds the "
+				"maximum of 0x%x", info->off0_src1,
+						I40E_FIELD_OFFSET_MAX);
+			return I40E_ERR_PARAM;
+		} else if (info->len0 > I40E_FIELD_LEN_MAX) {
+			PMD_DRV_LOG(ERR, "len0 (0x%x) exceeds the maximum "
+				"of 0x%x", info->len0, I40E_FIELD_LEN_MAX);
+			return I40E_ERR_PARAM;
+		} else if (info->off1_src0 > I40E_FIELD_OFFSET_MAX) {
+			PMD_DRV_LOG(ERR, "off1_src0 (0x%x) exceeds the "
+				"maximum of 0x%x", info->off1_src0,
+						I40E_FIELD_OFFSET_MAX);
+			return I40E_ERR_PARAM;
+		} else if (info->off1_src1 > I40E_FIELD_OFFSET_MAX) {
+			PMD_DRV_LOG(ERR, "off1_src1 (0x%x) exceeds the "
+				"maximum of 0x%x", info->off1_src1,
+						I40E_FIELD_OFFSET_MAX);
+			return I40E_ERR_PARAM;
+		} else if (info->len1 > I40E_FIELD_LEN_MAX) {
+			PMD_DRV_LOG(ERR, "len1 (0x%x) exceeds the maximum "
+				"of 0x%x", info->len1, I40E_FIELD_LEN_MAX);
+			return I40E_ERR_PARAM;
+		}
+
+		/**
+		 * The offset and length given in byte unit, which need to be
+		 * converted in word unit before being written to the register,
+		 * as hardware requires it in word unit.
+		 */
+		reg = (info->off0_src0 >> 1) << I40E_GLQF_SWAP_OFF0_SRC0_SHIFT;
+		reg |= (info->off0_src1 >> 1) <<
+			I40E_GLQF_SWAP_OFF0_SRC1_SHIFT;
+		reg |= (info->len0 >> 1) << I40E_GLQF_SWAP_FLEN0_SHIFT;
+		reg |= (info->off1_src0 >> 1) <<
+			I40E_GLQF_SWAP_OFF1_SRC0_SHIFT;
+		reg |= (info->off1_src1 >> 1) <<
+			I40E_GLQF_SWAP_OFF1_SRC1_SHIFT;
+		reg |= (info->len1 >> 1) << I40E_GLQF_SWAP_FLEN1_SHIFT;
+
+		PMD_DRV_LOG(DEBUG, "Value to be written to "
+			"I40E_GLQF_SWAP[0,%d]: 0x%x", info->pctype, reg);
+		I40E_WRITE_REG(hw, I40E_GLQF_SWAP(0, info->pctype), reg);
+		I40E_WRITE_FLUSH(hw);
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "PCTYPE[%u] not supported", info->pctype);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* Get hash function type */
+static void
+i40e_get_hash_function(struct i40e_hw *hw, enum rte_eth_hash_function *hf)
+{
+	uint32_t reg = I40E_READ_REG(hw, I40E_GLQF_CTL);
+
+	if (reg & I40E_GLQF_CTL_HTOEP_MASK)
+		*hf = RTE_ETH_HASH_FUNCTION_TOEPLITZ;
+	else
+		*hf = RTE_ETH_HASH_FUNCTION_SIMPLE_XOR;
+
+	PMD_DRV_LOG(INFO, "Hash function is %s",
+		(reg & I40E_GLQF_CTL_HTOEP_MASK) ? "Toeplitz" : "Simple XOR");
+}
+
+/* Set hash function type */
+static int
+i40e_set_hash_function(struct i40e_hw *hw, enum rte_eth_hash_function hf)
+{
+	uint32_t reg = I40E_READ_REG(hw, I40E_GLQF_CTL);
+
+	if (hf == RTE_ETH_HASH_FUNCTION_TOEPLITZ) {
+		if (reg & I40E_GLQF_CTL_HTOEP_MASK) {
+			PMD_DRV_LOG(DEBUG, "Hash function already set to "
+								"Toeplitz");
+			return 0;
+		}
+		reg |= I40E_GLQF_CTL_HTOEP_MASK;
+	} else if (hf == RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) {
+		if (!(reg & I40E_GLQF_CTL_HTOEP_MASK)) {
+			PMD_DRV_LOG(DEBUG, "Hash function already set to "
+							"Simple XOR");
+			return 0;
+		}
+		reg &= ~I40E_GLQF_CTL_HTOEP_MASK;
+	} else {
+		PMD_DRV_LOG(ERR, "Unknown hash function type");
+		return -EINVAL;
+	}
+
+	PMD_DRV_LOG(INFO, "Hash function set to %s",
+		(reg & I40E_GLQF_CTL_HTOEP_MASK) ? "Toeplitz" : "Simple XOR");
+	I40E_WRITE_REG(hw, I40E_GLQF_CTL, reg);
+	I40E_WRITE_FLUSH(hw);
+
+	return 0;
+}
+
+static int
+i40e_hash_filter_get(struct i40e_hw *hw, struct rte_eth_hash_filter_info *info)
+{
+	int ret = 0;
+
+	if (!hw || !info) {
+		PMD_DRV_LOG(ERR, "Invalid pointer");
+		return -EFAULT;
+	}
+
+	switch (info->info_type) {
+	case RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PCTYPE:
+		ret = i40e_get_symmetric_hash_enable_per_pctype(hw,
+					&(info->info.sym_hash_ena));
+		break;
+	case RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PORT:
+		i40e_get_symmetric_hash_enable_per_port(hw,
+					&(info->info.enable));
+		break;
+	case RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP:
+		ret = i40e_get_filter_swap(hw, &(info->info.filter_swap));
+		break;
+	case RTE_ETH_HASH_FILTER_INFO_TYPE_HASH_FUNCTION:
+		i40e_get_hash_function(hw, &(info->info.hash_function));
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "Hash filter info type (%d) not supported",
+							info->info_type);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int
+i40e_hash_filter_set(struct i40e_hw *hw, struct rte_eth_hash_filter_info *info)
+{
+	int ret = 0;
+
+	if (!hw || !info) {
+		PMD_DRV_LOG(ERR, "Invalid pointer");
+		return -EFAULT;
+	}
+
+	switch (info->info_type) {
+	case RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PCTYPE:
+		ret = i40e_set_symmetric_hash_enable_per_pctype(hw,
+					&(info->info.sym_hash_ena));
+		break;
+	case RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PORT:
+		i40e_set_symmetric_hash_enable_per_port(hw, info->info.enable);
+		break;
+	case RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP:
+		ret = i40e_set_filter_swap(hw, &(info->info.filter_swap));
+		break;
+	case RTE_ETH_HASH_FILTER_INFO_TYPE_HASH_FUNCTION:
+		ret = i40e_set_hash_function(hw, info->info.hash_function);
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "Hash filter info type (%d) not supported",
+							info->info_type);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+/* Operations for hash function */
+static int
+i40e_hash_filter_ctrl(struct rte_eth_dev *dev,
+		      enum rte_filter_op filter_op,
+		      void *arg)
+{
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	int ret = 0;
+
+	switch (filter_op) {
+	case RTE_ETH_FILTER_NOP:
+		break;
+	case RTE_ETH_FILTER_GET:
+		ret = i40e_hash_filter_get(hw,
+			(struct rte_eth_hash_filter_info *)arg);
+		break;
+	case RTE_ETH_FILTER_SET:
+		ret = i40e_hash_filter_set(hw,
+			(struct rte_eth_hash_filter_info *)arg);
+		break;
+	default:
+		PMD_DRV_LOG(WARNING, "Filter operation (%d) not supported",
+								filter_op);
+		ret = -ENOTSUP;
+		break;
+	}
+
+	return ret;
+}
+
 static int
 i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
 		     enum rte_filter_type filter_type,
@@ -4152,13 +4524,14 @@ i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
 		     void *arg)
 {
 	int ret = 0;
-	(void)filter_op;
-	(void)arg;
 
 	if (dev == NULL)
 		return -EINVAL;
 
 	switch (filter_type) {
+	case RTE_ETH_FILTER_HASH:
+		ret = i40e_hash_filter_ctrl(dev, filter_op, arg);
+		break;
 	default:
 		PMD_DRV_LOG(WARNING, "Filter type (%d) not supported",
 							filter_type);
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v5 4/5] i40e: add hardware initialization
  2014-10-21  3:14     ` [dpdk-dev] [PATCH v5 0/5] " Helin Zhang
                         ` (2 preceding siblings ...)
  2014-10-21  3:14       ` [dpdk-dev] [PATCH v5 3/5] i40e: add hash filter control implementation Helin Zhang
@ 2014-10-21  3:14       ` Helin Zhang
  2014-10-21  3:14       ` [dpdk-dev] [PATCH v5 5/5] app/testpmd: add commands to support hash filter Helin Zhang
                         ` (3 subsequent siblings)
  7 siblings, 0 replies; 71+ messages in thread
From: Helin Zhang @ 2014-10-21  3:14 UTC (permalink / raw)
  To: dev

As global registers will be reset only after a whole chip reset,
those registers might not be in an initial state after each
launching a physical port. The hardware initialization is added to
put specific global registers into an initial state.

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
---
 lib/librte_pmd_i40e/i40e_ethdev.c | 78 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 78 insertions(+)

diff --git a/lib/librte_pmd_i40e/i40e_ethdev.c b/lib/librte_pmd_i40e/i40e_ethdev.c
index 7531e3c..cedd09a 100644
--- a/lib/librte_pmd_i40e/i40e_ethdev.c
+++ b/lib/librte_pmd_i40e/i40e_ethdev.c
@@ -190,6 +190,7 @@ static int i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
 				enum rte_filter_type filter_type,
 				enum rte_filter_op filter_op,
 				void *arg);
+static void i40e_hw_init(struct i40e_hw *hw);
 
 static struct rte_pci_id pci_id_i40e_map[] = {
 #define RTE_PCI_DEV_ID_DECL_I40E(vend, dev) {RTE_PCI_DEVICE(vend, dev)},
@@ -368,6 +369,9 @@ eth_i40e_dev_init(__rte_unused struct eth_driver *eth_drv,
 	/* Make sure all is clean before doing PF reset */
 	i40e_clear_hw(hw);
 
+	/* Initialize the hardware */
+	i40e_hw_init(hw);
+
 	/* Reset here to make sure all is clean for each PF */
 	ret = i40e_pf_reset(hw);
 	if (ret) {
@@ -4541,3 +4545,77 @@ i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
 
 	return ret;
 }
+
+/* Initialization for hash function */
+static void
+i40e_hash_function_hw_init(struct i40e_hw *hw)
+{
+	uint32_t i;
+	const struct rte_eth_sym_hash_ena_info sym_hash_ena_info[] = {
+		{ETH_RSS_NONF_IPV4_UDP_SHIFT, 0},
+		{ETH_RSS_NONF_IPV4_TCP_SHIFT, 0},
+		{ETH_RSS_NONF_IPV4_SCTP_SHIFT, 0},
+		{ETH_RSS_NONF_IPV4_OTHER_SHIFT, 0},
+		{ETH_RSS_FRAG_IPV4_SHIFT, 0},
+		{ETH_RSS_NONF_IPV6_UDP_SHIFT, 0},
+		{ETH_RSS_NONF_IPV6_TCP_SHIFT, 0},
+		{ETH_RSS_NONF_IPV6_SCTP_SHIFT, 0},
+		{ETH_RSS_NONF_IPV6_OTHER_SHIFT, 0},
+		{ETH_RSS_FRAG_IPV6_SHIFT, 0},
+		{ETH_RSS_L2_PAYLOAD_SHIFT, 0},
+	};
+	const struct rte_eth_filter_swap_info swap_info[] = {
+		{ETH_RSS_NONF_IPV4_UDP_SHIFT,
+			0x1e, 0x36, 0x04, 0x3a, 0x3c, 0x02},
+		{ETH_RSS_NONF_IPV4_TCP_SHIFT,
+			0x1e, 0x36, 0x04, 0x3a, 0x3c, 0x02},
+		{ETH_RSS_NONF_IPV4_SCTP_SHIFT,
+			0x1e, 0x36, 0x04, 0x00, 0x00, 0x00},
+		{ETH_RSS_NONF_IPV4_OTHER_SHIFT,
+			0x1e, 0x36, 0x04, 0x00, 0x00, 0x00},
+		{ETH_RSS_FRAG_IPV4_SHIFT,
+			0x1e, 0x36, 0x04, 0x00, 0x00, 0x00},
+		{ETH_RSS_NONF_IPV6_UDP_SHIFT,
+			0x1a, 0x2a, 0x10, 0x3a, 0x3c, 0x02},
+		{ETH_RSS_NONF_IPV6_TCP_SHIFT,
+			0x1a, 0x2a, 0x10, 0x3a, 0x3c, 0x02},
+		{ETH_RSS_NONF_IPV6_SCTP_SHIFT,
+			0x1a, 0x2a, 0x10, 0x00, 0x00, 0x00},
+		{ETH_RSS_NONF_IPV6_OTHER_SHIFT,
+			0x1a, 0x2a, 0x10, 0x00, 0x00, 0x00},
+		{ETH_RSS_FRAG_IPV6_SHIFT,
+			0x1a, 0x2a, 0x10, 0x00, 0x00, 0x00},
+		{ETH_RSS_L2_PAYLOAD_SHIFT,
+			0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+	};
+
+	/* Disable symmetric hash per PCTYPE */
+	for (i = 0; i < RTE_DIM(sym_hash_ena_info); i++)
+		i40e_set_symmetric_hash_enable_per_pctype(hw,
+					&sym_hash_ena_info[i]);
+
+	/* Disable symmetric hash per port */
+	i40e_set_symmetric_hash_enable_per_port(hw, 0);
+
+	/* Initialize filter swap */
+	for (i = 0; i < RTE_DIM(swap_info); i++)
+		i40e_set_filter_swap(hw, &swap_info[i]);
+
+	/* Set hash function to Toeplitz by default */
+	i40e_set_hash_function(hw, RTE_ETH_HASH_FUNCTION_TOEPLITZ);
+}
+
+/*
+ * As global registers wouldn't be reset unless a global hardware reset,
+ * hardware initialization is needed to put those registers into an
+ * expected initial state.
+ */
+static void
+i40e_hw_init(struct i40e_hw *hw)
+{
+	/* clear the PF Queue Filter control register */
+	I40E_WRITE_REG(hw, I40E_PFQF_CTL_0, 0);
+
+	/* Initialize hardware for hash function */
+	i40e_hash_function_hw_init(hw);
+}
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v5 5/5] app/testpmd: add commands to support hash filter
  2014-10-21  3:14     ` [dpdk-dev] [PATCH v5 0/5] " Helin Zhang
                         ` (3 preceding siblings ...)
  2014-10-21  3:14       ` [dpdk-dev] [PATCH v5 4/5] i40e: add hardware initialization Helin Zhang
@ 2014-10-21  3:14       ` Helin Zhang
  2014-11-07  3:45       ` [dpdk-dev] [PATCH v5 0/5] Support configuring hash functions Chen, Erlu
                         ` (2 subsequent siblings)
  7 siblings, 0 replies; 71+ messages in thread
From: Helin Zhang @ 2014-10-21  3:14 UTC (permalink / raw)
  To: dev

To demonstrate the hash filter control, commands are added. They are
- get_sym_hash_ena_per_port
- set_sym_hash_ena_per_port
- get_sym_hash_ena_per_pctype
- set_sym_hash_ena_per_pctype
- get_filter_swap
- set_filter_swap
- get_hash_function
- set_hash_function

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
---
 app/test-pmd/cmdline.c | 566 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 566 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 0b972f9..23c669a 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -74,6 +74,7 @@
 #include <rte_ethdev.h>
 #include <rte_string_fns.h>
 #include <rte_devargs.h>
+#include <rte_eth_ctrl.h>
 
 #include <cmdline_rdline.h>
 #include <cmdline_parse.h>
@@ -660,6 +661,35 @@ static void cmd_help_long_parsed(void *parsed_result,
 
 			"get_flex_filter (port_id) index (idx)\n"
 			"    get info of a flex filter.\n\n"
+
+			"get_sym_hash_ena_per_port (port_id)\n"
+			"    get symmetric hash enable configuration per port.\n\n"
+
+			"set_sym_hash_ena_per_port (port_id)"
+			" (enable|disable)\n"
+			"    set symmetric hash enable configuration per port"
+			" to enable or disable.\n\n"
+
+			"get_sym_hash_ena_per_pctype (port_id) (pctype)\n"
+			"    get symmetric hash enable configuration per port\n\n"
+
+			"set_sym_hash_ena_per_pctype (port_id) (pctype)"
+			" (enable|disable)\n"
+			"    set symmetric hash enable configuration per"
+			" pctype to enable or disable.\n\n"
+
+			"get_filter_swap (port_id) (pctype)\n"
+			"    get filter swap configurations.\n\n"
+
+			"set_filter_swap (port_id) (pctype) (off0_src0) (off0_src1)"
+			" (len0) (off1_src0) (off1_src1) (len1)\n"
+			"    set filter swap configurations.\n\n"
+
+			"get_hash_function (port_id)\n"
+			"    get hash function of Toeplitz or Simple XOR.\n\n"
+
+			"set_hash_function (port_id) (toeplitz|simple_xor)\n"
+			"    set the hash function to Toeplitz or Simple XOR.\n\n"
 		);
 	}
 }
@@ -7415,6 +7445,534 @@ cmdline_parse_inst_t cmd_get_flex_filter = {
 	},
 };
 
+/* *** Classification Filters Control *** */
+
+/* *** Get symmetric hash enable per port *** */
+struct cmd_get_sym_hash_ena_per_port_result {
+	cmdline_fixed_string_t get_sym_hash_ena_per_port;
+	uint8_t port_id;
+};
+
+static void
+cmd_get_sym_hash_per_port_parsed(void *parsed_result,
+				 __rte_unused struct cmdline *cl,
+				 __rte_unused void *data)
+{
+	struct cmd_get_sym_hash_ena_per_port_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port: %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PORT;
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+						RTE_ETH_FILTER_GET, &info);
+	if (ret < 0) {
+		printf("Cannot get symmetric hash enable per port "
+					"on port %u\n", res->port_id);
+		return;
+	}
+
+	printf("Symmetric hash is %s on port %u\n", info.info.enable ?
+				"enabled" : "disabled", res->port_id);
+}
+
+cmdline_parse_token_string_t cmd_get_sym_hash_ena_per_port_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_get_sym_hash_ena_per_port_result,
+		get_sym_hash_ena_per_port, "get_sym_hash_ena_per_port");
+cmdline_parse_token_num_t cmd_get_sym_hash_ena_per_port_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_get_sym_hash_ena_per_port_result,
+		port_id, UINT8);
+
+cmdline_parse_inst_t cmd_get_sym_hash_ena_per_port = {
+	.f = cmd_get_sym_hash_per_port_parsed,
+	.data = NULL,
+	.help_str = "get_sym_hash_ena_per_port port_id",
+	.tokens = {
+		(void *)&cmd_get_sym_hash_ena_per_port_all,
+		(void *)&cmd_get_sym_hash_ena_per_port_port_id,
+		NULL,
+	},
+};
+
+/* *** Set symmetric hash enable per port *** */
+struct cmd_set_sym_hash_ena_per_port_result {
+	cmdline_fixed_string_t set_sym_hash_ena_per_port;
+	cmdline_fixed_string_t enable;
+	uint8_t port_id;
+};
+
+static void
+cmd_set_sym_hash_per_port_parsed(void *parsed_result,
+				 __rte_unused struct cmdline *cl,
+				 __rte_unused void *data)
+{
+	struct cmd_set_sym_hash_ena_per_port_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port: %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PORT;
+	if (!strcmp(res->enable, "enable"))
+		info.info.enable = 1;
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+						RTE_ETH_FILTER_SET, &info);
+	if (ret < 0) {
+		printf("Cannot set symmetric hash enable per port on "
+					"port %u\n", res->port_id);
+		return;
+	}
+
+	printf("Symmetric hash has been set to %s on port %u\n",
+					res->enable, res->port_id);
+}
+
+cmdline_parse_token_string_t cmd_set_sym_hash_ena_per_port_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_sym_hash_ena_per_port_result,
+		set_sym_hash_ena_per_port, "set_sym_hash_ena_per_port");
+cmdline_parse_token_num_t cmd_set_sym_hash_ena_per_port_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_sym_hash_ena_per_port_result,
+		port_id, UINT8);
+cmdline_parse_token_string_t cmd_set_sym_hash_ena_per_port_enable =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_sym_hash_ena_per_port_result,
+		enable, "enable#disable");
+
+cmdline_parse_inst_t cmd_set_sym_hash_ena_per_port = {
+	.f = cmd_set_sym_hash_per_port_parsed,
+	.data = NULL,
+	.help_str = "set_sym_hash_ena_per_port port_id enable|disable",
+	.tokens = {
+		(void *)&cmd_set_sym_hash_ena_per_port_all,
+		(void *)&cmd_set_sym_hash_ena_per_port_port_id,
+		(void *)&cmd_set_sym_hash_ena_per_port_enable,
+		NULL,
+	},
+};
+
+/* *** Get symmetric hash enable per pctype *** */
+struct cmd_get_sym_hash_ena_per_pctype_result {
+	cmdline_fixed_string_t get_sym_hash_ena_per_pctype;
+	uint8_t port_id;
+	uint8_t pctype;
+};
+
+static void
+cmd_get_sym_hash_per_pctype_parsed(void *parsed_result,
+				   __rte_unused struct cmdline *cl,
+				   __rte_unused void *data)
+{
+	struct cmd_get_sym_hash_ena_per_pctype_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port: %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PCTYPE;
+	info.info.sym_hash_ena.pctype = res->pctype;
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+						RTE_ETH_FILTER_GET, &info);
+	if (ret < 0) {
+		printf("Cannot get symmetric hash enable per pctype on "
+			"port %u, pctype %u\n", res->port_id, res->pctype);
+		return;
+	}
+	printf("Symmetric hash is %s on port %u, pctype %u\n",
+			info.info.sym_hash_ena.enable ? "enabled" :
+			"disabled", res->port_id, res->pctype);
+}
+
+cmdline_parse_token_string_t cmd_get_sym_hash_ena_per_pctype_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_get_sym_hash_ena_per_pctype_result,
+		get_sym_hash_ena_per_pctype, "get_sym_hash_ena_per_pctype");
+cmdline_parse_token_num_t cmd_get_sym_hash_ena_per_pctype_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_get_sym_hash_ena_per_pctype_result,
+		port_id, UINT8);
+cmdline_parse_token_num_t cmd_get_sym_hash_ena_per_pctype_pctype =
+	TOKEN_NUM_INITIALIZER(struct cmd_get_sym_hash_ena_per_pctype_result,
+		pctype, UINT8);
+
+cmdline_parse_inst_t cmd_get_sym_hash_ena_per_pctype = {
+	.f = cmd_get_sym_hash_per_pctype_parsed,
+	.data = NULL,
+	.help_str = "get_sym_hash_ena_per_pctype port_id pctype",
+	.tokens = {
+		(void *)&cmd_get_sym_hash_ena_per_pctype_all,
+		(void *)&cmd_get_sym_hash_ena_per_pctype_port_id,
+		(void *)&cmd_get_sym_hash_ena_per_pctype_pctype,
+		NULL,
+	},
+};
+
+/* *** Set symmetric hash enable per pctype *** */
+struct cmd_set_sym_hash_ena_per_pctype_result {
+	cmdline_fixed_string_t set_sym_hash_ena_per_pctype;
+	cmdline_fixed_string_t enable;
+	uint8_t port_id;
+	uint8_t pctype;
+};
+
+static void
+cmd_set_sym_hash_per_pctype_parsed(void *parsed_result,
+				   __rte_unused struct cmdline *cl,
+				   __rte_unused void *data)
+{
+	struct cmd_set_sym_hash_ena_per_pctype_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port: %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PCTYPE;
+	info.info.sym_hash_ena.pctype = res->pctype;
+	if (!strcmp(res->enable, "enable"))
+		info.info.sym_hash_ena.enable = 1;
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+						RTE_ETH_FILTER_SET, &info);
+	if (ret < 0) {
+		printf("Cannot set symmetric hash enable per pctype to %s "
+			"on port %u, pctype %u\n", res->enable ? "enabled" :
+				"disabled", res->port_id, res->pctype);
+		return;
+	}
+	printf("Symmetic hash has been set to %s on port %u, pctype %u\n",
+				res->enable, res->port_id, res->pctype);
+}
+
+cmdline_parse_token_string_t cmd_set_sym_hash_ena_per_pctype_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_sym_hash_ena_per_pctype_result,
+		set_sym_hash_ena_per_pctype, "set_sym_hash_ena_per_pctype");
+cmdline_parse_token_num_t cmd_set_sym_hash_ena_per_pctype_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_sym_hash_ena_per_pctype_result,
+		port_id, UINT8);
+cmdline_parse_token_num_t cmd_set_sym_hash_ena_per_pctype_pctype =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_sym_hash_ena_per_pctype_result,
+		pctype, UINT8);
+cmdline_parse_token_string_t cmd_set_sym_hash_ena_per_pctype_enable =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_sym_hash_ena_per_pctype_result,
+		enable, "enable#disable");
+
+cmdline_parse_inst_t cmd_set_sym_hash_ena_per_pctype = {
+	.f = cmd_set_sym_hash_per_pctype_parsed,
+	.data = NULL,
+	.help_str = "set_sym_hash_ena_per_pctype pord_id pctype "
+						"enable|disable",
+	.tokens = {
+		(void *)&cmd_set_sym_hash_ena_per_pctype_all,
+		(void *)&cmd_set_sym_hash_ena_per_pctype_port_id,
+		(void *)&cmd_set_sym_hash_ena_per_pctype_pctype,
+		(void *)&cmd_set_sym_hash_ena_per_pctype_enable,
+		NULL,
+	},
+};
+
+/* *** Get filter swap *** */
+struct cmd_get_filter_swap_result {
+	cmdline_fixed_string_t get_filter_swap;
+	uint8_t port_id;
+	uint8_t pctype;
+};
+
+static void
+cmd_get_filter_swap_parsed(void *parsed_result,
+			   __rte_unused struct cmdline *cl,
+			   __rte_unused void *data)
+{
+	struct cmd_get_filter_swap_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port: %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP;
+	info.info.filter_swap.pctype = res->pctype;
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+						RTE_ETH_FILTER_GET, &info);
+	if (ret < 0) {
+		printf("Cannot get filter swap on port %u, pctype %u\n",
+						res->port_id, res->pctype);
+		return;
+	}
+	printf("Filter swap of port %u, pctype %u is configured as:\n"
+		"off0_src0: 0x%02x, off0_src1: 0x%02x, len0: 0x%02x\n"
+		"off1_src0: 0x%02x, off1_src1: 0x%02x, len1: 0x%02x\n",
+		res->port_id, res->pctype, info.info.filter_swap.off0_src0,
+		info.info.filter_swap.off0_src1, info.info.filter_swap.len0,
+		info.info.filter_swap.off1_src0,
+		info.info.filter_swap.off1_src1, info.info.filter_swap.len1);
+}
+
+cmdline_parse_token_string_t cmd_get_filter_swap_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_get_filter_swap_result,
+		get_filter_swap, "get_filter_swap");
+cmdline_parse_token_num_t cmd_get_filter_swap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_get_filter_swap_result,
+		port_id, UINT8);
+cmdline_parse_token_num_t cmd_get_filter_swap_pctype =
+	TOKEN_NUM_INITIALIZER(struct cmd_get_filter_swap_result,
+		pctype, UINT8);
+
+cmdline_parse_inst_t cmd_get_filter_swap = {
+	.f = cmd_get_filter_swap_parsed,
+	.data = NULL,
+	.help_str = "get_filter_swap port_id pctype",
+	.tokens = {
+		(void *)&cmd_get_filter_swap_all,
+		(void *)&cmd_get_filter_swap_port_id,
+		(void *)&cmd_get_filter_swap_pctype,
+		NULL,
+	},
+};
+
+/* *** Set filter swap *** */
+struct cmd_set_filter_swap_result {
+	cmdline_fixed_string_t set_filter_swap;
+	uint8_t port_id;
+	uint8_t pctype;
+	uint8_t off0_src0;
+	uint8_t off0_src1;
+	uint8_t len0;
+	uint8_t off1_src0;
+	uint8_t off1_src1;
+	uint8_t len1;
+};
+
+static void
+cmd_set_filter_swap_parsed(void *parsed_result,
+			   __rte_unused struct cmdline *cl,
+			   __rte_unused void *data)
+{
+	struct cmd_set_filter_swap_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port: %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP;
+	info.info.filter_swap.pctype = res->pctype;
+	info.info.filter_swap.off0_src0 = res->off0_src0;
+	info.info.filter_swap.off0_src1 = res->off0_src1;
+	info.info.filter_swap.len0 = res->len0;
+	info.info.filter_swap.off1_src0 = res->off1_src0;
+	info.info.filter_swap.off1_src1 = res->off1_src1;
+	info.info.filter_swap.len1 = res->len1;
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+						RTE_ETH_FILTER_SET, &info);
+	if (ret < 0) {
+		printf("Cannot set filter swap on port %u, pctype %u\n",
+						res->port_id, res->pctype);
+		return;
+	}
+	printf("Filter swap of port %u, pctype %u has been set as:\n"
+		"off0_src0: 0x%02x, off0_src1: 0x%02x, len0: 0x%02x\n"
+		"off1_src0: 0x%02x, off1_src1: 0x%02x, len1: 0x%02x\n",
+		res->port_id, res->pctype, info.info.filter_swap.off0_src0,
+		info.info.filter_swap.off0_src1, info.info.filter_swap.len0,
+		info.info.filter_swap.off1_src0,
+		info.info.filter_swap.off1_src1, info.info.filter_swap.len1);
+}
+
+cmdline_parse_token_string_t cmd_set_filter_swap_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_filter_swap_result,
+		set_filter_swap, "set_filter_swap");
+cmdline_parse_token_num_t cmd_set_filter_swap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_filter_swap_result,
+		port_id, UINT8);
+cmdline_parse_token_num_t cmd_set_filter_swap_pctype =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_filter_swap_result,
+		pctype, UINT8);
+cmdline_parse_token_num_t cmd_set_filter_swap_off0_src0 =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_filter_swap_result,
+		off0_src0, UINT8);
+cmdline_parse_token_num_t cmd_set_filter_swap_off0_src1 =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_filter_swap_result,
+		off0_src1, UINT8);
+cmdline_parse_token_num_t cmd_set_filter_swap_len0 =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_filter_swap_result,
+		len0, UINT8);
+cmdline_parse_token_num_t cmd_set_filter_swap_off1_src0 =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_filter_swap_result,
+		off1_src0, UINT8);
+cmdline_parse_token_num_t cmd_set_filter_swap_off1_src1 =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_filter_swap_result,
+		off1_src1, UINT8);
+cmdline_parse_token_num_t cmd_set_filter_swap_len1 =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_filter_swap_result,
+		len1, UINT8);
+
+cmdline_parse_inst_t cmd_set_filter_swap = {
+	.f = cmd_set_filter_swap_parsed,
+	.data = NULL,
+	.help_str = "set_filter_swap port_id pctype off0_src0 off0_src1 "
+					"len0 off1_src0 off1_src1 len1",
+	.tokens = {
+		(void *)&cmd_set_filter_swap_all,
+		(void *)&cmd_set_filter_swap_port_id,
+		(void *)&cmd_set_filter_swap_pctype,
+		(void *)&cmd_set_filter_swap_off0_src0,
+		(void *)&cmd_set_filter_swap_off0_src1,
+		(void *)&cmd_set_filter_swap_len0,
+		(void *)&cmd_set_filter_swap_off1_src0,
+		(void *)&cmd_set_filter_swap_off1_src1,
+		(void *)&cmd_set_filter_swap_len1,
+		NULL,
+	},
+};
+
+/* Get hash function */
+struct cmd_get_hash_function_result {
+	cmdline_fixed_string_t get_hash_function;
+	uint8_t port_id;
+};
+
+static void
+cmd_get_hash_function_parsed(void *parsed_result,
+			     __rte_unused struct cmdline *cl,
+			     __rte_unused void *data)
+{
+	struct cmd_get_hash_function_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_INFO_TYPE_HASH_FUNCTION;
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+						RTE_ETH_FILTER_GET, &info);
+	if (ret < 0) {
+		printf("Cannot get hash function on port %d\n", res->port_id);
+		return;
+	}
+	printf("Hash function is %s\n", info.info.hash_function ==
+		RTE_ETH_HASH_FUNCTION_TOEPLITZ ? "Toeplitz" : "Simple XOR");
+}
+
+cmdline_parse_token_string_t cmd_get_hash_function_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_get_hash_function_result,
+		get_hash_function, "get_hash_function");
+cmdline_parse_token_num_t cmd_get_hash_function_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_get_hash_function_result,
+		port_id, UINT8);
+
+cmdline_parse_inst_t cmd_get_hash_function = {
+	.f = cmd_get_hash_function_parsed,
+	.data = NULL,
+	.help_str = "get_hash_function port_id",
+	.tokens = {
+		(void *)&cmd_get_hash_function_all,
+		(void *)&cmd_get_hash_function_port_id,
+		NULL,
+	},
+};
+
+/* Set hash function of Hoeplitz or Simple XOR */
+struct cmd_set_hash_function_result {
+	cmdline_fixed_string_t set_hash_function;
+	uint8_t port_id;
+	cmdline_fixed_string_t hash_function;
+};
+
+static void
+cmd_set_hash_function_parsed(void *parsed_result,
+			     __rte_unused struct cmdline *cl,
+			     __rte_unused void *data)
+{
+	struct cmd_set_hash_function_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_INFO_TYPE_HASH_FUNCTION;
+	if (!strcmp(res->hash_function, "toeplitz"))
+		info.info.hash_function = RTE_ETH_HASH_FUNCTION_TOEPLITZ;
+	else if (!strcmp(res->hash_function, "simple_xor"))
+		info.info.hash_function = RTE_ETH_HASH_FUNCTION_SIMPLE_XOR;
+	else {
+		printf("Unsupported hash function %s\n", res->hash_function);
+		return;
+	}
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+						RTE_ETH_FILTER_SET, &info);
+	if (ret < 0) {
+		printf("Cannot set hash function to %s on port %d\n",
+				res->hash_function, res->port_id);
+		return;
+	}
+	printf("Hash function has been successfully set to %s on port %d\n",
+					res->hash_function, res->port_id);
+}
+
+cmdline_parse_token_string_t cmd_set_hash_function_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_hash_function_result,
+		set_hash_function, "set_hash_function");
+cmdline_parse_token_num_t cmd_set_hash_function_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_hash_function_result,
+		port_id, UINT8);
+cmdline_parse_token_string_t cmd_set_hash_function_hash_function =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_hash_function_result,
+		hash_function, "toeplitz#simple_xor");
+
+cmdline_parse_inst_t cmd_set_hash_function = {
+	.f = cmd_set_hash_function_parsed,
+	.data = NULL,
+	.help_str = "set_hash_function port_id toeplitz|simple_xor",
+	.tokens = {
+		(void *)&cmd_set_hash_function_all,
+		(void *)&cmd_set_hash_function_port_id,
+		(void *)&cmd_set_hash_function_hash_function,
+		NULL,
+	},
+};
+
 /* ******************************************************************************** */
 
 /* list of instructions */
@@ -7541,6 +8099,14 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_add_flex_filter,
 	(cmdline_parse_inst_t *)&cmd_remove_flex_filter,
 	(cmdline_parse_inst_t *)&cmd_get_flex_filter,
+	(cmdline_parse_inst_t *)&cmd_get_sym_hash_ena_per_port,
+	(cmdline_parse_inst_t *)&cmd_set_sym_hash_ena_per_port,
+	(cmdline_parse_inst_t *)&cmd_get_sym_hash_ena_per_pctype,
+	(cmdline_parse_inst_t *)&cmd_set_sym_hash_ena_per_pctype,
+	(cmdline_parse_inst_t *)&cmd_get_filter_swap,
+	(cmdline_parse_inst_t *)&cmd_set_filter_swap,
+	(cmdline_parse_inst_t *)&cmd_set_hash_function,
+	(cmdline_parse_inst_t *)&cmd_get_hash_function,
 	NULL,
 };
 
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [dpdk-dev] [PATCH v5 1/5] i40e: Use constant random hash keys
  2014-10-21  3:14       ` [dpdk-dev] [PATCH v5 1/5] i40e: Use constant random hash keys Helin Zhang
@ 2014-11-03  7:49         ` Thomas Monjalon
  2014-11-03  8:18           ` Zhang, Helin
  0 siblings, 1 reply; 71+ messages in thread
From: Thomas Monjalon @ 2014-11-03  7:49 UTC (permalink / raw)
  To: Helin Zhang; +Cc: dev

Hi Helin,

The title is a bit surprising:
- it should be about RSS
- a constant cannot be really random ;)

2014-10-21 11:14, Helin Zhang:
> To be simpler, and remove the race condition, it uses prepared
> constant random hash keys to replace runtime generating the hash
> keys.

Could you explain what is the role of rss_key_default?

Thanks
-- 
Thomas

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [dpdk-dev] [PATCH v5 2/5] ethdev: add enum type and relevant structures for hash filter control
  2014-10-21  3:14       ` [dpdk-dev] [PATCH v5 2/5] ethdev: add enum type and relevant structures for hash filter control Helin Zhang
@ 2014-11-03  7:57         ` Thomas Monjalon
  2014-11-06  3:41           ` Zhang, Helin
                             ` (2 more replies)
  0 siblings, 3 replies; 71+ messages in thread
From: Thomas Monjalon @ 2014-11-03  7:57 UTC (permalink / raw)
  To: Helin Zhang; +Cc: dev

2014-10-21 11:14, Helin Zhang:
> +enum rte_eth_hash_filter_info_type {
> +	RTE_ETH_HASH_FILTER_INFO_TYPE_UNKNOWN = 0,
> +	RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PCTYPE,

PCTYPE is an unknown word in the API layer.
Could you replace it by something more generic?

> +	RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PORT,
> +	RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP,
> +	RTE_ETH_HASH_FILTER_INFO_TYPE_HASH_FUNCTION,
> +	RTE_ETH_HASH_FILTER_INFO_TYPE_MAX,
> +};

You should comment each constant.

> +struct rte_eth_sym_hash_ena_info {
> +	/**< packet classification type, defined in rte_ethdev.h */
> +	uint8_t pctype;

No, PCTYPE is not anymore defined in ethdev.

> +/**
> + * A structure used to set or get filter swap information, to support
> + * 'RTE_ETH_FILTER_HASH', 'RTE_ETH_FILTER_GET/RTE_ETH_FILTER_SET',
> + * with information type 'RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP'.
> + */
> +struct rte_eth_filter_swap_info {
> +	/**< Packet classification type, defined in rte_ethdev.h */
> +	uint8_t pctype;
> +	/**< Offset of the 1st field of the 1st couple to be swapped. */
> +	uint8_t off0_src0;
> +	/**< Offset of the 2nd field of the 1st couple to be swapped. */
> +	uint8_t off0_src1;
> +	/**< Field length of the first couple. */
> +	uint8_t len0;
> +	/**< Offset of the 1st field of the 2nd couple to be swapped. */
> +	uint8_t off1_src0;
> +	/**< Offset of the 2nd field of the 2nd couple to be swapped. */
> +	uint8_t off1_src1;
> +	/**< Field length of the second couple. */
> +	uint8_t len1;
> +};

I guess it would be easier to understand if
RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP was defined previously.

-- 
Thomas

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [dpdk-dev] [PATCH v5 1/5] i40e: Use constant random hash keys
  2014-11-03  7:49         ` Thomas Monjalon
@ 2014-11-03  8:18           ` Zhang, Helin
  2014-11-03  8:59             ` Thomas Monjalon
  0 siblings, 1 reply; 71+ messages in thread
From: Zhang, Helin @ 2014-11-03  8:18 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev

Hi Thomas

> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Monday, November 3, 2014 3:50 PM
> To: Zhang, Helin
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v5 1/5] i40e: Use constant random hash keys
> 
> Hi Helin,
> 
> The title is a bit surprising:
> - it should be about RSS
RSS makes use of hash function to route received packets, though hash function can be used for other cases, e.g. Flow director.

> - a constant cannot be really random ;)
The hash keys are generated by libc random function. It is preparatory to avoid calling random function for each port.

> 
> 2014-10-21 11:14, Helin Zhang:
> > To be simpler, and remove the race condition, it uses prepared
> > constant random hash keys to replace runtime generating the hash keys.
> 
> Could you explain what is the role of rss_key_default?
Hash function needs to be configured with keys, before end users configured them with specific keys, we need to provide a default keys which is generated by libc random function.
The random keys can get the hash function to route the received packets to all the queues well-proportioned.

> 
> Thanks
> --
> Thomas

Regards,
Helin

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [dpdk-dev] [PATCH v5 1/5] i40e: Use constant random hash keys
  2014-11-03  8:18           ` Zhang, Helin
@ 2014-11-03  8:59             ` Thomas Monjalon
  2014-11-06  7:52               ` Zhang, Helin
  2014-11-11  3:30               ` Zhang, Helin
  0 siblings, 2 replies; 71+ messages in thread
From: Thomas Monjalon @ 2014-11-03  8:59 UTC (permalink / raw)
  To: Zhang, Helin; +Cc: dev

2014-11-03 08:18, Zhang, Helin:
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > The title is a bit surprising:
> > - it should be about RSS
> 
> RSS makes use of hash function to route received packets, though
> hash function can be used for other cases, e.g. Flow director.

Yes but this patch is only changing rss_key_default so I guess it's
only related to RSS, right?

> > - a constant cannot be really random ;)
> 
> The hash keys are generated by libc random function.
> It is preparatory to avoid calling random function for each port.

Here, you remove the call to rte_rand by a constant value.

> > 2014-10-21 11:14, Helin Zhang:
> > > To be simpler, and remove the race condition, it uses prepared
> > > constant random hash keys to replace runtime generating the hash keys.
> > 
> > Could you explain what is the role of rss_key_default?
> 
> Hash function needs to be configured with keys, before end users configured
> them with specific keys, we need to provide a default keys which is
> generated by libc random function.
> The random keys can get the hash function to route the received packets to
> all the queues well-proportioned.

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [dpdk-dev] [PATCH v5 2/5] ethdev: add enum type and relevant structures for hash filter control
  2014-11-03  7:57         ` Thomas Monjalon
@ 2014-11-06  3:41           ` Zhang, Helin
  2014-11-06  8:43             ` Thomas Monjalon
  2014-11-11  3:27           ` Zhang, Helin
  2014-11-11  6:46           ` Zhang, Helin
  2 siblings, 1 reply; 71+ messages in thread
From: Zhang, Helin @ 2014-11-06  3:41 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev

Thanks for your good comments!

> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Monday, November 3, 2014 3:57 PM
> To: Zhang, Helin
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v5 2/5] ethdev: add enum type and relevant
> structures for hash filter control
> 
> 2014-10-21 11:14, Helin Zhang:
> > +enum rte_eth_hash_filter_info_type {
> > +	RTE_ETH_HASH_FILTER_INFO_TYPE_UNKNOWN = 0,
> > +	RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PCTYPE,
> 
> PCTYPE is an unknown word in the API layer.
> Could you replace it by something more generic?
So you suggested to remove words of PCTYPE, pctype, or packet classification type?
I am not trying to rename ETH_RSS_IPV4_SHIFT, ..., ETH_RSS_NONF_IPV4_UDP_SHIFT, ..., etc.
They are actually pctype in i40e, and not only for RSS. I would like to rename them into
generic names. Any good naming ideas from you or other guys? My idea is to rename
them like RTE_ETH_FLOW_TYPE_XX.

> 
> > +	RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PORT,
> > +	RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP,
> > +	RTE_ETH_HASH_FILTER_INFO_TYPE_HASH_FUNCTION,
> > +	RTE_ETH_HASH_FILTER_INFO_TYPE_MAX,
> > +};
> 
> You should comment each constant.
OK. Good to know that!

> 
> > +struct rte_eth_sym_hash_ena_info {
> > +	/**< packet classification type, defined in rte_ethdev.h */
> > +	uint8_t pctype;
> 
> No, PCTYPE is not anymore defined in ethdev.
We need a generic name for that, how about flow_type? Good comments are welcome!

> 
> > +/**
> > + * A structure used to set or get filter swap information, to support
> > + * 'RTE_ETH_FILTER_HASH', 'RTE_ETH_FILTER_GET/RTE_ETH_FILTER_SET',
> > + * with information type 'RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP'.
> > + */
> > +struct rte_eth_filter_swap_info {
> > +	/**< Packet classification type, defined in rte_ethdev.h */
> > +	uint8_t pctype;
> > +	/**< Offset of the 1st field of the 1st couple to be swapped. */
> > +	uint8_t off0_src0;
> > +	/**< Offset of the 2nd field of the 1st couple to be swapped. */
> > +	uint8_t off0_src1;
> > +	/**< Field length of the first couple. */
> > +	uint8_t len0;
> > +	/**< Offset of the 1st field of the 2nd couple to be swapped. */
> > +	uint8_t off1_src0;
> > +	/**< Offset of the 2nd field of the 2nd couple to be swapped. */
> > +	uint8_t off1_src1;
> > +	/**< Field length of the second couple. */
> > +	uint8_t len1;
> > +};
> 
> I guess it would be easier to understand if
> RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP was defined previously.
It has already been defined before this structure definition.
I don't think I have understood your idea. Could you help to explain more? Thanks!

> 
> --
> Thomas

Regards,
Helin

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [dpdk-dev] [PATCH v5 1/5] i40e: Use constant random hash keys
  2014-11-03  8:59             ` Thomas Monjalon
@ 2014-11-06  7:52               ` Zhang, Helin
  2014-11-11  3:30               ` Zhang, Helin
  1 sibling, 0 replies; 71+ messages in thread
From: Zhang, Helin @ 2014-11-06  7:52 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev



> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Monday, November 3, 2014 4:59 PM
> To: Zhang, Helin
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v5 1/5] i40e: Use constant random hash keys
> 
> 2014-11-03 08:18, Zhang, Helin:
> > From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > > The title is a bit surprising:
> > > - it should be about RSS
> >
> > RSS makes use of hash function to route received packets, though hash
> > function can be used for other cases, e.g. Flow director.
> 
> Yes but this patch is only changing rss_key_default so I guess it's only related to
> RSS, right?
Yes, it is related to RSS.

> 
> > > - a constant cannot be really random ;)
> >
> > The hash keys are generated by libc random function.
> > It is preparatory to avoid calling random function for each port.
> 
> Here, you remove the call to rte_rand by a constant value.
Yes, actually the hardware just needs random keys by default, no matter what the
real data it is. So array of random data would be better, as no need of cpu cycles,
and it is safer in multi-threads environments.

> 
> > > 2014-10-21 11:14, Helin Zhang:
> > > > To be simpler, and remove the race condition, it uses prepared
> > > > constant random hash keys to replace runtime generating the hash keys.
> > >
> > > Could you explain what is the role of rss_key_default?
> >
> > Hash function needs to be configured with keys, before end users
> > configured them with specific keys, we need to provide a default keys
> > which is generated by libc random function.
> > The random keys can get the hash function to route the received
> > packets to all the queues well-proportioned.

Regards,
Helin

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [dpdk-dev] [PATCH v5 2/5] ethdev: add enum type and relevant structures for hash filter control
  2014-11-06  3:41           ` Zhang, Helin
@ 2014-11-06  8:43             ` Thomas Monjalon
  2014-11-06  8:54               ` Zhang, Helin
  0 siblings, 1 reply; 71+ messages in thread
From: Thomas Monjalon @ 2014-11-06  8:43 UTC (permalink / raw)
  To: Zhang, Helin; +Cc: dev

2014-11-06 03:41, Zhang, Helin:
> > > +/**
> > > + * A structure used to set or get filter swap information, to support
> > > + * 'RTE_ETH_FILTER_HASH', 'RTE_ETH_FILTER_GET/RTE_ETH_FILTER_SET',
> > > + * with information type 'RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP'.
> > > + */
> > > +struct rte_eth_filter_swap_info {
> > > +	/**< Packet classification type, defined in rte_ethdev.h */
> > > +	uint8_t pctype;
> > > +	/**< Offset of the 1st field of the 1st couple to be swapped. */
> > > +	uint8_t off0_src0;
> > > +	/**< Offset of the 2nd field of the 1st couple to be swapped. */
> > > +	uint8_t off0_src1;
> > > +	/**< Field length of the first couple. */
> > > +	uint8_t len0;
> > > +	/**< Offset of the 1st field of the 2nd couple to be swapped. */
> > > +	uint8_t off1_src0;
> > > +	/**< Offset of the 2nd field of the 2nd couple to be swapped. */
> > > +	uint8_t off1_src1;
> > > +	/**< Field length of the second couple. */
> > > +	uint8_t len1;
> > > +};
> > 
> > I guess it would be easier to understand if
> > RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP was defined previously.
> 
> It has already been defined before this structure definition.
> I don't think I have understood your idea. Could you help to explain more? Thanks!

By "defined", I mean "explained". What is the action of swap filter?
You offer new features in API without explaining them. It's probably obvious
for you but not for me.

-- 
Thomas

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [dpdk-dev] [PATCH v5 2/5] ethdev: add enum type and relevant structures for hash filter control
  2014-11-06  8:43             ` Thomas Monjalon
@ 2014-11-06  8:54               ` Zhang, Helin
  0 siblings, 0 replies; 71+ messages in thread
From: Zhang, Helin @ 2014-11-06  8:54 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev



> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Thursday, November 6, 2014 4:43 PM
> To: Zhang, Helin
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v5 2/5] ethdev: add enum type and relevant
> structures for hash filter control
> 
> 2014-11-06 03:41, Zhang, Helin:
> > > > +/**
> > > > + * A structure used to set or get filter swap information, to
> > > > +support
> > > > + * 'RTE_ETH_FILTER_HASH',
> > > > +'RTE_ETH_FILTER_GET/RTE_ETH_FILTER_SET',
> > > > + * with information type
> 'RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP'.
> > > > + */
> > > > +struct rte_eth_filter_swap_info {
> > > > +	/**< Packet classification type, defined in rte_ethdev.h */
> > > > +	uint8_t pctype;
> > > > +	/**< Offset of the 1st field of the 1st couple to be swapped. */
> > > > +	uint8_t off0_src0;
> > > > +	/**< Offset of the 2nd field of the 1st couple to be swapped. */
> > > > +	uint8_t off0_src1;
> > > > +	/**< Field length of the first couple. */
> > > > +	uint8_t len0;
> > > > +	/**< Offset of the 1st field of the 2nd couple to be swapped. */
> > > > +	uint8_t off1_src0;
> > > > +	/**< Offset of the 2nd field of the 2nd couple to be swapped. */
> > > > +	uint8_t off1_src1;
> > > > +	/**< Field length of the second couple. */
> > > > +	uint8_t len1;
> > > > +};
> > >
> > > I guess it would be easier to understand if
> > > RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP was defined previously.
> >
> > It has already been defined before this structure definition.
> > I don't think I have understood your idea. Could you help to explain more?
> Thanks!
> 
> By "defined", I mean "explained". What is the action of swap filter?
> You offer new features in API without explaining them. It's probably obvious for
> you but not for me.
Yes, they should be explained.

> 
> --
> Thomas

Regards,
Helin

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [dpdk-dev] [PATCH v5 0/5] Support configuring hash functions
  2014-10-21  3:14     ` [dpdk-dev] [PATCH v5 0/5] " Helin Zhang
                         ` (4 preceding siblings ...)
  2014-10-21  3:14       ` [dpdk-dev] [PATCH v5 5/5] app/testpmd: add commands to support hash filter Helin Zhang
@ 2014-11-07  3:45       ` Chen, Erlu
  2014-11-07  6:12       ` Chen, Erlu
  2014-11-19 14:58       ` [dpdk-dev] [PATCH v6 0/3] " Helin Zhang
  7 siblings, 0 replies; 71+ messages in thread
From: Chen, Erlu @ 2014-11-07  3:45 UTC (permalink / raw)
  To: Zhang, Helin, dev

Tested-by: Erlu Chen <erlu.chen@intel.com>

- Tested Commit: 23fcffe8ffaccf8a2901050e7daa4979597141ed
- OS: Linux fc20 3.11.10-301.fc20.x86_64
- CPU: Intel(R) Xeon(R) CPU E5-2680 v2 @ 2.80GHz
- GCC: gcc version 4.8.3 20140624
- NIC:  Intel Corporation Ethernet Controller X710 for 10GbE SFP+ [8086:1572]
  Intel Corporation Ethernet Controller XL710 for 40GbE QSFP+ [8086:1584]
  Intel Corporation Ethernet Controller XL710 for 40GbE QSFP+ [8086:1583]
- Default x86_64-native-linuxapp-gcc configuration
- Total 4 cases, 4 passed, 0 failed

- Case: test_toeplitz
  Description: 
  Command / instruction:
	#1. set up testpmd with fortville NICs::
  	./testpmd -c fffff -n %d -- -i --coremask=0xffffe --rxq=16 --txq=16

#2. Reta Configuration.  128 reta entries configuration::
  	testpmd command: port config 0 rss reta (hash_index,queue_id)

#3. PMD fwd only receive the packets::
  	testpmd command: set fwd rxonly

#4. rss received package type configuration two received packet types configuration::
  	testpmd command: port config 0 rss ip/udp

#5. verbose configuration::
 	 testpmd command: set verbose 8

#6. set hash functions, can choose symmetric or not, chose port and packet type::
  	set_hash_function 0 toeplitz

#7. start packet receive::
  	testpmd command: start

tester Configuration
--------------------
	
#1. set up scapy

#2. send packets with different type ipv4/ipv4 with tcp/ipv4 with udp/ipv6/ipv6 with tcp/ipv6 with udp::
    	sendp([Ether(dst="90:e2:ba:36:99:3c")/IP(src="192.168.0.4", dst="192.168.0.5")], iface="eth3")
           
  Expected test result:
The testpmd will print the hash value and actual queue of every packet.
#1. Calaute the queue id: hash value%128or512, then refer to the redirection table to get the theoretical queue id.
#2. The theoretical queue id is the same with the actual queue id. 

- Case: test_toeplitz_symmetric
  Description: The same with the above steps, pay attention to "set hash function", and the hash value and queue should be the same for these two flow .
  Command / instruction:
The same with the above steps, pay attention to "set hash function", should use::
 	 set_hash_function 0 toeplitz
 	 set_sym_hash_ena_per_port 0 enable
 	 set_sym_hash_ena_per_pctype 0 35 enable

And send packets with the same flow in different direction::
 	 sendp([Ether(dst="90:e2:ba:36:99:3c")/IP(src="192.168.0.4", dst="192.168.0.5")], iface="eth3")
  	sendp([Ether(dst="90:e2:ba:36:99:3c")/IP(src="192.168.0.5", dst="192.168.0.4")], iface="eth3")
  Expected test result:
	The hash value and queue should be the same for these two flow .

- Case: test_simple
  Description: The same as the above two test cases. Just pay attention to set the hash function to "simple xor"

- Case: test_simple_symmetric
  Description: The same as the above two test cases. Just pay attention to set the hash function to "simple xor"


-----Original Message-----
From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Helin Zhang
Sent: Tuesday, October 21, 2014 11:15 AM
To: dev@dpdk.org
Subject: [dpdk-dev] [PATCH v5 0/5] Support configuring hash functions

These patches mainly support configuring hash functions.
In detail,
 - It can get or set hash functions.
 - It can configure symmetric hash functions.
   * Get/set symmetric hash enable per port.
   * Get/set symmetric hash enable per 'PCTYPE'.
   * Get/set filter swap configurations.
 - Six commands have been implemented in testpmd to support
   testing above.
   * get_sym_hash_ena_per_port
   * set_sym_hash_ena_per_port
   * get_sym_hash_ena_per_pctype
   * set_sym_hash_ena_per_pctype
   * get_filter_swap
   * set_filter_swap
   * get_hash_function
   * set_hash_function
Note that 'PCTYPE' means 'Packet Classification Type'.

It also uses prepared constant hash keys to replace runtime generating hash keys. Global initialization is added to put global registers to an initial state, as global registers can be reset by global reset only.

v3 changes:
* Removed renamings in rte_ethdev.h.
* Redesigned filter control API and its relevant structures/enums.
* Renamed header file from rte_eth_features.h to rte_eth_ctrol.h.
* Remove public header file of rte_i40e.h specific for i40e.
* Added hardware initialization function during port init.
* Used constant random hash keys in i40e PF.
* renamed the commands in testpmd based on the redesigned filter
  control API.

v4 changes:
* Fixed a bug in testpmd to support 'set_sym_hash_ena_per_port'.

v5 changes:
* Integrated with filter API defined recently.
* Remove all for filter API definition, as it has already defined
  and merged recently.

Helin Zhang (5):
  i40e: Use constant random hash keys
  ethdev: add enum type and relevant structures for hash filter control
  i40e: add hash filter control implementation
  i40e: add hardware initialization
  app/testpmd: add commands to support hash filter

 app/test-pmd/cmdline.c            | 566 ++++++++++++++++++++++++++++++++++++++
 lib/librte_ether/rte_eth_ctrl.h   |  75 +++++
 lib/librte_pmd_i40e/i40e_ethdev.c | 467 ++++++++++++++++++++++++++++++-
 3 files changed, 1100 insertions(+), 8 deletions(-)

--
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [dpdk-dev] [PATCH v5 0/5] Support configuring hash functions
  2014-10-21  3:14     ` [dpdk-dev] [PATCH v5 0/5] " Helin Zhang
                         ` (5 preceding siblings ...)
  2014-11-07  3:45       ` [dpdk-dev] [PATCH v5 0/5] Support configuring hash functions Chen, Erlu
@ 2014-11-07  6:12       ` Chen, Erlu
  2014-11-19 14:58       ` [dpdk-dev] [PATCH v6 0/3] " Helin Zhang
  7 siblings, 0 replies; 71+ messages in thread
From: Chen, Erlu @ 2014-11-07  6:12 UTC (permalink / raw)
  To: Zhang, Helin, dev

Tested-by: Erlu Chen <erlu.chen@intel.com>

- Tested Commit: b82da759779ee56d74ce36dc5a1020c60be9ca24
- OS: Linux fc20 3.11.10-301.fc20.x86_64
- CPU: Intel(R) Xeon(R) CPU E5-2680 v2 @ 2.80GHz
- GCC: gcc version 4.8.3 20140624
- NIC:  Intel Corporation Ethernet Controller X710 for 10GbE SFP+ [8086:1572]
  Intel Corporation Ethernet Controller XL710 for 40GbE QSFP+ [8086:1584]
  Intel Corporation Ethernet Controller XL710 for 40GbE QSFP+ [8086:1583]
- Default x86_64-native-linuxapp-gcc configuration
- Total 4 cases, 4 passed, 0 failed

- Case: test_toeplitz
  Description: 
  Command / instruction:
	#1. set up testpmd with fortville NICs::
  	./testpmd -c fffff -n %d -- -i --coremask=0xffffe --rxq=16 --txq=16

	#2. Reta Configuration.  128 reta entries configuration::
  	testpmd command: port config 0 rss reta (hash_index,queue_id)

	#3. PMD fwd only receive the packets::
  	testpmd command: set fwd rxonly

	#4. rss received package type configuration two received packet types configuration::
  	testpmd command: port config 0 rss ip/udp

	#5. verbose configuration::
 	 testpmd command: set verbose 8

	#6. set hash functions, can choose symmetric or not, chose port and packet type::
  	set_hash_function 0 toeplitz

	#7. start packet receive::
  	testpmd command: start

	tester Configuration
	--------------------
	
	#1. set up scapy

	#2. send packets with different type ipv4/ipv4 with tcp/ipv4 with udp/ipv6/ipv6 with tcp/ipv6 with udp::
    	sendp([Ether(dst="90:e2:ba:36:99:3c")/IP(src="192.168.0.4", dst="192.168.0.5")], iface="eth3")
           
  Expected test result:
The testpmd will print the hash value and actual queue of every packet.
#1. Calaute the queue id: hash value%128or512, then refer to the redirection table to get the theoretical queue id.
#2. The theoretical queue id is the same with the actual queue id. 

- Case: test_toeplitz_symmetric
  Description: The same with the above steps, pay attention to "set hash function", and the hash value and queue should be the same for these two flow .
  Command / instruction:
  The same with the above steps, pay attention to "set hash function", should use::
 	 set_hash_function 0 toeplitz
 	 set_sym_hash_ena_per_port 0 enable
 	 set_sym_hash_ena_per_pctype 0 35 enable

  And send packets with the same flow in different direction::
 	 sendp([Ether(dst="90:e2:ba:36:99:3c")/IP(src="192.168.0.4", dst="192.168.0.5")], iface="eth3")
  	sendp([Ether(dst="90:e2:ba:36:99:3c")/IP(src="192.168.0.5", dst="192.168.0.4")], iface="eth3")
  Expected test result:
	The hash value and queue should be the same for these two flow .

- Case: test_simple
  Description: The same as the above two test cases. Just pay attention to set the hash function to "simple xor"

- Case: test_simple_symmetric
  Description: The same as the above two test cases. Just pay attention to set the hash function to "simple xor"


-----Original Message-----
From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Helin Zhang
Sent: Tuesday, October 21, 2014 11:15 AM
To: dev@dpdk.org
Subject: [dpdk-dev] [PATCH v5 0/5] Support configuring hash functions

These patches mainly support configuring hash functions.
In detail,
 - It can get or set hash functions.
 - It can configure symmetric hash functions.
   * Get/set symmetric hash enable per port.
   * Get/set symmetric hash enable per 'PCTYPE'.
   * Get/set filter swap configurations.
 - Six commands have been implemented in testpmd to support
   testing above.
   * get_sym_hash_ena_per_port
   * set_sym_hash_ena_per_port
   * get_sym_hash_ena_per_pctype
   * set_sym_hash_ena_per_pctype
   * get_filter_swap
   * set_filter_swap
   * get_hash_function
   * set_hash_function
Note that 'PCTYPE' means 'Packet Classification Type'.

It also uses prepared constant hash keys to replace runtime generating hash keys. Global initialization is added to put global registers to an initial state, as global registers can be reset by global reset only.

v3 changes:
* Removed renamings in rte_ethdev.h.
* Redesigned filter control API and its relevant structures/enums.
* Renamed header file from rte_eth_features.h to rte_eth_ctrol.h.
* Remove public header file of rte_i40e.h specific for i40e.
* Added hardware initialization function during port init.
* Used constant random hash keys in i40e PF.
* renamed the commands in testpmd based on the redesigned filter
  control API.

v4 changes:
* Fixed a bug in testpmd to support 'set_sym_hash_ena_per_port'.

v5 changes:
* Integrated with filter API defined recently.
* Remove all for filter API definition, as it has already defined
  and merged recently.

Helin Zhang (5):
  i40e: Use constant random hash keys
  ethdev: add enum type and relevant structures for hash filter control
  i40e: add hash filter control implementation
  i40e: add hardware initialization
  app/testpmd: add commands to support hash filter

 app/test-pmd/cmdline.c            | 566 ++++++++++++++++++++++++++++++++++++++
 lib/librte_ether/rte_eth_ctrl.h   |  75 +++++
 lib/librte_pmd_i40e/i40e_ethdev.c | 467 ++++++++++++++++++++++++++++++-
 3 files changed, 1100 insertions(+), 8 deletions(-)

--
1.8.1.4


-----Original Message-----
From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Helin Zhang
Sent: Tuesday, October 21, 2014 11:15 AM
To: dev@dpdk.org
Subject: [dpdk-dev] [PATCH v5 0/5] Support configuring hash functions

These patches mainly support configuring hash functions.
In detail,
 - It can get or set hash functions.
 - It can configure symmetric hash functions.
   * Get/set symmetric hash enable per port.
   * Get/set symmetric hash enable per 'PCTYPE'.
   * Get/set filter swap configurations.
 - Six commands have been implemented in testpmd to support
   testing above.
   * get_sym_hash_ena_per_port
   * set_sym_hash_ena_per_port
   * get_sym_hash_ena_per_pctype
   * set_sym_hash_ena_per_pctype
   * get_filter_swap
   * set_filter_swap
   * get_hash_function
   * set_hash_function
Note that 'PCTYPE' means 'Packet Classification Type'.

It also uses prepared constant hash keys to replace runtime generating hash keys. Global initialization is added to put global registers to an initial state, as global registers can be reset by global reset only.

v3 changes:
* Removed renamings in rte_ethdev.h.
* Redesigned filter control API and its relevant structures/enums.
* Renamed header file from rte_eth_features.h to rte_eth_ctrol.h.
* Remove public header file of rte_i40e.h specific for i40e.
* Added hardware initialization function during port init.
* Used constant random hash keys in i40e PF.
* renamed the commands in testpmd based on the redesigned filter
  control API.

v4 changes:
* Fixed a bug in testpmd to support 'set_sym_hash_ena_per_port'.

v5 changes:
* Integrated with filter API defined recently.
* Remove all for filter API definition, as it has already defined
  and merged recently.

Helin Zhang (5):
  i40e: Use constant random hash keys
  ethdev: add enum type and relevant structures for hash filter control
  i40e: add hash filter control implementation
  i40e: add hardware initialization
  app/testpmd: add commands to support hash filter

 app/test-pmd/cmdline.c            | 566 ++++++++++++++++++++++++++++++++++++++
 lib/librte_ether/rte_eth_ctrl.h   |  75 +++++
 lib/librte_pmd_i40e/i40e_ethdev.c | 467 ++++++++++++++++++++++++++++++-
 3 files changed, 1100 insertions(+), 8 deletions(-)

--
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [dpdk-dev] [PATCH v5 2/5] ethdev: add enum type and relevant structures for hash filter control
  2014-11-03  7:57         ` Thomas Monjalon
  2014-11-06  3:41           ` Zhang, Helin
@ 2014-11-11  3:27           ` Zhang, Helin
  2014-11-11  6:46           ` Zhang, Helin
  2 siblings, 0 replies; 71+ messages in thread
From: Zhang, Helin @ 2014-11-11  3:27 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev



> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Monday, November 3, 2014 3:57 PM
> To: Zhang, Helin
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v5 2/5] ethdev: add enum type and relevant
> structures for hash filter control
> 
> 2014-10-21 11:14, Helin Zhang:
> > +enum rte_eth_hash_filter_info_type {
> > +	RTE_ETH_HASH_FILTER_INFO_TYPE_UNKNOWN = 0,
> > +	RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PCTYPE,
> 
> PCTYPE is an unknown word in the API layer.
> Could you replace it by something more generic?
In ethdev layer, the idea of 'flow type' will be used for generic purpose.

> 
> > +	RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PORT,
> > +	RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP,
> > +	RTE_ETH_HASH_FILTER_INFO_TYPE_HASH_FUNCTION,
> > +	RTE_ETH_HASH_FILTER_INFO_TYPE_MAX,
> > +};
> 
> You should comment each constant.
Yes, agree.

> 
> > +struct rte_eth_sym_hash_ena_info {
> > +	/**< packet classification type, defined in rte_ethdev.h */
> > +	uint8_t pctype;
> 
> No, PCTYPE is not anymore defined in ethdev.
No pctype will be there on ethdev layer.

> 
> > +/**
> > + * A structure used to set or get filter swap information, to support
> > + * 'RTE_ETH_FILTER_HASH', 'RTE_ETH_FILTER_GET/RTE_ETH_FILTER_SET',
> > + * with information type 'RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP'.
> > + */
> > +struct rte_eth_filter_swap_info {
> > +	/**< Packet classification type, defined in rte_ethdev.h */
> > +	uint8_t pctype;
> > +	/**< Offset of the 1st field of the 1st couple to be swapped. */
> > +	uint8_t off0_src0;
> > +	/**< Offset of the 2nd field of the 1st couple to be swapped. */
> > +	uint8_t off0_src1;
> > +	/**< Field length of the first couple. */
> > +	uint8_t len0;
> > +	/**< Offset of the 1st field of the 2nd couple to be swapped. */
> > +	uint8_t off1_src0;
> > +	/**< Offset of the 2nd field of the 2nd couple to be swapped. */
> > +	uint8_t off1_src1;
> > +	/**< Field length of the second couple. */
> > +	uint8_t len1;
> > +};
> 
> I guess it would be easier to understand if
> RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP was defined previously.
> 
> --
> Thomas

Regards,
Helin

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [dpdk-dev] [PATCH v5 1/5] i40e: Use constant random hash keys
  2014-11-03  8:59             ` Thomas Monjalon
  2014-11-06  7:52               ` Zhang, Helin
@ 2014-11-11  3:30               ` Zhang, Helin
  1 sibling, 0 replies; 71+ messages in thread
From: Zhang, Helin @ 2014-11-11  3:30 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev



> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Monday, November 3, 2014 4:59 PM
> To: Zhang, Helin
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v5 1/5] i40e: Use constant random hash keys
> 
> 2014-11-03 08:18, Zhang, Helin:
> > From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > > The title is a bit surprising:
> > > - it should be about RSS
> >
> > RSS makes use of hash function to route received packets, though hash
> > function can be used for other cases, e.g. Flow director.
> 
> Yes but this patch is only changing rss_key_default so I guess it's only related to
> RSS, right?
Yes, it is currently for rss only.

> 
> > > - a constant cannot be really random ;)
The comments could be re-worded.

> >
> > The hash keys are generated by libc random function.
> > It is preparatory to avoid calling random function for each port.
> 
> Here, you remove the call to rte_rand by a constant value.
No need to calculate it every time, like what Linux i40e driver does.

> 
> > > 2014-10-21 11:14, Helin Zhang:
> > > > To be simpler, and remove the race condition, it uses prepared
> > > > constant random hash keys to replace runtime generating the hash keys.
> > >
> > > Could you explain what is the role of rss_key_default?
> >
> > Hash function needs to be configured with keys, before end users
> > configured them with specific keys, we need to provide a default keys
> > which is generated by libc random function.
> > The random keys can get the hash function to route the received
> > packets to all the queues well-proportioned.

Regards,
Helin

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [dpdk-dev] [PATCH v5 2/5] ethdev: add enum type and relevant structures for hash filter control
  2014-11-03  7:57         ` Thomas Monjalon
  2014-11-06  3:41           ` Zhang, Helin
  2014-11-11  3:27           ` Zhang, Helin
@ 2014-11-11  6:46           ` Zhang, Helin
  2014-11-11 21:08             ` Thomas Monjalon
  2 siblings, 1 reply; 71+ messages in thread
From: Zhang, Helin @ 2014-11-11  6:46 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev

Hi Thomas

In order to get things more generic, and remove any mappings on specific NIC hardwares, I planned to change the macros in rte_ethdev.h from

/* Supported RSS offloads */
/* for 1G & 10G */
#define ETH_RSS_IPV4_SHIFT                    0
#define ETH_RSS_IPV4_TCP_SHIFT                1
#define ETH_RSS_IPV6_SHIFT                    2
#define ETH_RSS_IPV6_EX_SHIFT                 3
#define ETH_RSS_IPV6_TCP_SHIFT                4
#define ETH_RSS_IPV6_TCP_EX_SHIFT             5
#define ETH_RSS_IPV4_UDP_SHIFT                6
#define ETH_RSS_IPV6_UDP_SHIFT                7
#define ETH_RSS_IPV6_UDP_EX_SHIFT             8
/* for 40G only */
#define ETH_RSS_NONF_IPV4_UDP_SHIFT           31
#define ETH_RSS_NONF_IPV4_TCP_SHIFT           33
#define ETH_RSS_NONF_IPV4_SCTP_SHIFT          34
#define ETH_RSS_NONF_IPV4_OTHER_SHIFT         35
#define ETH_RSS_FRAG_IPV4_SHIFT               36
#define ETH_RSS_NONF_IPV6_UDP_SHIFT           41
#define ETH_RSS_NONF_IPV6_TCP_SHIFT           43
#define ETH_RSS_NONF_IPV6_SCTP_SHIFT          44
#define ETH_RSS_NONF_IPV6_OTHER_SHIFT         45
#define ETH_RSS_FRAG_IPV6_SHIFT               46
#define ETH_RSS_FCOE_OX_SHIFT                 48
#define ETH_RSS_FCOE_RX_SHIFT                 49
#define ETH_RSS_FCOE_OTHER_SHIFT              50
#define ETH_RSS_L2_PAYLOAD_SHIFT              63

to

/* Supported RSS offloads */
/* for 1G & 10G */
#define ETH_FLOW_TYPE_IPV4                    0
#define ETH_FLOW_TYPE_IPV4_TCP                1
#define ETH_FLOW_TYPE_IPV6                    2
#define ETH_FLOW_TYPE_IPV6_EX                 3
#define ETH_FLOW_TYPE_IPV6_TCP                4
#define ETH_FLOW_TYPE_IPV6_TCP_EX             5
#define ETH_FLOW_TYPE_IPV4_UDP                6
#define ETH_FLOW_TYPE_IPV6_UDP                7
#define ETH_FLOW_TYPE_IPV6_UDP_EX             8
/* for 40G only */
#define ETH_FLOW_TYPE_NONFRAG_IPV4_UDP           9
#define ETH_FLOW_TYPE_NONFRAG_IPV4_TCP           10
#define ETH_FLOW_TYPE_NONFRAG_IPV4_SCTP          11
#define ETH_FLOW_TYPE_NONFRAG_IPV4_OTHER         12
#define ETH_FLOW_TYPE_FRAG_IPV4               13
#define ETH_FLOW_TYPE_NONFRAG_IPV6_UDP           14
#define ETH_FLOW_TYPE_NONFRAG_IPV6_TCP           15
#define ETH_FLOW_TYPE_NONFRAG_IPV6_SCTP          16
#define ETH_FLOW_TYPE_NONFRAG_IPV6_OTHER         17
#define ETH_FLOW_TYPE_FRAG_IPV6              18
#define ETH_FLOW_TYPE_L2_PAYLOAD              19

Any comments or better ideas on that? Thanks!

Regards,
Helin
> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Monday, November 3, 2014 3:57 PM
> To: Zhang, Helin
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v5 2/5] ethdev: add enum type and relevant
> structures for hash filter control
> 
> 2014-10-21 11:14, Helin Zhang:
> > +enum rte_eth_hash_filter_info_type {
> > +	RTE_ETH_HASH_FILTER_INFO_TYPE_UNKNOWN = 0,
> > +	RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PCTYPE,
> 
> PCTYPE is an unknown word in the API layer.
> Could you replace it by something more generic?
> 
> > +	RTE_ETH_HASH_FILTER_INFO_TYPE_SYM_HASH_ENA_PER_PORT,
> > +	RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP,
> > +	RTE_ETH_HASH_FILTER_INFO_TYPE_HASH_FUNCTION,
> > +	RTE_ETH_HASH_FILTER_INFO_TYPE_MAX,
> > +};
> 
> You should comment each constant.
> 
> > +struct rte_eth_sym_hash_ena_info {
> > +	/**< packet classification type, defined in rte_ethdev.h */
> > +	uint8_t pctype;
> 
> No, PCTYPE is not anymore defined in ethdev.
> 
> > +/**
> > + * A structure used to set or get filter swap information, to support
> > + * 'RTE_ETH_FILTER_HASH', 'RTE_ETH_FILTER_GET/RTE_ETH_FILTER_SET',
> > + * with information type 'RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP'.
> > + */
> > +struct rte_eth_filter_swap_info {
> > +	/**< Packet classification type, defined in rte_ethdev.h */
> > +	uint8_t pctype;
> > +	/**< Offset of the 1st field of the 1st couple to be swapped. */
> > +	uint8_t off0_src0;
> > +	/**< Offset of the 2nd field of the 1st couple to be swapped. */
> > +	uint8_t off0_src1;
> > +	/**< Field length of the first couple. */
> > +	uint8_t len0;
> > +	/**< Offset of the 1st field of the 2nd couple to be swapped. */
> > +	uint8_t off1_src0;
> > +	/**< Offset of the 2nd field of the 2nd couple to be swapped. */
> > +	uint8_t off1_src1;
> > +	/**< Field length of the second couple. */
> > +	uint8_t len1;
> > +};
> 
> I guess it would be easier to understand if
> RTE_ETH_HASH_FILTER_INFO_TYPE_FILTER_SWAP was defined previously.
> 
> --
> Thomas

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [dpdk-dev] [PATCH v5 2/5] ethdev: add enum type and relevant structures for hash filter control
  2014-11-11  6:46           ` Zhang, Helin
@ 2014-11-11 21:08             ` Thomas Monjalon
  2014-11-12  5:52               ` Zhang, Helin
  0 siblings, 1 reply; 71+ messages in thread
From: Thomas Monjalon @ 2014-11-11 21:08 UTC (permalink / raw)
  To: Zhang, Helin; +Cc: dev

2014-11-11 06:46, Zhang, Helin:
> In order to get things more generic, and remove any mappings on specific NIC hardwares, I planned to change the macros in rte_ethdev.h from
> 
> /* Supported RSS offloads */
> /* for 1G & 10G */
> #define ETH_RSS_IPV4_SHIFT                    0
> #define ETH_RSS_IPV4_TCP_SHIFT                1
> #define ETH_RSS_IPV6_SHIFT                    2
> #define ETH_RSS_IPV6_EX_SHIFT                 3
> #define ETH_RSS_IPV6_TCP_SHIFT                4
> #define ETH_RSS_IPV6_TCP_EX_SHIFT             5
> #define ETH_RSS_IPV4_UDP_SHIFT                6
> #define ETH_RSS_IPV6_UDP_SHIFT                7
> #define ETH_RSS_IPV6_UDP_EX_SHIFT             8
> /* for 40G only */
> #define ETH_RSS_NONF_IPV4_UDP_SHIFT           31
> #define ETH_RSS_NONF_IPV4_TCP_SHIFT           33
> #define ETH_RSS_NONF_IPV4_SCTP_SHIFT          34
> #define ETH_RSS_NONF_IPV4_OTHER_SHIFT         35
> #define ETH_RSS_FRAG_IPV4_SHIFT               36
> #define ETH_RSS_NONF_IPV6_UDP_SHIFT           41
> #define ETH_RSS_NONF_IPV6_TCP_SHIFT           43
> #define ETH_RSS_NONF_IPV6_SCTP_SHIFT          44
> #define ETH_RSS_NONF_IPV6_OTHER_SHIFT         45
> #define ETH_RSS_FRAG_IPV6_SHIFT               46
> #define ETH_RSS_FCOE_OX_SHIFT                 48
> #define ETH_RSS_FCOE_RX_SHIFT                 49
> #define ETH_RSS_FCOE_OTHER_SHIFT              50
> #define ETH_RSS_L2_PAYLOAD_SHIFT              63
> 
> to
> 
> /* Supported RSS offloads */
> /* for 1G & 10G */
> #define ETH_FLOW_TYPE_IPV4                    0
> #define ETH_FLOW_TYPE_IPV4_TCP                1
> #define ETH_FLOW_TYPE_IPV6                    2
> #define ETH_FLOW_TYPE_IPV6_EX                 3
> #define ETH_FLOW_TYPE_IPV6_TCP                4
> #define ETH_FLOW_TYPE_IPV6_TCP_EX             5
> #define ETH_FLOW_TYPE_IPV4_UDP                6
> #define ETH_FLOW_TYPE_IPV6_UDP                7
> #define ETH_FLOW_TYPE_IPV6_UDP_EX             8
> /* for 40G only */
> #define ETH_FLOW_TYPE_NONFRAG_IPV4_UDP           9
> #define ETH_FLOW_TYPE_NONFRAG_IPV4_TCP           10
> #define ETH_FLOW_TYPE_NONFRAG_IPV4_SCTP          11
> #define ETH_FLOW_TYPE_NONFRAG_IPV4_OTHER         12
> #define ETH_FLOW_TYPE_FRAG_IPV4               13
> #define ETH_FLOW_TYPE_NONFRAG_IPV6_UDP           14
> #define ETH_FLOW_TYPE_NONFRAG_IPV6_TCP           15
> #define ETH_FLOW_TYPE_NONFRAG_IPV6_SCTP          16
> #define ETH_FLOW_TYPE_NONFRAG_IPV6_OTHER         17
> #define ETH_FLOW_TYPE_FRAG_IPV6              18
> #define ETH_FLOW_TYPE_L2_PAYLOAD              19
> 
> Any comments or better ideas on that? Thanks!

About the renaming RSS -> FLOW_TYPE, I have no objection.
It seems a bit better.
Some comments are needed to explain what means the value.
I think the comments "1G & 10G" or "40G only" are possibly wrong.
Actually you use ETH_FLOW_TYPE_IPV4 for ixgbe and ETH_FLOW_TYPE_FRAG_IPV4
or ETH_FLOW_TYPE_NONFRAG_IPV4_* for i40e. It's not consistent and clearly
shows that you stick to the hardware definitions.

Something really generic could be a set of flags like this:
	IPV4
	IPV6
	NONFRAG
	UDP
	TCP
	SCTP

-- 
Thomas

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [dpdk-dev] [PATCH v5 2/5] ethdev: add enum type and relevant structures for hash filter control
  2014-11-11 21:08             ` Thomas Monjalon
@ 2014-11-12  5:52               ` Zhang, Helin
  2014-11-12  9:30                 ` Thomas Monjalon
  0 siblings, 1 reply; 71+ messages in thread
From: Zhang, Helin @ 2014-11-12  5:52 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev



> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Wednesday, November 12, 2014 5:09 AM
> To: Zhang, Helin
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v5 2/5] ethdev: add enum type and relevant
> structures for hash filter control
> 
> 2014-11-11 06:46, Zhang, Helin:
> > In order to get things more generic, and remove any mappings on
> > specific NIC hardwares, I planned to change the macros in rte_ethdev.h
> > from
> >
> > /* Supported RSS offloads */
> > /* for 1G & 10G */
> > #define ETH_RSS_IPV4_SHIFT                    0
> > #define ETH_RSS_IPV4_TCP_SHIFT                1
> > #define ETH_RSS_IPV6_SHIFT                    2
> > #define ETH_RSS_IPV6_EX_SHIFT                 3
> > #define ETH_RSS_IPV6_TCP_SHIFT                4
> > #define ETH_RSS_IPV6_TCP_EX_SHIFT             5
> > #define ETH_RSS_IPV4_UDP_SHIFT                6
> > #define ETH_RSS_IPV6_UDP_SHIFT                7
> > #define ETH_RSS_IPV6_UDP_EX_SHIFT             8
> > /* for 40G only */
> > #define ETH_RSS_NONF_IPV4_UDP_SHIFT           31
> > #define ETH_RSS_NONF_IPV4_TCP_SHIFT           33
> > #define ETH_RSS_NONF_IPV4_SCTP_SHIFT          34
> > #define ETH_RSS_NONF_IPV4_OTHER_SHIFT         35
> > #define ETH_RSS_FRAG_IPV4_SHIFT               36
> > #define ETH_RSS_NONF_IPV6_UDP_SHIFT           41
> > #define ETH_RSS_NONF_IPV6_TCP_SHIFT           43
> > #define ETH_RSS_NONF_IPV6_SCTP_SHIFT          44
> > #define ETH_RSS_NONF_IPV6_OTHER_SHIFT         45
> > #define ETH_RSS_FRAG_IPV6_SHIFT               46
> > #define ETH_RSS_FCOE_OX_SHIFT                 48
> > #define ETH_RSS_FCOE_RX_SHIFT                 49
> > #define ETH_RSS_FCOE_OTHER_SHIFT              50
> > #define ETH_RSS_L2_PAYLOAD_SHIFT              63
> >
> > to
> >
> > /* Supported RSS offloads */
> > /* for 1G & 10G */
> > #define ETH_FLOW_TYPE_IPV4                    0
> > #define ETH_FLOW_TYPE_IPV4_TCP                1
> > #define ETH_FLOW_TYPE_IPV6                    2
> > #define ETH_FLOW_TYPE_IPV6_EX                 3
> > #define ETH_FLOW_TYPE_IPV6_TCP                4
> > #define ETH_FLOW_TYPE_IPV6_TCP_EX             5
> > #define ETH_FLOW_TYPE_IPV4_UDP                6
> > #define ETH_FLOW_TYPE_IPV6_UDP                7
> > #define ETH_FLOW_TYPE_IPV6_UDP_EX             8
> > /* for 40G only */
> > #define ETH_FLOW_TYPE_NONFRAG_IPV4_UDP           9
> > #define ETH_FLOW_TYPE_NONFRAG_IPV4_TCP           10
> > #define ETH_FLOW_TYPE_NONFRAG_IPV4_SCTP          11
> > #define ETH_FLOW_TYPE_NONFRAG_IPV4_OTHER         12
> > #define ETH_FLOW_TYPE_FRAG_IPV4               13
> > #define ETH_FLOW_TYPE_NONFRAG_IPV6_UDP           14
> > #define ETH_FLOW_TYPE_NONFRAG_IPV6_TCP           15
> > #define ETH_FLOW_TYPE_NONFRAG_IPV6_SCTP          16
> > #define ETH_FLOW_TYPE_NONFRAG_IPV6_OTHER         17
> > #define ETH_FLOW_TYPE_FRAG_IPV6              18
> > #define ETH_FLOW_TYPE_L2_PAYLOAD              19
> >
> > Any comments or better ideas on that? Thanks!
> 
> About the renaming RSS -> FLOW_TYPE, I have no objection.
> It seems a bit better.
Nice to hear that!

> Some comments are needed to explain what means the value.
> I think the comments "1G & 10G" or "40G only" are possibly wrong.
Yes, I agree with you.

> Actually you use ETH_FLOW_TYPE_IPV4 for ixgbe and
> ETH_FLOW_TYPE_FRAG_IPV4 or ETH_FLOW_TYPE_NONFRAG_IPV4_* for i40e.
> It's not consistent and clearly shows that you stick to the hardware definitions.
> 
> Something really generic could be a set of flags like this:
> 	IPV4
> 	IPV6
> 	NONFRAG
> 	UDP
> 	TCP
> 	SCTP
Good conclusion! We could think of it in a new patch set. I don't want to put everything into this patch. :)

> 
> --
> Thomas

Regards,
Helin

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [dpdk-dev] [PATCH v5 2/5] ethdev: add enum type and relevant structures for hash filter control
  2014-11-12  5:52               ` Zhang, Helin
@ 2014-11-12  9:30                 ` Thomas Monjalon
  2014-11-12 14:22                   ` Zhang, Helin
  0 siblings, 1 reply; 71+ messages in thread
From: Thomas Monjalon @ 2014-11-12  9:30 UTC (permalink / raw)
  To: Zhang, Helin; +Cc: dev

2014-11-12 05:52, Zhang, Helin:
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > Actually you use ETH_FLOW_TYPE_IPV4 for ixgbe and
> > ETH_FLOW_TYPE_FRAG_IPV4 or ETH_FLOW_TYPE_NONFRAG_IPV4_* for i40e.
> > It's not consistent and clearly shows that you stick to the hardware definitions.
> > 
> > Something really generic could be a set of flags like this:
> > 	IPV4
> > 	IPV6
> > 	NONFRAG
> > 	UDP
> > 	TCP
> > 	SCTP
> 
> Good conclusion! We could think of it in a new patch set.
> I don't want to put everything into this patch. :)

If you agree flags must be used, the old defines must be removed.
So no need to rename the defines.
I think you should directly change to flags (in this patchset or another).

Thanks
-- 
Thomas

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [dpdk-dev] [PATCH v5 2/5] ethdev: add enum type and relevant structures for hash filter control
  2014-11-12  9:30                 ` Thomas Monjalon
@ 2014-11-12 14:22                   ` Zhang, Helin
  0 siblings, 0 replies; 71+ messages in thread
From: Zhang, Helin @ 2014-11-12 14:22 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev



> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Wednesday, November 12, 2014 5:31 PM
> To: Zhang, Helin
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v5 2/5] ethdev: add enum type and relevant
> structures for hash filter control
> 
> 2014-11-12 05:52, Zhang, Helin:
> > From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > > Actually you use ETH_FLOW_TYPE_IPV4 for ixgbe and
> > > ETH_FLOW_TYPE_FRAG_IPV4 or ETH_FLOW_TYPE_NONFRAG_IPV4_* for
> i40e.
> > > It's not consistent and clearly shows that you stick to the hardware
> definitions.
> > >
> > > Something really generic could be a set of flags like this:
> > > 	IPV4
> > > 	IPV6
> > > 	NONFRAG
> > > 	UDP
> > > 	TCP
> > > 	SCTP
> >
> > Good conclusion! We could think of it in a new patch set.
> > I don't want to put everything into this patch. :)
> 
> If you agree flags must be used, the old defines must be removed.
> So no need to rename the defines.
> I think you should directly change to flags (in this patchset or another).
I will keep it as it is in this patch for configuring hash functions. But I really
agree with your idea of using flags instead.
I will rework it in another patch set and send out a RFC to see if there is any
objections. For this patch set, I will focus on feature itself.

> 
> Thanks
> --
> Thomas

Regards,
Helin

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v6 0/3] Support configuring hash functions
  2014-10-21  3:14     ` [dpdk-dev] [PATCH v5 0/5] " Helin Zhang
                         ` (6 preceding siblings ...)
  2014-11-07  6:12       ` Chen, Erlu
@ 2014-11-19 14:58       ` Helin Zhang
  2014-11-19 14:58         ` [dpdk-dev] [PATCH v6 1/3] i40e: Use constant as the default hash keys Helin Zhang
                           ` (4 more replies)
  7 siblings, 5 replies; 71+ messages in thread
From: Helin Zhang @ 2014-11-19 14:58 UTC (permalink / raw)
  To: dev

These patches mainly support configuring hash functions.
In detail,
 - It can get or set hash functions.
 - It can configure symmetric hash functions.
   * Get/set symmetric hash enable per port.
   * Get/set symmetric hash enable per flow type.
   * Get/set filter swap configurations.
 - Six commands have been implemented in testpmd to support
   testing above.
   * get_sym_hash_ena_per_port
   * set_sym_hash_ena_per_port
   * get_sym_hash_ena_per_flow_type
   * set_sym_hash_ena_per_flow_type
   * get_filter_swap
   * set_filter_swap
   * get_hash_function
   * set_hash_function

It also uses constant hash keys to replace runtime generating
hash keys. Global initialization is added to correctly put
registers to an initial state.

v3 changes:
* Removed renamings in rte_ethdev.h.
* Redesigned filter control API and its relevant structures/enums.
* Renamed header file from rte_eth_features.h to rte_eth_ctrol.h.
* Remove public header file of rte_i40e.h specific for i40e.
* Added hardware initialization function during port init.
* Used constant random hash keys in i40e PF.
* renamed the commands in testpmd based on the redesigned filter
  control API.

v4 changes:
* Fixed a bug in testpmd to support 'set_sym_hash_ena_per_port'.

v5 changes:
* Integrated with filter API defined recently.
* Remove all for filter API definition, as it has already defined
  and merged recently.

v6 changes:
* Flow type strings are used to replace Packet Classification
  Types, to isolate hardware specific things.
* Implemented the mapping function to convert RSS offload types to
  Packet Classification Types, to isolate the real hardware
  specific things.
* Removed initialization of global registers in i40e PMD, as global
  registers shouldn't be initialized per port.
* Added more annotations to get code more understandable.
* Corrected annotation format for documenation.

Helin Zhang (3):
  i40e: Use constant as the default hash keys
  i40e: support of controlling hash functions
  app/testpmd: add commands to support hash functions

 app/test-pmd/cmdline.c            | 628 ++++++++++++++++++++++++++++++++++++++
 lib/librte_ether/rte_eth_ctrl.h   |  98 +++++-
 lib/librte_pmd_i40e/i40e_ethdev.c | 403 +++++++++++++++++++++++-
 3 files changed, 1117 insertions(+), 12 deletions(-)

-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v6 1/3] i40e: Use constant as the default hash keys
  2014-11-19 14:58       ` [dpdk-dev] [PATCH v6 0/3] " Helin Zhang
@ 2014-11-19 14:58         ` Helin Zhang
  2014-11-19 14:58         ` [dpdk-dev] [PATCH v6 2/3] i40e: support of controlling hash functions Helin Zhang
                           ` (3 subsequent siblings)
  4 siblings, 0 replies; 71+ messages in thread
From: Helin Zhang @ 2014-11-19 14:58 UTC (permalink / raw)
  To: dev

Calculating the default RSS hash keys at run time is not needed at
all, and may have race conditions. The alternative is to use array
of random values which were generated manually as the default hash
keys.

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
---
 lib/librte_pmd_i40e/i40e_ethdev.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/lib/librte_pmd_i40e/i40e_ethdev.c b/lib/librte_pmd_i40e/i40e_ethdev.c
index 5074262..9096802 100644
--- a/lib/librte_pmd_i40e/i40e_ethdev.c
+++ b/lib/librte_pmd_i40e/i40e_ethdev.c
@@ -92,7 +92,7 @@
 #define I40E_48_BIT_SHIFT 48
 #define I40E_48_BIT_MASK  0xFFFFFFFFFFFFULL
 
-/* Default queue interrupt throttling time in microseconds*/
+/* Default queue interrupt throttling time in microseconds */
 #define I40E_ITR_INDEX_DEFAULT          0
 #define I40E_QUEUE_ITR_INTERVAL_DEFAULT 32 /* 32 us */
 #define I40E_QUEUE_ITR_INTERVAL_MAX     8160 /* 8160 us */
@@ -210,9 +210,6 @@ static int i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
 				enum rte_filter_op filter_op,
 				void *arg);
 
-/* Default hash key buffer for RSS */
-static uint32_t rss_key_default[I40E_PFQF_HKEY_MAX_INDEX + 1];
-
 static struct rte_pci_id pci_id_i40e_map[] = {
 #define RTE_PCI_DEV_ID_DECL_I40E(vend, dev) {RTE_PCI_DEVICE(vend, dev)},
 #include "rte_pci_dev_ids.h"
@@ -4893,9 +4890,12 @@ i40e_pf_config_rss(struct i40e_pf *pf)
 	}
 	if (rss_conf.rss_key == NULL || rss_conf.rss_key_len <
 		(I40E_PFQF_HKEY_MAX_INDEX + 1) * sizeof(uint32_t)) {
-		/* Calculate the default hash key */
-		for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++)
-			rss_key_default[i] = (uint32_t)rte_rand();
+		/* Random default keys */
+		static uint32_t rss_key_default[] = {0x6b793944,
+			0x23504cb5, 0x5bea75b6, 0x309f4f12, 0x3dc0a2b8,
+			0x024ddcdf, 0x339b8ca0, 0x4c4af64a, 0x34fac605,
+			0x55d85839, 0x3a58997d, 0x2ec938e1, 0x66031581};
+
 		rss_conf.rss_key = (uint8_t *)rss_key_default;
 		rss_conf.rss_key_len = (I40E_PFQF_HKEY_MAX_INDEX + 1) *
 							sizeof(uint32_t);
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v6 2/3] i40e: support of controlling hash functions
  2014-11-19 14:58       ` [dpdk-dev] [PATCH v6 0/3] " Helin Zhang
  2014-11-19 14:58         ` [dpdk-dev] [PATCH v6 1/3] i40e: Use constant as the default hash keys Helin Zhang
@ 2014-11-19 14:58         ` Helin Zhang
  2014-11-19 14:58         ` [dpdk-dev] [PATCH v6 3/3] app/testpmd: add commands to support " Helin Zhang
                           ` (2 subsequent siblings)
  4 siblings, 0 replies; 71+ messages in thread
From: Helin Zhang @ 2014-11-19 14:58 UTC (permalink / raw)
  To: dev

Hash filter control has been implemented for i40e. It includes
getting/setting,
- hash function type
- symmetric hash enable per pctype (packet classification type)
- symmetric hash enable per port
- filter swap configuration

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
---
 lib/librte_ether/rte_eth_ctrl.h   |  98 +++++++++-
 lib/librte_pmd_i40e/i40e_ethdev.c | 389 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 482 insertions(+), 5 deletions(-)

v5 changes:
* Integrated with filter API defined recently.

v6 changes:
* Implemented the mapping function to convert RSS offload types to
  Packet Classification Types, to isolate the real hardware
  specific things.
* Removed initialization of global registers in i40e PMD, as global
  registers shouldn't be initialized per port.
* Added more annotations to get code more understandable.
* Corrected annotation format for documenation.

diff --git a/lib/librte_ether/rte_eth_ctrl.h b/lib/librte_ether/rte_eth_ctrl.h
index 8dd384d..1dab7d0 100644
--- a/lib/librte_ether/rte_eth_ctrl.h
+++ b/lib/librte_ether/rte_eth_ctrl.h
@@ -51,6 +51,7 @@ extern "C" {
  */
 enum rte_filter_type {
 	RTE_ETH_FILTER_NONE = 0,
+	RTE_ETH_FILTER_HASH,
 	RTE_ETH_FILTER_MACVLAN,
 	RTE_ETH_FILTER_TUNNEL,
 	RTE_ETH_FILTER_MAX
@@ -60,29 +61,116 @@ enum rte_filter_type {
  * Generic operations on filters
  */
 enum rte_filter_op {
+	/** used to check whether the type filter is supported */
 	RTE_ETH_FILTER_NOP = 0,
-	/**< used to check whether the type filter is supported */
 	RTE_ETH_FILTER_ADD,      /**< add filter entry */
 	RTE_ETH_FILTER_UPDATE,   /**< update filter entry */
 	RTE_ETH_FILTER_DELETE,   /**< delete filter entry */
 	RTE_ETH_FILTER_FLUSH,    /**< flush all entries */
 	RTE_ETH_FILTER_GET,      /**< get filter entry */
 	RTE_ETH_FILTER_SET,      /**< configurations */
+	/** get information of filter, such as status or statistics */
 	RTE_ETH_FILTER_INFO,
-	/**< get information of filter, such as status or statistics */
 	RTE_ETH_FILTER_OP_MAX
 };
 
 /**
+ * Hash filter information types.
+ * - RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_FLOW_TYPE is for getting/setting the
+ *   information/configuration of 'symmetric hash enable' per flow type.
+ * - RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT is for getting/setting the
+ *   information/configuration of 'symmetric hash enable' per port.
+ * - RTE_ETH_HASH_FILTER_SWAP is for getting/setting the swap
+ *   information/configuration which is for symmetric hash function.
+ * - RTE_ETH_HASH_FILTER_HASH_FUNCTION is for getting/setting the hash function
+ *   which could be Toeplitz or Simple Xor.
+ */
+enum rte_eth_hash_filter_info_type {
+	RTE_ETH_HASH_FILTER_INFO_TYPE_UNKNOWN = 0,
+	/** Symmetric hash enable per flow type */
+	RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_FLOW_TYPE,
+	/** Symmetric hash enable per port */
+	RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT,
+	/** Hash filter swap */
+	RTE_ETH_HASH_FILTER_SWAP,
+	/** Hash function */
+	RTE_ETH_HASH_FILTER_HASH_FUNCTION,
+	RTE_ETH_HASH_FILTER_INFO_TYPE_MAX,
+};
+
+/**
+ * Hash function types.
+ */
+enum rte_eth_hash_function {
+	RTE_ETH_HASH_FUNCTION_UNKNOWN = 0,
+	RTE_ETH_HASH_FUNCTION_TOEPLITZ, /**< Toeplitz */
+	RTE_ETH_HASH_FUNCTION_SIMPLE_XOR, /**< Simple XOR */
+	RTE_ETH_HASH_FUNCTION_MAX,
+};
+
+/**
+ * A structure used to set or get symmetric hash enable information, to support
+ * 'RTE_ETH_FILTER_HASH', 'RTE_ETH_FILTER_GET/RTE_ETH_FILTER_SET', with
+ * information type 'RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_FLOW_TYPE'.
+ * The flow type could be 'ETH_RSS_<*>_SHIFT' which is defined in rte_ethdev.h.
+ */
+struct rte_eth_sym_hash_ena_info {
+	/** Flow type, defined in rte_ethdev.h */
+	uint8_t flow_type;
+	uint8_t enable; /**< Enable or disable flag */
+};
+
+/**
+ * A structure used to set or get filter swap information, to support
+ * 'RTE_ETH_FILTER_HASH', 'RTE_ETH_FILTER_GET/RTE_ETH_FILTER_SET',
+ * with information type 'RTE_ETH_HASH_FILTER_SWAP'.
+ * The flow type could be 'ETH_RSS_<*>_SHIFT' which is defined in rte_ethdev.h.
+ */
+struct rte_eth_filter_swap_info {
+	/** Flow type, defined in rte_ethdev.h */
+	uint8_t flow_type;
+	/** Offset of the 1st field of the 1st couple to be swapped. */
+	uint8_t off0_src0;
+	/** Offset of the 2nd field of the 1st couple to be swapped. */
+	uint8_t off0_src1;
+	/** Field length of the first couple. */
+	uint8_t len0;
+	/** Offset of the 1st field of the 2nd couple to be swapped. */
+	uint8_t off1_src0;
+	/** Offset of the 2nd field of the 2nd couple to be swapped. */
+	uint8_t off1_src1;
+	/** Field length of the second couple. */
+	uint8_t len1;
+};
+
+/**
+ * A structure used to set or get hash filter information, to support filter
+ * type of 'RTE_ETH_FILTER_HASH' and its operations.
+ */
+struct rte_eth_hash_filter_info {
+	enum rte_eth_hash_filter_info_type info_type; /**< Information type. */
+	/** Details of hash filter infomation */
+	union {
+		/* For RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_FLOW_TYPE */
+		struct rte_eth_sym_hash_ena_info sym_hash_ena;
+		/* For RTE_ETH_HASH_FILTER_SWAP */
+		struct rte_eth_filter_swap_info filter_swap;
+		/* For RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT */
+		uint8_t enable;
+		/* For RTE_ETH_HASH_FILTER_HASH_FUNCTION */
+		enum rte_eth_hash_function hash_function;
+	} info;
+};
+
+/*
  * MAC filter type
  */
 enum rte_mac_filter_type {
 	RTE_MAC_PERFECT_MATCH = 1, /**< exact match of MAC addr. */
-	RTE_MACVLAN_PERFECT_MATCH,
-	/**< exact match of MAC addr and VLAN ID. */
+	RTE_MACVLAN_PERFECT_MATCH, /**< exact match of MAC addr and VLAN ID. */
 	RTE_MAC_HASH_MATCH, /**< hash match of MAC addr. */
+	/** hash match of MAC addr and exact match of VLAN ID. */
 	RTE_MACVLAN_HASH_MATCH,
-	/**< hash match of MAC addr and exact match of VLAN ID. */
 };
 
 /**
diff --git a/lib/librte_pmd_i40e/i40e_ethdev.c b/lib/librte_pmd_i40e/i40e_ethdev.c
index 9096802..4ec609b 100644
--- a/lib/librte_pmd_i40e/i40e_ethdev.c
+++ b/lib/librte_pmd_i40e/i40e_ethdev.c
@@ -99,6 +99,10 @@
 
 #define I40E_PRE_TX_Q_CFG_WAIT_US       10 /* 10 us */
 
+/* Field max of swap configurations for symmetric hash */
+#define I40E_SWAP_FIELD_LEN_MAX         0x1F
+#define I40E_SWAP_FIELD_OFFSET_MAX      0x7F
+
 /* Mask of PF interrupt causes */
 #define I40E_PFINT_ICR0_ENA_MASK ( \
 		I40E_PFINT_ICR0_ENA_ECC_ERR_MASK | \
@@ -209,6 +213,8 @@ static int i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
 				enum rte_filter_type filter_type,
 				enum rte_filter_op filter_op,
 				void *arg);
+static void i40e_hw_init(struct i40e_hw *hw);
+static uint8_t i40e_flow_type_to_pctype(uint64_t type);
 
 static struct rte_pci_id pci_id_i40e_map[] = {
 #define RTE_PCI_DEV_ID_DECL_I40E(vend, dev) {RTE_PCI_DEVICE(vend, dev)},
@@ -379,6 +385,9 @@ eth_i40e_dev_init(__rte_unused struct eth_driver *eth_drv,
 	/* Make sure all is clean before doing PF reset */
 	i40e_clear_hw(hw);
 
+	/* Initialize the hardware */
+	i40e_hw_init(hw);
+
 	/* Reset here to make sure all is clean for each PF */
 	ret = i40e_pf_reset(hw);
 	if (ret) {
@@ -4990,6 +4999,328 @@ i40e_pf_config_mq_rx(struct i40e_pf *pf)
 	return ret;
 }
 
+/* Get the symmetric hash enable configurations per flow type */
+static int
+i40e_get_symmetric_hash_enable_per_flow_type(struct i40e_hw *hw,
+			struct rte_eth_sym_hash_ena_info *info)
+{
+	uint32_t reg;
+	uint8_t pctype = i40e_flow_type_to_pctype(info->flow_type);
+
+	if (pctype > 0) {
+		reg = I40E_READ_REG(hw, I40E_GLQF_HSYM(pctype));
+		info->enable = reg & I40E_GLQF_HSYM_SYMH_ENA_MASK ? 1 : 0;
+		return 0;
+	} else {
+		PMD_DRV_LOG(ERR, "RSS type[%u] not supported", info->flow_type);
+		return -EINVAL;
+	}
+}
+
+/* Set the symmetric hash enable configurations per flow type */
+static int
+i40e_set_symmetric_hash_enable_per_flow_type(struct i40e_hw *hw,
+		const struct rte_eth_sym_hash_ena_info *info)
+{
+	uint32_t reg;
+	uint8_t pctype = i40e_flow_type_to_pctype(info->flow_type);
+
+	if (pctype > 0) {
+		reg = info->enable ? I40E_GLQF_HSYM_SYMH_ENA_MASK : 0;
+		I40E_WRITE_REG(hw, I40E_GLQF_HSYM(pctype), reg);
+		I40E_WRITE_FLUSH(hw);
+		return 0;
+	} else {
+		PMD_DRV_LOG(ERR, "RSS type[%u] not supported", info->flow_type);
+		return -EINVAL;
+	}
+}
+
+/* Get the symmetric hash enable configurations per port */
+static void
+i40e_get_symmetric_hash_enable_per_port(struct i40e_hw *hw, uint8_t *enable)
+{
+	uint32_t reg = I40E_READ_REG(hw, I40E_PRTQF_CTL_0);
+
+	*enable = reg & I40E_PRTQF_CTL_0_HSYM_ENA_MASK ? 1 : 0;
+}
+
+/* Set the symmetric hash enable configurations per port */
+static void
+i40e_set_symmetric_hash_enable_per_port(struct i40e_hw *hw, uint8_t enable)
+{
+	uint32_t reg = I40E_READ_REG(hw, I40E_PRTQF_CTL_0);
+
+	if (enable > 0) {
+		if (reg & I40E_PRTQF_CTL_0_HSYM_ENA_MASK) {
+			PMD_DRV_LOG(INFO, "Symmetric hash has already "
+							"been enabled");
+			return;
+		}
+		reg |= I40E_PRTQF_CTL_0_HSYM_ENA_MASK;
+	} else {
+		if (!(reg & I40E_PRTQF_CTL_0_HSYM_ENA_MASK)) {
+			PMD_DRV_LOG(INFO, "Symmetric hash has already "
+							"been disabled");
+			return;
+		}
+		reg &= ~I40E_PRTQF_CTL_0_HSYM_ENA_MASK;
+	}
+	I40E_WRITE_REG(hw, I40E_PRTQF_CTL_0, reg);
+	I40E_WRITE_FLUSH(hw);
+}
+
+/* Get filter swap configurations */
+static int
+i40e_get_filter_swap(struct i40e_hw *hw, struct rte_eth_filter_swap_info *info)
+{
+	uint32_t reg;
+	uint8_t pctype = i40e_flow_type_to_pctype(info->flow_type);
+
+	if (pctype > 0) {
+		reg = I40E_READ_REG(hw, I40E_GLQF_SWAP(0, pctype));
+		PMD_DRV_LOG(DEBUG, "Value read from I40E_GLQF_SWAP[0,%d]: "
+							"0x%x", pctype, reg);
+
+		/**
+		 * The offset and length read from register in word unit,
+		 * which need to be converted in byte unit before being saved.
+		 */
+		info->off0_src0 =
+			(uint8_t)((reg & I40E_GLQF_SWAP_OFF0_SRC0_MASK) >>
+					I40E_GLQF_SWAP_OFF0_SRC0_SHIFT) << 1;
+		info->off0_src1 =
+			(uint8_t)((reg & I40E_GLQF_SWAP_OFF0_SRC1_MASK) >>
+					I40E_GLQF_SWAP_OFF0_SRC1_SHIFT) << 1;
+		info->len0 = (uint8_t)((reg & I40E_GLQF_SWAP_FLEN0_MASK) >>
+					I40E_GLQF_SWAP_FLEN0_SHIFT) << 1;
+		info->off1_src0 =
+			(uint8_t)((reg & I40E_GLQF_SWAP_OFF1_SRC0_MASK) >>
+					I40E_GLQF_SWAP_OFF1_SRC0_SHIFT) << 1;
+		info->off1_src1 =
+			(uint8_t)((reg & I40E_GLQF_SWAP_OFF1_SRC1_MASK) >>
+					I40E_GLQF_SWAP_OFF1_SRC1_SHIFT) << 1;
+		info->len1 = (uint8_t)((reg & I40E_GLQF_SWAP_FLEN1_MASK) >>
+					I40E_GLQF_SWAP_FLEN1_SHIFT) << 1;
+		return 0;
+	} else {
+		PMD_DRV_LOG(ERR, "RSS type[%u] not supported", info->flow_type);
+		return -EINVAL;
+	}
+}
+
+/* Set filter swap configurations */
+static int
+i40e_set_filter_swap(struct i40e_hw *hw,
+		     const struct rte_eth_filter_swap_info *info)
+{
+	uint32_t reg;
+	uint8_t pctype = i40e_flow_type_to_pctype(info->flow_type);
+
+	if (pctype > 0) {
+		if (info->off0_src0 > I40E_SWAP_FIELD_OFFSET_MAX) {
+			PMD_DRV_LOG(ERR, "off0_src0 (0x%x) exceeds the "
+				"maximum of 0x%x", info->off0_src0,
+					I40E_SWAP_FIELD_OFFSET_MAX);
+			return I40E_ERR_PARAM;
+		} else if (info->off0_src1 > I40E_SWAP_FIELD_OFFSET_MAX) {
+			PMD_DRV_LOG(ERR, "off0_src1 (0x%x) exceeds the "
+				"maximum of 0x%x", info->off0_src1,
+					I40E_SWAP_FIELD_OFFSET_MAX);
+			return I40E_ERR_PARAM;
+		} else if (info->len0 > I40E_SWAP_FIELD_LEN_MAX) {
+			PMD_DRV_LOG(ERR, "len0 (0x%x) exceeds the maximum "
+			"of 0x%x", info->len0, I40E_SWAP_FIELD_LEN_MAX);
+			return I40E_ERR_PARAM;
+		} else if (info->off1_src0 > I40E_SWAP_FIELD_OFFSET_MAX) {
+			PMD_DRV_LOG(ERR, "off1_src0 (0x%x) exceeds the "
+				"maximum of 0x%x", info->off1_src0,
+					I40E_SWAP_FIELD_OFFSET_MAX);
+			return I40E_ERR_PARAM;
+		} else if (info->off1_src1 > I40E_SWAP_FIELD_OFFSET_MAX) {
+			PMD_DRV_LOG(ERR, "off1_src1 (0x%x) exceeds the "
+				"maximum of 0x%x", info->off1_src1,
+					I40E_SWAP_FIELD_OFFSET_MAX);
+			return I40E_ERR_PARAM;
+		} else if (info->len1 > I40E_SWAP_FIELD_LEN_MAX) {
+			PMD_DRV_LOG(ERR, "len1 (0x%x) exceeds the maximum "
+			"of 0x%x", info->len1, I40E_SWAP_FIELD_LEN_MAX);
+			return I40E_ERR_PARAM;
+		}
+
+		/**
+		 * The offset and length given in byte unit, which need to be
+		 * converted in word unit before being written to the register,
+		 * as hardware requires it in word unit.
+		 */
+		reg = (info->off0_src0 >> 1) << I40E_GLQF_SWAP_OFF0_SRC0_SHIFT;
+		reg |= (info->off0_src1 >> 1) <<
+			I40E_GLQF_SWAP_OFF0_SRC1_SHIFT;
+		reg |= (info->len0 >> 1) << I40E_GLQF_SWAP_FLEN0_SHIFT;
+		reg |= (info->off1_src0 >> 1) <<
+			I40E_GLQF_SWAP_OFF1_SRC0_SHIFT;
+		reg |= (info->off1_src1 >> 1) <<
+			I40E_GLQF_SWAP_OFF1_SRC1_SHIFT;
+		reg |= (info->len1 >> 1) << I40E_GLQF_SWAP_FLEN1_SHIFT;
+
+		PMD_DRV_LOG(DEBUG, "Value to be written to "
+			"I40E_GLQF_SWAP[0,%d]: 0x%x", pctype, reg);
+		I40E_WRITE_REG(hw, I40E_GLQF_SWAP(0, pctype), reg);
+		I40E_WRITE_FLUSH(hw);
+		return 0;
+	} else {
+		PMD_DRV_LOG(ERR, "RSS type[%u] not supported", info->flow_type);
+		return -EINVAL;
+	}
+}
+
+/* Get hash function type */
+static void
+i40e_get_hash_function(struct i40e_hw *hw, enum rte_eth_hash_function *hf)
+{
+	uint32_t reg = I40E_READ_REG(hw, I40E_GLQF_CTL);
+
+	if (reg & I40E_GLQF_CTL_HTOEP_MASK)
+		*hf = RTE_ETH_HASH_FUNCTION_TOEPLITZ;
+	else
+		*hf = RTE_ETH_HASH_FUNCTION_SIMPLE_XOR;
+
+	PMD_DRV_LOG(INFO, "Hash function is %s",
+		(reg & I40E_GLQF_CTL_HTOEP_MASK) ? "Toeplitz" : "Simple XOR");
+}
+
+/* Set hash function type */
+static int
+i40e_set_hash_function(struct i40e_hw *hw, enum rte_eth_hash_function hf)
+{
+	uint32_t reg = I40E_READ_REG(hw, I40E_GLQF_CTL);
+
+	if (hf == RTE_ETH_HASH_FUNCTION_TOEPLITZ) {
+		if (reg & I40E_GLQF_CTL_HTOEP_MASK) {
+			PMD_DRV_LOG(DEBUG, "Hash function already set to "
+								"Toeplitz");
+			return 0;
+		}
+		reg |= I40E_GLQF_CTL_HTOEP_MASK;
+	} else if (hf == RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) {
+		if (!(reg & I40E_GLQF_CTL_HTOEP_MASK)) {
+			PMD_DRV_LOG(DEBUG, "Hash function already set to "
+							"Simple XOR");
+			return 0;
+		}
+		reg &= ~I40E_GLQF_CTL_HTOEP_MASK;
+	} else {
+		PMD_DRV_LOG(ERR, "Unknown hash function type");
+		return -EINVAL;
+	}
+
+	PMD_DRV_LOG(INFO, "Hash function set to %s",
+		(reg & I40E_GLQF_CTL_HTOEP_MASK) ? "Toeplitz" : "Simple XOR");
+	I40E_WRITE_REG(hw, I40E_GLQF_CTL, reg);
+	I40E_WRITE_FLUSH(hw);
+
+	return 0;
+}
+
+static int
+i40e_hash_filter_get(struct i40e_hw *hw, struct rte_eth_hash_filter_info *info)
+{
+	int ret = 0;
+
+	if (!hw || !info) {
+		PMD_DRV_LOG(ERR, "Invalid pointer");
+		return -EFAULT;
+	}
+
+	switch (info->info_type) {
+	case RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_FLOW_TYPE:
+		ret = i40e_get_symmetric_hash_enable_per_flow_type(hw,
+					&(info->info.sym_hash_ena));
+		break;
+	case RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT:
+		i40e_get_symmetric_hash_enable_per_port(hw,
+					&(info->info.enable));
+		break;
+	case RTE_ETH_HASH_FILTER_SWAP:
+		ret = i40e_get_filter_swap(hw, &(info->info.filter_swap));
+		break;
+	case RTE_ETH_HASH_FILTER_HASH_FUNCTION:
+		i40e_get_hash_function(hw, &(info->info.hash_function));
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "Hash filter info type (%d) not supported",
+							info->info_type);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int
+i40e_hash_filter_set(struct i40e_hw *hw, struct rte_eth_hash_filter_info *info)
+{
+	int ret = 0;
+
+	if (!hw || !info) {
+		PMD_DRV_LOG(ERR, "Invalid pointer");
+		return -EFAULT;
+	}
+
+	switch (info->info_type) {
+	case RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_FLOW_TYPE:
+		ret = i40e_set_symmetric_hash_enable_per_flow_type(hw,
+					&(info->info.sym_hash_ena));
+		break;
+	case RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT:
+		i40e_set_symmetric_hash_enable_per_port(hw, info->info.enable);
+		break;
+	case RTE_ETH_HASH_FILTER_SWAP:
+		ret = i40e_set_filter_swap(hw, &(info->info.filter_swap));
+		break;
+	case RTE_ETH_HASH_FILTER_HASH_FUNCTION:
+		ret = i40e_set_hash_function(hw, info->info.hash_function);
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "Hash filter info type (%d) not supported",
+							info->info_type);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+/* Operations for hash function */
+static int
+i40e_hash_filter_ctrl(struct rte_eth_dev *dev,
+		      enum rte_filter_op filter_op,
+		      void *arg)
+{
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	int ret = 0;
+
+	switch (filter_op) {
+	case RTE_ETH_FILTER_NOP:
+		break;
+	case RTE_ETH_FILTER_GET:
+		ret = i40e_hash_filter_get(hw,
+			(struct rte_eth_hash_filter_info *)arg);
+		break;
+	case RTE_ETH_FILTER_SET:
+		ret = i40e_hash_filter_set(hw,
+			(struct rte_eth_hash_filter_info *)arg);
+		break;
+	default:
+		PMD_DRV_LOG(WARNING, "Filter operation (%d) not supported",
+								filter_op);
+		ret = -ENOTSUP;
+		break;
+	}
+
+	return ret;
+}
+
 static int
 i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
 		     enum rte_filter_type filter_type,
@@ -5002,6 +5333,9 @@ i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
 		return -EINVAL;
 
 	switch (filter_type) {
+	case RTE_ETH_FILTER_HASH:
+		ret = i40e_hash_filter_ctrl(dev, filter_op, arg);
+		break;
 	case RTE_ETH_FILTER_MACVLAN:
 		ret = i40e_mac_filter_handle(dev, filter_op, arg);
 		break;
@@ -5017,3 +5351,58 @@ i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
 
 	return ret;
 }
+
+/*
+ * As some registers wouldn't be reset unless a global hardware reset,
+ * hardware initialization is needed to put those registers into an
+ * expected initial state.
+ */
+static void
+i40e_hw_init(struct i40e_hw *hw)
+{
+	/* clear the PF Queue Filter control register */
+	I40E_WRITE_REG(hw, I40E_PFQF_CTL_0, 0);
+
+	/* Disable symmetric hash per port */
+	i40e_set_symmetric_hash_enable_per_port(hw, 0);
+}
+
+static uint8_t
+i40e_flow_type_to_pctype(uint64_t type)
+{
+	struct flow_type_pctype_t {
+		uint8_t flow_type;
+		uint8_t pctype;
+	};
+	uint32_t i;
+	static const struct flow_type_pctype_t flow_type_pctype_table[] = {
+		{ETH_RSS_NONF_IPV4_UDP_SHIFT,
+			I40E_FILTER_PCTYPE_NONF_IPV4_UDP},
+		{ETH_RSS_NONF_IPV4_TCP_SHIFT,
+			I40E_FILTER_PCTYPE_NONF_IPV4_TCP},
+		{ETH_RSS_NONF_IPV4_SCTP_SHIFT,
+			I40E_FILTER_PCTYPE_NONF_IPV4_SCTP},
+		{ETH_RSS_NONF_IPV4_OTHER_SHIFT,
+			I40E_FILTER_PCTYPE_NONF_IPV4_OTHER},
+		{ETH_RSS_FRAG_IPV4_SHIFT,
+			I40E_FILTER_PCTYPE_FRAG_IPV4},
+		{ETH_RSS_NONF_IPV6_UDP_SHIFT,
+			I40E_FILTER_PCTYPE_NONF_IPV6_UDP},
+		{ETH_RSS_NONF_IPV6_TCP_SHIFT,
+			I40E_FILTER_PCTYPE_NONF_IPV6_TCP},
+		{ETH_RSS_NONF_IPV6_SCTP_SHIFT,
+			I40E_FILTER_PCTYPE_NONF_IPV6_SCTP},
+		{ETH_RSS_NONF_IPV6_OTHER_SHIFT,
+			I40E_FILTER_PCTYPE_NONF_IPV6_OTHER},
+		{ETH_RSS_FRAG_IPV6_SHIFT,
+			I40E_FILTER_PCTYPE_FRAG_IPV6},
+		{ETH_RSS_L2_PAYLOAD_SHIFT,
+			I40E_FILTER_PCTYPE_L2_PAYLOAD}
+	};
+
+	for (i = 0; i < RTE_DIM(flow_type_pctype_table); i++)
+		if (type == flow_type_pctype_table[i].flow_type)
+			return flow_type_pctype_table[i].pctype;
+
+	return 0;
+}
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v6 3/3] app/testpmd: add commands to support hash functions
  2014-11-19 14:58       ` [dpdk-dev] [PATCH v6 0/3] " Helin Zhang
  2014-11-19 14:58         ` [dpdk-dev] [PATCH v6 1/3] i40e: Use constant as the default hash keys Helin Zhang
  2014-11-19 14:58         ` [dpdk-dev] [PATCH v6 2/3] i40e: support of controlling hash functions Helin Zhang
@ 2014-11-19 14:58         ` Helin Zhang
  2014-11-27 15:45         ` [dpdk-dev] [PATCH v6 0/3] Support configuring " Thomas Monjalon
  2014-11-28 12:14         ` [dpdk-dev] [PATCH v7 0/4] " Helin Zhang
  4 siblings, 0 replies; 71+ messages in thread
From: Helin Zhang @ 2014-11-19 14:58 UTC (permalink / raw)
  To: dev

To demonstrate the hash filter control, commands are added.
They are,
- get_sym_hash_ena_per_port
- set_sym_hash_ena_per_port
- get_sym_hash_ena_per_pctype
- set_sym_hash_ena_per_pctype
- get_filter_swap
- set_filter_swap
- get_hash_function
- set_hash_function

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
---
 app/test-pmd/cmdline.c | 628 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 628 insertions(+)

v6 changes:
* Flow type strings are used to replace Packet Classification
  Types, to isolate hardware specific things.

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 4c3fc76..ce1547d 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -74,6 +74,7 @@
 #include <rte_ethdev.h>
 #include <rte_string_fns.h>
 #include <rte_devargs.h>
+#include <rte_eth_ctrl.h>
 
 #include <cmdline_rdline.h>
 #include <cmdline_parse.h>
@@ -683,6 +684,44 @@ static void cmd_help_long_parsed(void *parsed_result,
 
 			"get_flex_filter (port_id) index (idx)\n"
 			"    get info of a flex filter.\n\n"
+
+			"get_sym_hash_ena_per_port (port_id)\n"
+			"    get symmetric hash enable configuration per port.\n\n"
+
+			"set_sym_hash_ena_per_port (port_id)"
+			" (enable|disable)\n"
+			"    set symmetric hash enable configuration per port"
+			" to enable or disable.\n\n"
+
+			"get_sym_hash_ena_per_flow_type (port_id) (ipv4-udp|"
+			"ipv4-tcp|ipv4-sctp|ipv4-other|ipv4-frag|ipv6-udp|"
+			"ipv6-tcp|ipv6-sctp|ipv6-other|ipv6-frag|l2_payload)\n"
+			"    get symmetric hash enable configuration per flow type.\n\n"
+
+			"set_sym_hash_ena_per_flow_type (port_id) (ipv4-udp|"
+			"ipv4-tcp|ipv4-sctp|ipv4-other|ipv4-frag|ipv6-udp|"
+			"ipv6-tcp|ipv6-sctp|ipv6-other|ipv6-frag|l2_payload) "
+			"(enable|disable)\n"
+			"    set symmetric hash enable configuration per"
+			" flow type to enable or disable.\n\n"
+
+			"get_filter_swap (port_id) (ipv4-udp|ipv4-tcp|"
+			"ipv4-sctp|ipv4-other|ipv4-frag|ipv6-udp|ipv6-tcp|"
+			"ipv6-sctp|ipv6-other|ipv6-frag|l2_payload)\n"
+			"    get filter swap configurations.\n\n"
+
+			"set_filter_swap (port_id) (ipv4-udp|ipv4-tcp|"
+			"ipv4-sctp|ipv4-other|ipv4-frag|ipv6-udp|ipv6-tcp|"
+			"ipv6-sctp|ipv6-other|ipv6-frag|l2_payload) "
+			"(off0_src0) (off0_src1) (len0) (off1_src0) "
+			"(off1_src1) (len1)\n"
+			"    set filter swap configurations.\n\n"
+
+			"get_hash_function (port_id)\n"
+			"    get hash function of Toeplitz or Simple XOR.\n\n"
+
+			"set_hash_function (port_id) (toeplitz|simple_xor)\n"
+			"    set the hash function to Toeplitz or Simple XOR.\n\n"
 		);
 	}
 }
@@ -7745,6 +7784,587 @@ cmdline_parse_inst_t cmd_get_flex_filter = {
 	},
 };
 
+/* *** Classification Filters Control *** */
+static uint8_t
+parse_flow_type(const char *str)
+{
+	struct flow_type_pair {
+		char str[STR_TOKEN_SIZE];
+		uint8_t flow_type;
+	};
+	uint32_t i;
+	static const struct flow_type_pair ftype[] = {
+		{"ipv4-udp",   ETH_RSS_NONF_IPV4_UDP_SHIFT},
+		{"ipv4-tcp",   ETH_RSS_NONF_IPV4_TCP_SHIFT},
+		{"ipv4-sctp",  ETH_RSS_NONF_IPV4_SCTP_SHIFT},
+		{"ipv4-other", ETH_RSS_NONF_IPV4_OTHER_SHIFT},
+		{"ipv4-frag",  ETH_RSS_FRAG_IPV4_SHIFT},
+		{"ipv6-udp",   ETH_RSS_NONF_IPV6_UDP_SHIFT},
+		{"ipv6-tcp",   ETH_RSS_NONF_IPV6_TCP_SHIFT},
+		{"ipv6-sctp",  ETH_RSS_NONF_IPV6_SCTP_SHIFT},
+		{"ipv6-other", ETH_RSS_NONF_IPV6_OTHER_SHIFT},
+		{"ipv6-frag",  ETH_RSS_FRAG_IPV6_SHIFT},
+		{"l2_payload", ETH_RSS_L2_PAYLOAD_SHIFT},
+	};
+
+	if (!str)
+		return 0xFF;
+
+	for (i = 0; i < RTE_DIM(ftype); i++) {
+		if (!strcmp(ftype[i].str, str))
+			return ftype[i].flow_type;
+	}
+
+	return 0xFF;
+}
+
+/* *** Get symmetric hash enable per port *** */
+struct cmd_get_sym_hash_ena_per_port_result {
+	cmdline_fixed_string_t get_sym_hash_ena_per_port;
+	uint8_t port_id;
+};
+
+static void
+cmd_get_sym_hash_per_port_parsed(void *parsed_result,
+				 __rte_unused struct cmdline *cl,
+				 __rte_unused void *data)
+{
+	struct cmd_get_sym_hash_ena_per_port_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port: %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT;
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+						RTE_ETH_FILTER_GET, &info);
+	if (ret < 0) {
+		printf("Cannot get symmetric hash enable per port "
+					"on port %u\n", res->port_id);
+		return;
+	}
+
+	printf("Symmetric hash is %s on port %u\n", info.info.enable ?
+				"enabled" : "disabled", res->port_id);
+}
+
+cmdline_parse_token_string_t cmd_get_sym_hash_ena_per_port_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_get_sym_hash_ena_per_port_result,
+		get_sym_hash_ena_per_port, "get_sym_hash_ena_per_port");
+cmdline_parse_token_num_t cmd_get_sym_hash_ena_per_port_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_get_sym_hash_ena_per_port_result,
+		port_id, UINT8);
+
+cmdline_parse_inst_t cmd_get_sym_hash_ena_per_port = {
+	.f = cmd_get_sym_hash_per_port_parsed,
+	.data = NULL,
+	.help_str = "get_sym_hash_ena_per_port port_id",
+	.tokens = {
+		(void *)&cmd_get_sym_hash_ena_per_port_all,
+		(void *)&cmd_get_sym_hash_ena_per_port_port_id,
+		NULL,
+	},
+};
+
+/* *** Set symmetric hash enable per port *** */
+struct cmd_set_sym_hash_ena_per_port_result {
+	cmdline_fixed_string_t set_sym_hash_ena_per_port;
+	cmdline_fixed_string_t enable;
+	uint8_t port_id;
+};
+
+static void
+cmd_set_sym_hash_per_port_parsed(void *parsed_result,
+				 __rte_unused struct cmdline *cl,
+				 __rte_unused void *data)
+{
+	struct cmd_set_sym_hash_ena_per_port_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port: %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT;
+	if (!strcmp(res->enable, "enable"))
+		info.info.enable = 1;
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+						RTE_ETH_FILTER_SET, &info);
+	if (ret < 0) {
+		printf("Cannot set symmetric hash enable per port on "
+					"port %u\n", res->port_id);
+		return;
+	}
+
+	printf("Symmetric hash has been set to %s on port %u\n",
+					res->enable, res->port_id);
+}
+
+cmdline_parse_token_string_t cmd_set_sym_hash_ena_per_port_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_sym_hash_ena_per_port_result,
+		set_sym_hash_ena_per_port, "set_sym_hash_ena_per_port");
+cmdline_parse_token_num_t cmd_set_sym_hash_ena_per_port_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_sym_hash_ena_per_port_result,
+		port_id, UINT8);
+cmdline_parse_token_string_t cmd_set_sym_hash_ena_per_port_enable =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_sym_hash_ena_per_port_result,
+		enable, "enable#disable");
+
+cmdline_parse_inst_t cmd_set_sym_hash_ena_per_port = {
+	.f = cmd_set_sym_hash_per_port_parsed,
+	.data = NULL,
+	.help_str = "set_sym_hash_ena_per_port port_id enable|disable",
+	.tokens = {
+		(void *)&cmd_set_sym_hash_ena_per_port_all,
+		(void *)&cmd_set_sym_hash_ena_per_port_port_id,
+		(void *)&cmd_set_sym_hash_ena_per_port_enable,
+		NULL,
+	},
+};
+
+/* *** Get symmetric hash enable per flow_type *** */
+struct cmd_get_sym_hash_ena_per_flow_type_result {
+	cmdline_fixed_string_t get_sym_hash_ena_per_flow_type;
+	uint8_t port_id;
+	cmdline_fixed_string_t flow_type;
+};
+
+static void
+cmd_get_sym_hash_per_flow_type_parsed(void *parsed_result,
+				      __rte_unused struct cmdline *cl,
+				      __rte_unused void *data)
+{
+	struct cmd_get_sym_hash_ena_per_flow_type_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port: %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type =
+		RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_FLOW_TYPE;
+	info.info.sym_hash_ena.flow_type = parse_flow_type(res->flow_type);
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+						RTE_ETH_FILTER_GET, &info);
+	if (ret < 0) {
+		printf("Cannot get symmetric hash enable per flow_type on "
+						"port %u, flow_type %s\n",
+						res->port_id, res->flow_type);
+		return;
+	}
+	printf("Symmetric hash is %s on port %u, flow_type %s\n",
+			info.info.sym_hash_ena.enable ? "enabled" :
+			"disabled", res->port_id, res->flow_type);
+}
+
+cmdline_parse_token_string_t cmd_get_sym_hash_ena_per_flow_type_all =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_get_sym_hash_ena_per_flow_type_result,
+			get_sym_hash_ena_per_flow_type,
+			"get_sym_hash_ena_per_flow_type");
+cmdline_parse_token_num_t cmd_get_sym_hash_ena_per_flow_type_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_get_sym_hash_ena_per_flow_type_result,
+		port_id, UINT8);
+cmdline_parse_token_string_t cmd_get_sym_hash_ena_per_flow_type_flow_type =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_get_sym_hash_ena_per_flow_type_result, flow_type,
+		"ipv4-udp#ipv4-tcp#ipv4-sctp#ipv4-other#ipv4-frag#ipv6-udp#"
+		"ipv6-tcp#ipv6-sctp#ipv6-other#ipv6-frag#l2_payload");
+
+cmdline_parse_inst_t cmd_get_sym_hash_ena_per_flow_type = {
+	.f = cmd_get_sym_hash_per_flow_type_parsed,
+	.data = NULL,
+	.help_str = "get_sym_hash_ena_per_flow_type port_id ipv4-udp|ipv4-tcp|"
+		"ipv4-sctp|ipv4-other|ipv4-frag|ipv6-udp|ipv6-tcp|ipv6-sctp|"
+		"ipv6-other|ipv6-frag|l2_payload",
+	.tokens = {
+		(void *)&cmd_get_sym_hash_ena_per_flow_type_all,
+		(void *)&cmd_get_sym_hash_ena_per_flow_type_port_id,
+		(void *)&cmd_get_sym_hash_ena_per_flow_type_flow_type,
+		NULL,
+	},
+};
+
+/* *** Set symmetric hash enable per flow_type *** */
+struct cmd_set_sym_hash_ena_per_flow_type_result {
+	cmdline_fixed_string_t set_sym_hash_ena_per_flow_type;
+	cmdline_fixed_string_t enable;
+	uint8_t port_id;
+	cmdline_fixed_string_t flow_type;
+};
+
+static void
+cmd_set_sym_hash_per_flow_type_parsed(void *parsed_result,
+				      __rte_unused struct cmdline *cl,
+				      __rte_unused void *data)
+{
+	struct cmd_set_sym_hash_ena_per_flow_type_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port: %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type =
+		RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_FLOW_TYPE;
+	info.info.sym_hash_ena.flow_type = parse_flow_type(res->flow_type);
+	if (!strcmp(res->enable, "enable"))
+		info.info.sym_hash_ena.enable = 1;
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+						RTE_ETH_FILTER_SET, &info);
+	if (ret < 0) {
+		printf("Cannot set symmetric hash enable per flow_type to %s "
+			"on port %u, flow_type %s\n", res->enable ? "enabled" :
+				"disabled", res->port_id, res->flow_type);
+		return;
+	}
+	printf("Symmetic hash has been set to %s on port %u, flow_type %s\n",
+				res->enable, res->port_id, res->flow_type);
+}
+
+cmdline_parse_token_string_t cmd_set_sym_hash_ena_per_flow_type_all =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_sym_hash_ena_per_flow_type_result,
+				set_sym_hash_ena_per_flow_type,
+				"set_sym_hash_ena_per_flow_type");
+cmdline_parse_token_num_t cmd_set_sym_hash_ena_per_flow_type_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_sym_hash_ena_per_flow_type_result,
+		port_id, UINT8);
+cmdline_parse_token_string_t cmd_set_sym_hash_ena_per_flow_type_flow_type =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_sym_hash_ena_per_flow_type_result, flow_type,
+		"ipv4-udp#ipv4-tcp#ipv4-sctp#ipv4-other#ipv4-frag#ipv6-udp#"
+		"ipv6-tcp#ipv6-sctp#ipv6-other#ipv6-frag#l2_payload");
+cmdline_parse_token_string_t cmd_set_sym_hash_ena_per_flow_type_enable =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_sym_hash_ena_per_flow_type_result,
+		enable, "enable#disable");
+
+cmdline_parse_inst_t cmd_set_sym_hash_ena_per_flow_type = {
+	.f = cmd_set_sym_hash_per_flow_type_parsed,
+	.data = NULL,
+	.help_str = "set_sym_hash_ena_per_flow_type pord_id ipv4-udp|ipv4-tcp|"
+		"ipv4-sctp|ipv4-other|ipv4-frag|ipv6-udp|ipv6-tcp|ipv6-sctp|"
+		"ipv6-other|ipv6-frag|l2_payload enable|disable",
+	.tokens = {
+		(void *)&cmd_set_sym_hash_ena_per_flow_type_all,
+		(void *)&cmd_set_sym_hash_ena_per_flow_type_port_id,
+		(void *)&cmd_set_sym_hash_ena_per_flow_type_flow_type,
+		(void *)&cmd_set_sym_hash_ena_per_flow_type_enable,
+		NULL,
+	},
+};
+
+/* *** Get filter swap *** */
+struct cmd_get_filter_swap_result {
+	cmdline_fixed_string_t get_filter_swap;
+	uint8_t port_id;
+	cmdline_fixed_string_t flow_type;
+};
+
+static void
+cmd_get_filter_swap_parsed(void *parsed_result,
+			   __rte_unused struct cmdline *cl,
+			   __rte_unused void *data)
+{
+	struct cmd_get_filter_swap_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port: %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_SWAP;
+	info.info.filter_swap.flow_type = parse_flow_type(res->flow_type);
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+						RTE_ETH_FILTER_GET, &info);
+	if (ret < 0) {
+		printf("Cannot get filter swap on port %u, flow_type %s\n",
+					res->port_id, res->flow_type);
+		return;
+	}
+	printf("Filter swap of port %u, flow_type %s is configured as:\n"
+		"off0_src0: 0x%02x, off0_src1: 0x%02x, len0: 0x%02x\n"
+		"off1_src0: 0x%02x, off1_src1: 0x%02x, len1: 0x%02x\n",
+		res->port_id, res->flow_type, info.info.filter_swap.off0_src0,
+		info.info.filter_swap.off0_src1, info.info.filter_swap.len0,
+		info.info.filter_swap.off1_src0,
+		info.info.filter_swap.off1_src1, info.info.filter_swap.len1);
+}
+
+cmdline_parse_token_string_t cmd_get_filter_swap_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_get_filter_swap_result,
+		get_filter_swap, "get_filter_swap");
+cmdline_parse_token_num_t cmd_get_filter_swap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_get_filter_swap_result,
+		port_id, UINT8);
+cmdline_parse_token_string_t cmd_get_filter_swap_flow_type =
+	TOKEN_STRING_INITIALIZER(struct cmd_get_filter_swap_result, flow_type,
+		"ipv4-udp#ipv4-tcp#ipv4-sctp#ipv4-other#ipv4-frag#ipv6-udp#"
+		"ipv6-tcp#ipv6-sctp#ipv6-other#ipv6-frag#l2_payload");
+
+cmdline_parse_inst_t cmd_get_filter_swap = {
+	.f = cmd_get_filter_swap_parsed,
+	.data = NULL,
+	.help_str = "get_filter_swap port_id ipv4-udp|ipv4-tcp|ipv4-sctp|"
+		"ipv4-other|ipv4-frag|ipv6-udp|ipv6-tcp|ipv6-sctp|ipv6-other|"
+		"ipv6-frag|l2_payload",
+	.tokens = {
+		(void *)&cmd_get_filter_swap_all,
+		(void *)&cmd_get_filter_swap_port_id,
+		(void *)&cmd_get_filter_swap_flow_type,
+		NULL,
+	},
+};
+
+/* *** Set filter swap *** */
+struct cmd_set_filter_swap_result {
+	cmdline_fixed_string_t set_filter_swap;
+	uint8_t port_id;
+	cmdline_fixed_string_t flow_type;
+	uint8_t off0_src0;
+	uint8_t off0_src1;
+	uint8_t len0;
+	uint8_t off1_src0;
+	uint8_t off1_src1;
+	uint8_t len1;
+};
+
+static void
+cmd_set_filter_swap_parsed(void *parsed_result,
+			   __rte_unused struct cmdline *cl,
+			   __rte_unused void *data)
+{
+	struct cmd_set_filter_swap_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port: %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_SWAP;
+	info.info.filter_swap.flow_type = parse_flow_type(res->flow_type);
+	info.info.filter_swap.off0_src0 = res->off0_src0;
+	info.info.filter_swap.off0_src1 = res->off0_src1;
+	info.info.filter_swap.len0 = res->len0;
+	info.info.filter_swap.off1_src0 = res->off1_src0;
+	info.info.filter_swap.off1_src1 = res->off1_src1;
+	info.info.filter_swap.len1 = res->len1;
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+						RTE_ETH_FILTER_SET, &info);
+	if (ret < 0) {
+		printf("Cannot set filter swap on port %u, flow_type %s\n",
+					res->port_id, res->flow_type);
+		return;
+	}
+	printf("Filter swap of port %u, flow_type %s has been set as:\n"
+		"off0_src0: 0x%02x, off0_src1: 0x%02x, len0: 0x%02x\n"
+		"off1_src0: 0x%02x, off1_src1: 0x%02x, len1: 0x%02x\n",
+		res->port_id, res->flow_type, info.info.filter_swap.off0_src0,
+		info.info.filter_swap.off0_src1, info.info.filter_swap.len0,
+		info.info.filter_swap.off1_src0,
+		info.info.filter_swap.off1_src1, info.info.filter_swap.len1);
+}
+
+cmdline_parse_token_string_t cmd_set_filter_swap_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_filter_swap_result,
+		set_filter_swap, "set_filter_swap");
+cmdline_parse_token_num_t cmd_set_filter_swap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_filter_swap_result,
+		port_id, UINT8);
+cmdline_parse_token_string_t cmd_set_filter_swap_flow_type =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_filter_swap_result, flow_type,
+		"ipv4-udp#ipv4-tcp#ipv4-sctp#ipv4-other#ipv4-frag#ipv6-udp#"
+		"ipv6-tcp#ipv6-sctp#ipv6-other#ipv6-frag#l2_payload");
+cmdline_parse_token_num_t cmd_set_filter_swap_off0_src0 =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_filter_swap_result,
+		off0_src0, UINT8);
+cmdline_parse_token_num_t cmd_set_filter_swap_off0_src1 =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_filter_swap_result,
+		off0_src1, UINT8);
+cmdline_parse_token_num_t cmd_set_filter_swap_len0 =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_filter_swap_result,
+		len0, UINT8);
+cmdline_parse_token_num_t cmd_set_filter_swap_off1_src0 =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_filter_swap_result,
+		off1_src0, UINT8);
+cmdline_parse_token_num_t cmd_set_filter_swap_off1_src1 =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_filter_swap_result,
+		off1_src1, UINT8);
+cmdline_parse_token_num_t cmd_set_filter_swap_len1 =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_filter_swap_result,
+		len1, UINT8);
+
+cmdline_parse_inst_t cmd_set_filter_swap = {
+	.f = cmd_set_filter_swap_parsed,
+	.data = NULL,
+	.help_str = "set_filter_swap port_id ipv4-udp|ipv4-tcp|ipv4-sctp|"
+		"ipv4-other|ipv4-frag|ipv6-udp|ipv6-tcp|ipv6-sctp|ipv6-other|"
+		"ipv6-frag|l2_payload off0_src0 off0_src1 len0 off1_src0 "
+		"off1_src1 len1",
+	.tokens = {
+		(void *)&cmd_set_filter_swap_all,
+		(void *)&cmd_set_filter_swap_port_id,
+		(void *)&cmd_set_filter_swap_flow_type,
+		(void *)&cmd_set_filter_swap_off0_src0,
+		(void *)&cmd_set_filter_swap_off0_src1,
+		(void *)&cmd_set_filter_swap_len0,
+		(void *)&cmd_set_filter_swap_off1_src0,
+		(void *)&cmd_set_filter_swap_off1_src1,
+		(void *)&cmd_set_filter_swap_len1,
+		NULL,
+	},
+};
+
+/* Get hash function */
+struct cmd_get_hash_function_result {
+	cmdline_fixed_string_t get_hash_function;
+	uint8_t port_id;
+};
+
+static void
+cmd_get_hash_function_parsed(void *parsed_result,
+			     __rte_unused struct cmdline *cl,
+			     __rte_unused void *data)
+{
+	struct cmd_get_hash_function_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_HASH_FUNCTION;
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+						RTE_ETH_FILTER_GET, &info);
+	if (ret < 0) {
+		printf("Cannot get hash function on port %d\n", res->port_id);
+		return;
+	}
+	printf("Hash function is %s\n", info.info.hash_function ==
+		RTE_ETH_HASH_FUNCTION_TOEPLITZ ? "Toeplitz" : "Simple XOR");
+}
+
+cmdline_parse_token_string_t cmd_get_hash_function_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_get_hash_function_result,
+		get_hash_function, "get_hash_function");
+cmdline_parse_token_num_t cmd_get_hash_function_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_get_hash_function_result,
+		port_id, UINT8);
+
+cmdline_parse_inst_t cmd_get_hash_function = {
+	.f = cmd_get_hash_function_parsed,
+	.data = NULL,
+	.help_str = "get_hash_function port_id",
+	.tokens = {
+		(void *)&cmd_get_hash_function_all,
+		(void *)&cmd_get_hash_function_port_id,
+		NULL,
+	},
+};
+
+/* Set hash function of Hoeplitz or Simple XOR */
+struct cmd_set_hash_function_result {
+	cmdline_fixed_string_t set_hash_function;
+	uint8_t port_id;
+	cmdline_fixed_string_t hash_function;
+};
+
+static void
+cmd_set_hash_function_parsed(void *parsed_result,
+			     __rte_unused struct cmdline *cl,
+			     __rte_unused void *data)
+{
+	struct cmd_set_hash_function_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_HASH_FUNCTION;
+	if (!strcmp(res->hash_function, "toeplitz"))
+		info.info.hash_function = RTE_ETH_HASH_FUNCTION_TOEPLITZ;
+	else if (!strcmp(res->hash_function, "simple_xor"))
+		info.info.hash_function = RTE_ETH_HASH_FUNCTION_SIMPLE_XOR;
+	else {
+		printf("Unsupported hash function %s\n", res->hash_function);
+		return;
+	}
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+						RTE_ETH_FILTER_SET, &info);
+	if (ret < 0) {
+		printf("Cannot set hash function to %s on port %d\n",
+				res->hash_function, res->port_id);
+		return;
+	}
+	printf("Hash function has been successfully set to %s on port %d\n",
+					res->hash_function, res->port_id);
+}
+
+cmdline_parse_token_string_t cmd_set_hash_function_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_hash_function_result,
+		set_hash_function, "set_hash_function");
+cmdline_parse_token_num_t cmd_set_hash_function_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_hash_function_result,
+		port_id, UINT8);
+cmdline_parse_token_string_t cmd_set_hash_function_hash_function =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_hash_function_result,
+		hash_function, "toeplitz#simple_xor");
+
+cmdline_parse_inst_t cmd_set_hash_function = {
+	.f = cmd_set_hash_function_parsed,
+	.data = NULL,
+	.help_str = "set_hash_function port_id toeplitz|simple_xor",
+	.tokens = {
+		(void *)&cmd_set_hash_function_all,
+		(void *)&cmd_set_hash_function_port_id,
+		(void *)&cmd_set_hash_function_hash_function,
+		NULL,
+	},
+};
+
 /* ******************************************************************************** */
 
 /* list of instructions */
@@ -7874,6 +8494,14 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_add_flex_filter,
 	(cmdline_parse_inst_t *)&cmd_remove_flex_filter,
 	(cmdline_parse_inst_t *)&cmd_get_flex_filter,
+	(cmdline_parse_inst_t *)&cmd_get_sym_hash_ena_per_port,
+	(cmdline_parse_inst_t *)&cmd_set_sym_hash_ena_per_port,
+	(cmdline_parse_inst_t *)&cmd_get_sym_hash_ena_per_flow_type,
+	(cmdline_parse_inst_t *)&cmd_set_sym_hash_ena_per_flow_type,
+	(cmdline_parse_inst_t *)&cmd_get_filter_swap,
+	(cmdline_parse_inst_t *)&cmd_set_filter_swap,
+	(cmdline_parse_inst_t *)&cmd_set_hash_function,
+	(cmdline_parse_inst_t *)&cmd_get_hash_function,
 	NULL,
 };
 
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [dpdk-dev] [PATCH v6 0/3] Support configuring hash functions
  2014-11-19 14:58       ` [dpdk-dev] [PATCH v6 0/3] " Helin Zhang
                           ` (2 preceding siblings ...)
  2014-11-19 14:58         ` [dpdk-dev] [PATCH v6 3/3] app/testpmd: add commands to support " Helin Zhang
@ 2014-11-27 15:45         ` Thomas Monjalon
  2014-11-27 16:17           ` Zhang, Helin
  2014-11-28 12:14         ` [dpdk-dev] [PATCH v7 0/4] " Helin Zhang
  4 siblings, 1 reply; 71+ messages in thread
From: Thomas Monjalon @ 2014-11-27 15:45 UTC (permalink / raw)
  To: Helin Zhang; +Cc: dev

Hi Helin,

I think you are working on a v7 of this patchset, right?
Any news?

-- 
Thomas

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [dpdk-dev] [PATCH v6 0/3] Support configuring hash functions
  2014-11-27 15:45         ` [dpdk-dev] [PATCH v6 0/3] Support configuring " Thomas Monjalon
@ 2014-11-27 16:17           ` Zhang, Helin
  0 siblings, 0 replies; 71+ messages in thread
From: Zhang, Helin @ 2014-11-27 16:17 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev

Hi Thomas

Yes, I am working on it. But still a few review comments should be dealt with.
Hopefully I can send it out tomorrow. Thank you!

Regards,
Helin

> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Thursday, November 27, 2014 11:45 PM
> To: Zhang, Helin
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v6 0/3] Support configuring hash functions
> 
> Hi Helin,
> 
> I think you are working on a v7 of this patchset, right?
> Any news?
> 
> --
> Thomas

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v7 0/4] Support configuring hash functions
  2014-11-19 14:58       ` [dpdk-dev] [PATCH v6 0/3] " Helin Zhang
                           ` (3 preceding siblings ...)
  2014-11-27 15:45         ` [dpdk-dev] [PATCH v6 0/3] Support configuring " Thomas Monjalon
@ 2014-11-28 12:14         ` Helin Zhang
  2014-11-28 12:14           ` [dpdk-dev] [PATCH v7 1/4] ethdev: code style fixes Helin Zhang
                             ` (4 more replies)
  4 siblings, 5 replies; 71+ messages in thread
From: Helin Zhang @ 2014-11-28 12:14 UTC (permalink / raw)
  To: dev

These patches mainly support configuring hash functions. In detail,
 - It can get/set global hash configurations.
  * Get/set symmetric hash enable per flow type.
  * Get/set hash function type.
 - It can get/set symmetric hash enable per port.
 - Four commands have been implemented in testpmd to support
   testing above.
   * get_sym_hash_ena_per_port
   * set_sym_hash_ena_per_port
   * get_hash_global_config
   * set_hash_global_config

It also uses constant hash keys to replace runtime generating hash keys. Global initialization is added to correctly put registers to an initial state.

v3 changes:
* Removed renamings in rte_ethdev.h.
* Redesigned filter control API and its relevant structures/enums.
* Renamed header file from rte_eth_features.h to rte_eth_ctrol.h.
* Remove public header file of rte_i40e.h specific for i40e.
* Added hardware initialization function during port init.
* Used constant random hash keys in i40e PF.
* renamed the commands in testpmd based on the redesigned filter
  control API.

v4 changes:
* Fixed a bug in testpmd to support 'set_sym_hash_ena_per_port'.

v5 changes:
* Integrated with filter API defined recently.
* Remove all for filter API definition, as it has already defined
  and merged recently.

v6 changes:
* Flow type strings are used to replace Packet Classification
  Types, to isolate hardware specific things.
* Implemented the mapping function to convert RSS offload types to
  Packet Classification Types, to isolate the real hardware
  specific things.
* Removed initialization of global registers in i40e PMD, as global
  registers shouldn't be initialized per port.
* Added more annotations to get code more understandable.
* Corrected annotation format for documenation.

v7 changes:
* Remove swap configurations, as it is not allowed by hardware design.
* Put symmetric hash per flow type and hash function type into
  'RTE_ETH_HASH_FILTER_GLOBAL_CONFIG', as they are controlling global
  registers which will affects all the ports of the same NIC.

Helin Zhang (4):
  ethdev: code style fixes
  i40e: use constant as the default hash keys
  i40e: support of controlling hash functions
  app/testpmd: app/testpmd: add commands to support hash functions

 app/test-pmd/cmdline.c            | 334 ++++++++++++++++++++++++++++++++++++++
 lib/librte_ether/rte_eth_ctrl.h   |  72 +++++++-
 lib/librte_pmd_i40e/i40e_ethdev.c | 312 ++++++++++++++++++++++++++++++++++-
 3 files changed, 704 insertions(+), 14 deletions(-)

-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v7 1/4] ethdev: code style fixes
  2014-11-28 12:14         ` [dpdk-dev] [PATCH v7 0/4] " Helin Zhang
@ 2014-11-28 12:14           ` Helin Zhang
  2014-11-28 12:14           ` [dpdk-dev] [PATCH v7 2/4] i40e: use constant as the default hash keys Helin Zhang
                             ` (3 subsequent siblings)
  4 siblings, 0 replies; 71+ messages in thread
From: Helin Zhang @ 2014-11-28 12:14 UTC (permalink / raw)
  To: dev

Added code style fixes.

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
---
 lib/librte_ether/rte_eth_ctrl.h | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/lib/librte_ether/rte_eth_ctrl.h b/lib/librte_ether/rte_eth_ctrl.h
index 7088d8d..6ab16c2 100644
--- a/lib/librte_ether/rte_eth_ctrl.h
+++ b/lib/librte_ether/rte_eth_ctrl.h
@@ -62,8 +62,8 @@ enum rte_filter_type {
  * Generic operations on filters
  */
 enum rte_filter_op {
+	/** used to check whether the type filter is supported */
 	RTE_ETH_FILTER_NOP = 0,
-	/**< used to check whether the type filter is supported */
 	RTE_ETH_FILTER_ADD,      /**< add filter entry */
 	RTE_ETH_FILTER_UPDATE,   /**< update filter entry */
 	RTE_ETH_FILTER_DELETE,   /**< delete filter entry */
@@ -75,16 +75,15 @@ enum rte_filter_op {
 	RTE_ETH_FILTER_OP_MAX
 };
 
-/**
+/*
  * MAC filter type
  */
 enum rte_mac_filter_type {
 	RTE_MAC_PERFECT_MATCH = 1, /**< exact match of MAC addr. */
-	RTE_MACVLAN_PERFECT_MATCH,
-	/**< exact match of MAC addr and VLAN ID. */
+	RTE_MACVLAN_PERFECT_MATCH, /**< exact match of MAC addr and VLAN ID. */
 	RTE_MAC_HASH_MATCH, /**< hash match of MAC addr. */
+	/** hash match of MAC addr and exact match of VLAN ID. */
 	RTE_MACVLAN_HASH_MATCH,
-	/**< hash match of MAC addr and exact match of VLAN ID. */
 };
 
 /**
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v7 2/4] i40e: use constant as the default hash keys
  2014-11-28 12:14         ` [dpdk-dev] [PATCH v7 0/4] " Helin Zhang
  2014-11-28 12:14           ` [dpdk-dev] [PATCH v7 1/4] ethdev: code style fixes Helin Zhang
@ 2014-11-28 12:14           ` Helin Zhang
  2014-11-28 12:14           ` [dpdk-dev] [PATCH v7 3/4] i40e: support of controlling hash functions Helin Zhang
                             ` (2 subsequent siblings)
  4 siblings, 0 replies; 71+ messages in thread
From: Helin Zhang @ 2014-11-28 12:14 UTC (permalink / raw)
  To: dev

Calculating the default RSS hash keys at run time is not needed
at all, and may have race conditions. The alternative is to use
array of random values which were generated manually as the
default hash keys.

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
---
 lib/librte_pmd_i40e/i40e_ethdev.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/lib/librte_pmd_i40e/i40e_ethdev.c b/lib/librte_pmd_i40e/i40e_ethdev.c
index 87e750a..8fbe25f 100644
--- a/lib/librte_pmd_i40e/i40e_ethdev.c
+++ b/lib/librte_pmd_i40e/i40e_ethdev.c
@@ -73,7 +73,7 @@
 /* Maximun number of VSI */
 #define I40E_MAX_NUM_VSIS          (384UL)
 
-/* Default queue interrupt throttling time in microseconds*/
+/* Default queue interrupt throttling time in microseconds */
 #define I40E_ITR_INDEX_DEFAULT          0
 #define I40E_QUEUE_ITR_INTERVAL_DEFAULT 32 /* 32 us */
 #define I40E_QUEUE_ITR_INTERVAL_MAX     8160 /* 8160 us */
@@ -199,9 +199,6 @@ static int i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
 				enum rte_filter_op filter_op,
 				void *arg);
 
-/* Default hash key buffer for RSS */
-static uint32_t rss_key_default[I40E_PFQF_HKEY_MAX_INDEX + 1];
-
 static struct rte_pci_id pci_id_i40e_map[] = {
 #define RTE_PCI_DEV_ID_DECL_I40E(vend, dev) {RTE_PCI_DEVICE(vend, dev)},
 #include "rte_pci_dev_ids.h"
@@ -5023,9 +5020,12 @@ i40e_pf_config_rss(struct i40e_pf *pf)
 	}
 	if (rss_conf.rss_key == NULL || rss_conf.rss_key_len <
 		(I40E_PFQF_HKEY_MAX_INDEX + 1) * sizeof(uint32_t)) {
-		/* Calculate the default hash key */
-		for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++)
-			rss_key_default[i] = (uint32_t)rte_rand();
+		/* Random default keys */
+		static uint32_t rss_key_default[] = {0x6b793944,
+			0x23504cb5, 0x5bea75b6, 0x309f4f12, 0x3dc0a2b8,
+			0x024ddcdf, 0x339b8ca0, 0x4c4af64a, 0x34fac605,
+			0x55d85839, 0x3a58997d, 0x2ec938e1, 0x66031581};
+
 		rss_conf.rss_key = (uint8_t *)rss_key_default;
 		rss_conf.rss_key_len = (I40E_PFQF_HKEY_MAX_INDEX + 1) *
 							sizeof(uint32_t);
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v7 3/4] i40e: support of controlling hash functions
  2014-11-28 12:14         ` [dpdk-dev] [PATCH v7 0/4] " Helin Zhang
  2014-11-28 12:14           ` [dpdk-dev] [PATCH v7 1/4] ethdev: code style fixes Helin Zhang
  2014-11-28 12:14           ` [dpdk-dev] [PATCH v7 2/4] i40e: use constant as the default hash keys Helin Zhang
@ 2014-11-28 12:14           ` Helin Zhang
  2014-11-28 12:52             ` Ananyev, Konstantin
  2014-11-28 12:14           ` [dpdk-dev] [PATCH v7 4/4] app/testpmd: app/testpmd: add commands to support " Helin Zhang
  2014-12-02  2:19           ` [dpdk-dev] [PATCH v8 0/4] Support configuring " Helin Zhang
  4 siblings, 1 reply; 71+ messages in thread
From: Helin Zhang @ 2014-11-28 12:14 UTC (permalink / raw)
  To: dev

Hash filter control has been implemented for i40e. It includes
getting/setting,
- global hash configurations (hash function type, and symmetric
  hash enable per flow type)
- symmetric hash enable per port

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
---
 lib/librte_ether/rte_eth_ctrl.h   |  63 ++++++++
 lib/librte_pmd_i40e/i40e_ethdev.c | 298 +++++++++++++++++++++++++++++++++++++-
 2 files changed, 359 insertions(+), 2 deletions(-)

v5 changes:
* Integrated with filter API defined recently.

v6 changes:
* Implemented the mapping function to convert RSS offload types to
  Packet Classification Types, to isolate the real hardware
  specific things.
* Removed initialization of global registers in i40e PMD, as global
  registers shouldn't be initialized per port.
* Added more annotations to get code more understandable.
* Corrected annotation format for documenation.

v7 changes:
* Remove swap configurations, as it is not allowed by hardware design.
* Put symmetric hash per flow type and hash function type into
  'RTE_ETH_HASH_FILTER_GLOBAL_CONFIG', as they are controlling global
  registers which will affects all the ports of the same NIC.

diff --git a/lib/librte_ether/rte_eth_ctrl.h b/lib/librte_ether/rte_eth_ctrl.h
index 6ab16c2..827d7ba 100644
--- a/lib/librte_ether/rte_eth_ctrl.h
+++ b/lib/librte_ether/rte_eth_ctrl.h
@@ -55,6 +55,7 @@ enum rte_filter_type {
 	RTE_ETH_FILTER_ETHERTYPE,
 	RTE_ETH_FILTER_TUNNEL,
 	RTE_ETH_FILTER_FDIR,
+	RTE_ETH_FILTER_HASH,
 	RTE_ETH_FILTER_MAX
 };
 
@@ -449,6 +450,68 @@ struct rte_eth_fdir_stats {
 	uint32_t best_cnt;     /**< Number of filters in best effort spaces. */
 };
 
+/**
+ * Hash filter information types.
+ * - RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT is for getting/setting the
+ *   information/configuration of 'symmetric hash enable' per port.
+ * - RTE_ETH_HASH_FILTER_GLOBAL_CONFIG is for getting/setting the global
+ *   configurations of hash filters. Those global configurations are valid
+ *   for all ports of the same NIC.
+ */
+enum rte_eth_hash_filter_info_type {
+	RTE_ETH_HASH_FILTER_INFO_TYPE_UNKNOWN = 0,
+	/** Symmetric hash enable per port */
+	RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT,
+	/** Configure globally for hash filter */
+	RTE_ETH_HASH_FILTER_GLOBAL_CONFIG,
+	RTE_ETH_HASH_FILTER_INFO_TYPE_MAX,
+};
+
+/**
+ * Hash function types.
+ */
+enum rte_eth_hash_function {
+	RTE_ETH_HASH_FUNCTION_DEFAULT = 0,
+	RTE_ETH_HASH_FUNCTION_TOEPLITZ, /**< Toeplitz */
+	RTE_ETH_HASH_FUNCTION_SIMPLE_XOR, /**< Simple XOR */
+	RTE_ETH_HASH_FUNCTION_MAX,
+};
+
+#define UINT32_BIT (CHAR_BIT * sizeof(uint32_t))
+#define RTE_SYM_HASH_MASK_ARRAY_SIZE \
+	(RTE_ALIGN(RTE_ETH_FLOW_TYPE_MAX, UINT32_BIT)/UINT32_BIT)
+/**
+ * A structure used to set or get global hash function configurations which
+ * include symmetric hash enable per flow type and hash function type.
+ * Each bit in sym_hash_enable_mask[] indicates if the symmetric hash of the
+ * coresponding flow type is enabled or not.
+ * Each bit in valid_bit_mask[] indicates if the coresponding bit in
+ * sym_hash_enable_mask[] is valid or not. For the configurations gotten, it
+ * also means if the flow type is supported by hardware or not.
+ */
+struct rte_eth_hash_global_conf {
+	enum rte_eth_hash_function hash_func; /**< Hash function type */
+	/** Bit mask for symmetric hash enable per flow type */
+	uint32_t sym_hash_enable_mask[RTE_SYM_HASH_MASK_ARRAY_SIZE];
+	/** Bit mask indicates if the coresponding bit is valid */
+	uint32_t valid_bit_mask[RTE_SYM_HASH_MASK_ARRAY_SIZE];
+};
+
+/**
+ * A structure used to set or get hash filter information, to support filter
+ * type of 'RTE_ETH_FILTER_HASH' and its operations.
+ */
+struct rte_eth_hash_filter_info {
+	enum rte_eth_hash_filter_info_type info_type; /**< Information type. */
+	/** Details of hash filter infomation */
+	union {
+		/* For RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT */
+		uint8_t enable;
+		/* Global configurations of hash filter */
+		struct rte_eth_hash_global_conf global_conf;
+	} info;
+};
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_pmd_i40e/i40e_ethdev.c b/lib/librte_pmd_i40e/i40e_ethdev.c
index 8fbe25f..ef8edd4 100644
--- a/lib/librte_pmd_i40e/i40e_ethdev.c
+++ b/lib/librte_pmd_i40e/i40e_ethdev.c
@@ -93,6 +93,18 @@
 		I40E_PFINT_ICR0_ENA_VFLR_MASK | \
 		I40E_PFINT_ICR0_ENA_ADMINQ_MASK)
 
+#define I40E_FLOW_TYPES ( \
+	(1UL << RTE_ETH_FLOW_TYPE_UDPV4) | \
+	(1UL << RTE_ETH_FLOW_TYPE_TCPV4) | \
+	(1UL << RTE_ETH_FLOW_TYPE_SCTPV4) | \
+	(1UL << RTE_ETH_FLOW_TYPE_IPV4_OTHER) | \
+	(1UL << RTE_ETH_FLOW_TYPE_FRAG_IPV4) | \
+	(1UL << RTE_ETH_FLOW_TYPE_UDPV6) | \
+	(1UL << RTE_ETH_FLOW_TYPE_TCPV6) | \
+	(1UL << RTE_ETH_FLOW_TYPE_SCTPV6) | \
+	(1UL << RTE_ETH_FLOW_TYPE_IPV6_OTHER) | \
+	(1UL << RTE_ETH_FLOW_TYPE_FRAG_IPV6))
+
 static int eth_i40e_dev_init(\
 			__attribute__((unused)) struct eth_driver *eth_drv,
 			struct rte_eth_dev *eth_dev);
@@ -198,6 +210,7 @@ static int i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
 				enum rte_filter_type filter_type,
 				enum rte_filter_op filter_op,
 				void *arg);
+static void i40e_hw_init(struct i40e_hw *hw);
 
 static struct rte_pci_id pci_id_i40e_map[] = {
 #define RTE_PCI_DEV_ID_DECL_I40E(vend, dev) {RTE_PCI_DEVICE(vend, dev)},
@@ -397,6 +410,9 @@ eth_i40e_dev_init(__rte_unused struct eth_driver *eth_drv,
 	/* Make sure all is clean before doing PF reset */
 	i40e_clear_hw(hw);
 
+	/* Initialize the hardware */
+	i40e_hw_init(hw);
+
 	/* Reset here to make sure all is clean for each PF */
 	ret = i40e_pf_reset(hw);
 	if (ret) {
@@ -5120,6 +5136,264 @@ i40e_pf_config_mq_rx(struct i40e_pf *pf)
 	return ret;
 }
 
+/* Get the symmetric hash enable configurations per port */
+static void
+i40e_get_symmetric_hash_enable_per_port(struct i40e_hw *hw, uint8_t *enable)
+{
+	uint32_t reg = I40E_READ_REG(hw, I40E_PRTQF_CTL_0);
+
+	*enable = reg & I40E_PRTQF_CTL_0_HSYM_ENA_MASK ? 1 : 0;
+}
+
+/* Set the symmetric hash enable configurations per port */
+static void
+i40e_set_symmetric_hash_enable_per_port(struct i40e_hw *hw, uint8_t enable)
+{
+	uint32_t reg = I40E_READ_REG(hw, I40E_PRTQF_CTL_0);
+
+	if (enable > 0) {
+		if (reg & I40E_PRTQF_CTL_0_HSYM_ENA_MASK) {
+			PMD_DRV_LOG(INFO, "Symmetric hash has already "
+							"been enabled");
+			return;
+		}
+		reg |= I40E_PRTQF_CTL_0_HSYM_ENA_MASK;
+	} else {
+		if (!(reg & I40E_PRTQF_CTL_0_HSYM_ENA_MASK)) {
+			PMD_DRV_LOG(INFO, "Symmetric hash has already "
+							"been disabled");
+			return;
+		}
+		reg &= ~I40E_PRTQF_CTL_0_HSYM_ENA_MASK;
+	}
+	I40E_WRITE_REG(hw, I40E_PRTQF_CTL_0, reg);
+	I40E_WRITE_FLUSH(hw);
+}
+
+/*
+ * Get global configurations of hash function type and symmetric hash enable
+ * per flow type (pctype). Note that global configuration means it affects all
+ * the ports on the same NIC.
+ */
+static int
+i40e_get_hash_filter_global_config(struct i40e_hw *hw,
+				   struct rte_eth_hash_global_conf *g_cfg)
+{
+	uint32_t reg, mask = I40E_FLOW_TYPES;
+	enum rte_eth_flow_type i;
+	enum i40e_filter_pctype pctype;
+
+	memset(g_cfg, 0, sizeof(*g_cfg));
+	reg = I40E_READ_REG(hw, I40E_GLQF_CTL);
+	if (reg & I40E_GLQF_CTL_HTOEP_MASK)
+		g_cfg->hash_func = RTE_ETH_HASH_FUNCTION_TOEPLITZ;
+	else
+		g_cfg->hash_func = RTE_ETH_HASH_FUNCTION_SIMPLE_XOR;
+	PMD_DRV_LOG(DEBUG, "Hash function is %s",
+		(reg & I40E_GLQF_CTL_HTOEP_MASK) ? "Toeplitz" : "Simple XOR");
+
+	for (i = 0; mask && i < RTE_ETH_FLOW_TYPE_MAX; i++) {
+		if (!(mask & (1UL << i)))
+			continue;
+		mask &= ~(1UL << i);
+		/* Bit set indicats the coresponding flow type is supported */
+		g_cfg->valid_bit_mask[0] |= (1UL << i);
+		pctype = i40e_flowtype_to_pctype(i);
+		if (!pctype)
+			continue;
+		reg = I40E_READ_REG(hw, I40E_GLQF_HSYM(pctype));
+		if (reg & I40E_GLQF_HSYM_SYMH_ENA_MASK)
+			g_cfg->sym_hash_enable_mask[0] |= (1UL << i);
+	}
+
+	return 0;
+}
+
+static int
+i40e_hash_global_config_check(struct rte_eth_hash_global_conf *g_cfg)
+{
+	uint32_t i;
+	uint32_t mask0, i40e_mask = I40E_FLOW_TYPES;
+
+	if (g_cfg->hash_func != RTE_ETH_HASH_FUNCTION_TOEPLITZ &&
+		g_cfg->hash_func != RTE_ETH_HASH_FUNCTION_SIMPLE_XOR &&
+		g_cfg->hash_func != RTE_ETH_HASH_FUNCTION_DEFAULT) {
+		PMD_DRV_LOG(ERR, "Unsupported hash function type %d",
+						g_cfg->hash_func);
+		return -EINVAL;
+	}
+
+	/*
+	 * As i40e supports less than 32 flow types, only first 32 bits need to
+	 * be checked.
+	 */
+	mask0 = g_cfg->valid_bit_mask[0];
+	for (i = 0; i < RTE_SYM_HASH_MASK_ARRAY_SIZE; i++) {
+		if (i == 0) {
+			/* Check if any unsupported flow type configured */
+			if ((mask0 | i40e_mask) ^ i40e_mask)
+				goto mask_err;
+		} else {
+			if (g_cfg->valid_bit_mask[i])
+				goto mask_err;
+		}
+	}
+
+	return 0;
+
+mask_err:
+	PMD_DRV_LOG(ERR, "i40e unsupported flow type bit(s) configured");
+
+	return -EINVAL;
+}
+
+/*
+ * Set global configurations of hash function type and symmetric hash enable
+ * per flow type (pctype). Note any modifying global configuration will affect
+ * all the ports on the same NIC.
+ */
+static int
+i40e_set_hash_filter_global_config(struct i40e_hw *hw,
+				   struct rte_eth_hash_global_conf *g_cfg)
+{
+	int ret;
+	uint32_t i, reg;
+	uint32_t mask0 = g_cfg->valid_bit_mask[0];
+	enum i40e_filter_pctype pctype;
+
+	/* Check the input parameters */
+	ret = i40e_hash_global_config_check(g_cfg);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; mask0 && i < UINT32_BIT; i++) {
+		if (!(mask0 & (1UL << i)))
+			continue;
+		mask0 &= ~(1UL << i);
+		pctype = i40e_flowtype_to_pctype(i);
+		if (!pctype)
+			continue;
+		reg = (g_cfg->sym_hash_enable_mask[0] & (1UL << i)) ?
+				I40E_GLQF_HSYM_SYMH_ENA_MASK : 0;
+		I40E_WRITE_REG(hw, I40E_GLQF_HSYM(pctype), reg);
+	}
+
+	reg = I40E_READ_REG(hw, I40E_GLQF_CTL);
+	if (g_cfg->hash_func == RTE_ETH_HASH_FUNCTION_TOEPLITZ) {
+		/* Toeplitz */
+		if (reg & I40E_GLQF_CTL_HTOEP_MASK) {
+			PMD_DRV_LOG(DEBUG, "Hash function already set to "
+								"Toeplitz");
+			goto out;
+		}
+		reg |= I40E_GLQF_CTL_HTOEP_MASK;
+	} else if (g_cfg->hash_func == RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) {
+		/* Simple XOR */
+		if (!(reg & I40E_GLQF_CTL_HTOEP_MASK)) {
+			PMD_DRV_LOG(DEBUG, "Hash function already set to "
+							"Simple XOR");
+			goto out;
+		}
+		reg &= ~I40E_GLQF_CTL_HTOEP_MASK;
+	} else
+		/* Use the default, and keep it as it is */
+		goto out;
+
+	I40E_WRITE_REG(hw, I40E_GLQF_CTL, reg);
+
+out:
+	I40E_WRITE_FLUSH(hw);
+
+	return 0;
+}
+
+static int
+i40e_hash_filter_get(struct i40e_hw *hw, struct rte_eth_hash_filter_info *info)
+{
+	int ret = 0;
+
+	if (!hw || !info) {
+		PMD_DRV_LOG(ERR, "Invalid pointer");
+		return -EFAULT;
+	}
+
+	switch (info->info_type) {
+	case RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT:
+		i40e_get_symmetric_hash_enable_per_port(hw,
+					&(info->info.enable));
+		break;
+	case RTE_ETH_HASH_FILTER_GLOBAL_CONFIG:
+		ret = i40e_get_hash_filter_global_config(hw,
+				&(info->info.global_conf));
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "Hash filter info type (%d) not supported",
+							info->info_type);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int
+i40e_hash_filter_set(struct i40e_hw *hw, struct rte_eth_hash_filter_info *info)
+{
+	int ret = 0;
+
+	if (!hw || !info) {
+		PMD_DRV_LOG(ERR, "Invalid pointer");
+		return -EFAULT;
+	}
+
+	switch (info->info_type) {
+	case RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT:
+		i40e_set_symmetric_hash_enable_per_port(hw, info->info.enable);
+		break;
+	case RTE_ETH_HASH_FILTER_GLOBAL_CONFIG:
+		ret = i40e_set_hash_filter_global_config(hw,
+				&(info->info.global_conf));
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "Hash filter info type (%d) not supported",
+							info->info_type);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+/* Operations for hash function */
+static int
+i40e_hash_filter_ctrl(struct rte_eth_dev *dev,
+		      enum rte_filter_op filter_op,
+		      void *arg)
+{
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	int ret = 0;
+
+	switch (filter_op) {
+	case RTE_ETH_FILTER_NOP:
+		break;
+	case RTE_ETH_FILTER_GET:
+		ret = i40e_hash_filter_get(hw,
+			(struct rte_eth_hash_filter_info *)arg);
+		break;
+	case RTE_ETH_FILTER_SET:
+		ret = i40e_hash_filter_set(hw,
+			(struct rte_eth_hash_filter_info *)arg);
+		break;
+	default:
+		PMD_DRV_LOG(WARNING, "Filter operation (%d) not supported",
+								filter_op);
+		ret = -ENOTSUP;
+		break;
+	}
+
+	return ret;
+}
+
 /*
  * Configure ethertype filter, which can director packet by filtering
  * with mac address and ether_type or only ether_type
@@ -5222,6 +5496,9 @@ i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
 		return -EINVAL;
 
 	switch (filter_type) {
+	case RTE_ETH_FILTER_HASH:
+		ret = i40e_hash_filter_ctrl(dev, filter_op, arg);
+		break;
 	case RTE_ETH_FILTER_MACVLAN:
 		ret = i40e_mac_filter_handle(dev, filter_op, arg);
 		break;
@@ -5244,10 +5521,26 @@ i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
 	return ret;
 }
 
+/*
+ * As some registers wouldn't be reset unless a global hardware reset,
+ * hardware initialization is needed to put those registers into an
+ * expected initial state.
+ */
+static void
+i40e_hw_init(struct i40e_hw *hw)
+{
+	/* clear the PF Queue Filter control register */
+	I40E_WRITE_REG(hw, I40E_PFQF_CTL_0, 0);
+
+	/* Disable symmetric hash per port */
+	i40e_set_symmetric_hash_enable_per_port(hw, 0);
+}
+
 enum i40e_filter_pctype
 i40e_flowtype_to_pctype(enum rte_eth_flow_type flow_type)
 {
-	static const enum i40e_filter_pctype pctype_table[] = {
+	static const enum i40e_filter_pctype
+		pctype_table[RTE_ETH_FLOW_TYPE_MAX] = {
 		[RTE_ETH_FLOW_TYPE_UDPV4] = I40E_FILTER_PCTYPE_NONF_IPV4_UDP,
 		[RTE_ETH_FLOW_TYPE_TCPV4] = I40E_FILTER_PCTYPE_NONF_IPV4_TCP,
 		[RTE_ETH_FLOW_TYPE_SCTPV4] = I40E_FILTER_PCTYPE_NONF_IPV4_SCTP,
@@ -5270,7 +5563,8 @@ i40e_flowtype_to_pctype(enum rte_eth_flow_type flow_type)
 enum rte_eth_flow_type
 i40e_pctype_to_flowtype(enum i40e_filter_pctype pctype)
 {
-	static const enum rte_eth_flow_type flowtype_table[] = {
+	static const enum rte_eth_flow_type
+		flowtype_table[RTE_ETH_FLOW_TYPE_MAX] = {
 		[I40E_FILTER_PCTYPE_NONF_IPV4_UDP] = RTE_ETH_FLOW_TYPE_UDPV4,
 		[I40E_FILTER_PCTYPE_NONF_IPV4_TCP] = RTE_ETH_FLOW_TYPE_TCPV4,
 		[I40E_FILTER_PCTYPE_NONF_IPV4_SCTP] = RTE_ETH_FLOW_TYPE_SCTPV4,
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v7 4/4] app/testpmd: app/testpmd: add commands to support hash functions
  2014-11-28 12:14         ` [dpdk-dev] [PATCH v7 0/4] " Helin Zhang
                             ` (2 preceding siblings ...)
  2014-11-28 12:14           ` [dpdk-dev] [PATCH v7 3/4] i40e: support of controlling hash functions Helin Zhang
@ 2014-11-28 12:14           ` Helin Zhang
  2014-12-02  2:19           ` [dpdk-dev] [PATCH v8 0/4] Support configuring " Helin Zhang
  4 siblings, 0 replies; 71+ messages in thread
From: Helin Zhang @ 2014-11-28 12:14 UTC (permalink / raw)
  To: dev

To demonstrate the hash filter control, commands are added.
They are,
- get_sym_hash_ena_per_port
- set_sym_hash_ena_per_port
- get_hash_global_config
- set_hash_global_config

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
---
 app/test-pmd/cmdline.c | 334 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 334 insertions(+)

v6 changes:
* Flow type strings are used to replace Packet Classification
  Types, to isolate hardware specific things.

v7 changes:
* Removed commands of,
  get_sym_hash_ena_per_pctype
  set_sym_hash_ena_per_pctype
  get_filter_swap
  set_filter_swap
  get_hash_function
  set_hash_function.
* Added new commands of,
  get_hash_global_config
  set_hash_global_config

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index c61c3a0..9027f47 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -75,6 +75,7 @@
 #include <rte_ethdev.h>
 #include <rte_string_fns.h>
 #include <rte_devargs.h>
+#include <rte_eth_ctrl.h>
 
 #include <cmdline_rdline.h>
 #include <cmdline_parse.h>
@@ -740,6 +741,21 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"flow_director_flex_payload (port_id)"
 			" (l2|l3|l4) (config)\n"
 			"    Configure flex payload selection.\n\n"
+
+			"get_sym_hash_ena_per_port (port_id)\n"
+			"    get symmetric hash enable configuration per port.\n\n"
+
+			"set_sym_hash_ena_per_port (port_id) (enable|disable)\n"
+			"    set symmetric hash enable configuration per port"
+			" to enable or disable.\n\n"
+
+			"get_hash_global_config (port_id)\n"
+			"    Get the global configurations of hash filters.\n\n"
+
+			"set_hash_global_config (port_id) (toeplitz|simple_xor|default)"
+			" (ip4|ip4-frag|tcp4|udp4|#sctp4|ip6|ip6-frag|tcp6|udp6|sctp6)"
+			" (enable|disable)\n"
+			"    Set the global configurations of hash filters.\n\n"
 		);
 	}
 }
@@ -8697,6 +8713,320 @@ cmdline_parse_inst_t cmd_set_flow_director_flex_payload = {
 	},
 };
 
+/* *** Classification Filters Control *** */
+/* *** Get symmetric hash enable per port *** */
+struct cmd_get_sym_hash_ena_per_port_result {
+	cmdline_fixed_string_t get_sym_hash_ena_per_port;
+	uint8_t port_id;
+};
+
+static void
+cmd_get_sym_hash_per_port_parsed(void *parsed_result,
+				 __rte_unused struct cmdline *cl,
+				 __rte_unused void *data)
+{
+	struct cmd_get_sym_hash_ena_per_port_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port: %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT;
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+						RTE_ETH_FILTER_GET, &info);
+
+	if (ret < 0) {
+		printf("Cannot get symmetric hash enable per port "
+					"on port %u\n", res->port_id);
+		return;
+	}
+
+	printf("Symmetric hash is %s on port %u\n", info.info.enable ?
+				"enabled" : "disabled", res->port_id);
+}
+
+cmdline_parse_token_string_t cmd_get_sym_hash_ena_per_port_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_get_sym_hash_ena_per_port_result,
+		get_sym_hash_ena_per_port, "get_sym_hash_ena_per_port");
+cmdline_parse_token_num_t cmd_get_sym_hash_ena_per_port_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_get_sym_hash_ena_per_port_result,
+		port_id, UINT8);
+
+cmdline_parse_inst_t cmd_get_sym_hash_ena_per_port = {
+	.f = cmd_get_sym_hash_per_port_parsed,
+	.data = NULL,
+	.help_str = "get_sym_hash_ena_per_port port_id",
+	.tokens = {
+		(void *)&cmd_get_sym_hash_ena_per_port_all,
+		(void *)&cmd_get_sym_hash_ena_per_port_port_id,
+		NULL,
+	},
+};
+
+/* *** Set symmetric hash enable per port *** */
+struct cmd_set_sym_hash_ena_per_port_result {
+	cmdline_fixed_string_t set_sym_hash_ena_per_port;
+	cmdline_fixed_string_t enable;
+	uint8_t port_id;
+};
+
+static void
+cmd_set_sym_hash_per_port_parsed(void *parsed_result,
+				 __rte_unused struct cmdline *cl,
+				 __rte_unused void *data)
+{
+	struct cmd_set_sym_hash_ena_per_port_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port: %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT;
+	if (!strcmp(res->enable, "enable"))
+		info.info.enable = 1;
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+					RTE_ETH_FILTER_SET, &info);
+	if (ret < 0) {
+		printf("Cannot set symmetric hash enable per port on "
+					"port %u\n", res->port_id);
+		return;
+	}
+	printf("Symmetric hash has been set to %s on port %u\n",
+					res->enable, res->port_id);
+}
+
+cmdline_parse_token_string_t cmd_set_sym_hash_ena_per_port_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_sym_hash_ena_per_port_result,
+		set_sym_hash_ena_per_port, "set_sym_hash_ena_per_port");
+cmdline_parse_token_num_t cmd_set_sym_hash_ena_per_port_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_sym_hash_ena_per_port_result,
+		port_id, UINT8);
+cmdline_parse_token_string_t cmd_set_sym_hash_ena_per_port_enable =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_sym_hash_ena_per_port_result,
+		enable, "enable#disable");
+
+cmdline_parse_inst_t cmd_set_sym_hash_ena_per_port = {
+	.f = cmd_set_sym_hash_per_port_parsed,
+	.data = NULL,
+	.help_str = "set_sym_hash_ena_per_port port_id enable|disable",
+	.tokens = {
+		(void *)&cmd_set_sym_hash_ena_per_port_all,
+		(void *)&cmd_set_sym_hash_ena_per_port_port_id,
+		(void *)&cmd_set_sym_hash_ena_per_port_enable,
+		NULL,
+	},
+};
+
+/* Get global config of hash function */
+struct cmd_get_hash_global_config_result {
+	cmdline_fixed_string_t get_hash_global_config;
+	uint8_t port_id;
+};
+
+static char *
+flowtype_to_str(enum rte_eth_flow_type ftype)
+{
+	uint16_t i;
+	static struct {
+		char str[16];
+		enum rte_eth_flow_type ftype;
+	} ftype_table[] = {
+		{"ip4", RTE_ETH_FLOW_TYPE_IPV4_OTHER},
+		{"ip4-frag", RTE_ETH_FLOW_TYPE_FRAG_IPV4},
+		{"udp4", RTE_ETH_FLOW_TYPE_UDPV4},
+		{"tcp4", RTE_ETH_FLOW_TYPE_TCPV4},
+		{"sctp4", RTE_ETH_FLOW_TYPE_SCTPV4},
+		{"ip6", RTE_ETH_FLOW_TYPE_IPV6_OTHER},
+		{"ip6-frag", RTE_ETH_FLOW_TYPE_FRAG_IPV6},
+		{"udp6", RTE_ETH_FLOW_TYPE_UDPV6},
+		{"tcp6", RTE_ETH_FLOW_TYPE_TCPV6},
+		{"sctp6", RTE_ETH_FLOW_TYPE_TCPV6},
+	};
+
+	for (i = 0; i < RTE_DIM(ftype_table); i++) {
+		if (ftype_table[i].ftype == ftype)
+			return ftype_table[i].str;
+	}
+
+	return NULL;
+}
+
+static void
+cmd_get_hash_global_config_parsed(void *parsed_result,
+				  __rte_unused struct cmdline *cl,
+				  __rte_unused void *data)
+{
+	struct cmd_get_hash_global_config_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	enum rte_eth_flow_type i;
+	uint32_t idx, offset;
+	char *str;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+			RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_GLOBAL_CONFIG;
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+					RTE_ETH_FILTER_GET, &info);
+	if (ret < 0) {
+		printf("Cannot get hash global configurations by port %d\n",
+							res->port_id);
+		return;
+	}
+
+	switch (info.info.global_conf.hash_func) {
+	case RTE_ETH_HASH_FUNCTION_TOEPLITZ:
+		printf("Hash function is Toeplitz\n");
+		break;
+	case RTE_ETH_HASH_FUNCTION_SIMPLE_XOR:
+		printf("Hash function is Simple XOR\n");
+		break;
+	default:
+		printf("Unknown hash function\n");
+		break;
+	}
+
+	for (i = 0; i < RTE_ETH_FLOW_TYPE_MAX; i++) {
+		idx = i / UINT32_BIT;
+		offset = i % UINT32_BIT;
+		if (!(info.info.global_conf.valid_bit_mask[idx] &
+						(1UL << offset)))
+			continue;
+		str = flowtype_to_str(i);
+		if (!str)
+			continue;
+		printf("Symmetric hash is %s globally for flow type %s "
+							"by port %d\n",
+			((info.info.global_conf.sym_hash_enable_mask[idx] &
+			(1UL << offset)) ? "enabled" : "disabled"), str,
+							res->port_id);
+	}
+}
+
+cmdline_parse_token_string_t cmd_get_hash_global_config_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_get_hash_global_config_result,
+		get_hash_global_config, "get_hash_global_config");
+cmdline_parse_token_num_t cmd_get_hash_global_config_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_get_hash_global_config_result,
+		port_id, UINT8);
+
+cmdline_parse_inst_t cmd_get_hash_global_config = {
+	.f = cmd_get_hash_global_config_parsed,
+	.data = NULL,
+	.help_str = "get_hash_global_config port_id",
+	.tokens = {
+		(void *)&cmd_get_hash_global_config_all,
+		(void *)&cmd_get_hash_global_config_port_id,
+		NULL,
+	},
+};
+
+/* Set global config of hash function */
+struct cmd_set_hash_global_config_result {
+	cmdline_fixed_string_t set_hash_global_config;
+	uint8_t port_id;
+	cmdline_fixed_string_t hash_func;
+	cmdline_fixed_string_t flow_type;
+	cmdline_fixed_string_t enable;
+};
+
+static void
+cmd_set_hash_global_config_parsed(void *parsed_result,
+				  __rte_unused struct cmdline *cl,
+				  __rte_unused void *data)
+{
+	struct cmd_set_hash_global_config_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	uint32_t ftype, idx, offset;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port %d\n",
+							res->port_id);
+		return;
+	}
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_GLOBAL_CONFIG;
+	if (!strcmp(res->hash_func, "toeplitz"))
+		info.info.global_conf.hash_func =
+			RTE_ETH_HASH_FUNCTION_TOEPLITZ;
+	else if (!strcmp(res->hash_func, "simple_xor"))
+		info.info.global_conf.hash_func =
+			RTE_ETH_HASH_FUNCTION_SIMPLE_XOR;
+	else if (!strcmp(res->hash_func, "default"))
+		info.info.global_conf.hash_func =
+			RTE_ETH_HASH_FUNCTION_DEFAULT;
+
+	ftype = str2flowtype(res->flow_type);
+	idx = ftype / (CHAR_BIT * sizeof(uint32_t));
+	offset = ftype % (CHAR_BIT * sizeof(uint32_t));
+	info.info.global_conf.valid_bit_mask[idx] |= (1UL << offset);
+	if (!strcmp(res->enable, "enable"))
+		info.info.global_conf.sym_hash_enable_mask[idx] |=
+						(1UL << offset);
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+					RTE_ETH_FILTER_SET, &info);
+	if (ret < 0)
+		printf("Cannot set global hash configurations by port %d\n",
+							res->port_id);
+	else
+		printf("Global hash configurations have been set "
+			"succcessfully by port %d\n", res->port_id);
+}
+
+cmdline_parse_token_string_t cmd_set_hash_global_config_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_hash_global_config_result,
+		set_hash_global_config, "set_hash_global_config");
+cmdline_parse_token_num_t cmd_set_hash_global_config_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_hash_global_config_result,
+		port_id, UINT8);
+cmdline_parse_token_string_t cmd_set_hash_global_config_hash_func =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_hash_global_config_result,
+		hash_func, "toeplitz#simple_xor#default");
+cmdline_parse_token_string_t cmd_set_hash_global_config_flow_type =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_hash_global_config_result,
+		flow_type,
+		"ip4#ip4-frag#tcp4#udp4#sctp4#ip6#ip6-frag#tcp6#udp6#sctp6");
+cmdline_parse_token_string_t cmd_set_hash_global_config_enable =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_hash_global_config_result,
+		enable, "enable#disable");
+
+cmdline_parse_inst_t cmd_set_hash_global_config = {
+	.f = cmd_set_hash_global_config_parsed,
+	.data = NULL,
+	.help_str = "set_hash_global_config port_id "
+		"toeplitz|simple_xor|default "
+		"ip4|ip4-frag|tcp4|udp4|#sctp4|ip6|ip6-frag|tcp6|udp6|sctp6 "
+		"enable|disable",
+	.tokens = {
+		(void *)&cmd_set_hash_global_config_all,
+		(void *)&cmd_set_hash_global_config_port_id,
+		(void *)&cmd_set_hash_global_config_hash_func,
+		(void *)&cmd_set_hash_global_config_flow_type,
+		(void *)&cmd_set_hash_global_config_enable,
+		NULL,
+	},
+};
+
 /* ******************************************************************************** */
 
 /* list of instructions */
@@ -8836,6 +9166,10 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_flush_flow_director,
 	(cmdline_parse_inst_t *)&cmd_set_flow_director_flex_mask,
 	(cmdline_parse_inst_t *)&cmd_set_flow_director_flex_payload,
+	(cmdline_parse_inst_t *)&cmd_get_sym_hash_ena_per_port,
+	(cmdline_parse_inst_t *)&cmd_set_sym_hash_ena_per_port,
+	(cmdline_parse_inst_t *)&cmd_get_hash_global_config,
+	(cmdline_parse_inst_t *)&cmd_set_hash_global_config,
 	NULL,
 };
 
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [dpdk-dev] [PATCH v7 3/4] i40e: support of controlling hash functions
  2014-11-28 12:14           ` [dpdk-dev] [PATCH v7 3/4] i40e: support of controlling hash functions Helin Zhang
@ 2014-11-28 12:52             ` Ananyev, Konstantin
  0 siblings, 0 replies; 71+ messages in thread
From: Ananyev, Konstantin @ 2014-11-28 12:52 UTC (permalink / raw)
  To: Zhang, Helin, dev

Hi Helin,
Few nits from me.
Konstantin


> -----Original Message-----
> From: Zhang, Helin
> Sent: Friday, November 28, 2014 12:14 PM
> To: dev@dpdk.org
> Cc: Cao, Waterman; Cao, Min; Ananyev, Konstantin; Zhang, Helin
> Subject: [PATCH v7 3/4] i40e: support of controlling hash functions
> 
> Hash filter control has been implemented for i40e. It includes
> getting/setting,
> - global hash configurations (hash function type, and symmetric
>   hash enable per flow type)
> - symmetric hash enable per port
> 
> Signed-off-by: Helin Zhang <helin.zhang@intel.com>
> ---
>  lib/librte_ether/rte_eth_ctrl.h   |  63 ++++++++
>  lib/librte_pmd_i40e/i40e_ethdev.c | 298 +++++++++++++++++++++++++++++++++++++-
>  2 files changed, 359 insertions(+), 2 deletions(-)
> 
> v5 changes:
> * Integrated with filter API defined recently.
> 
> v6 changes:
> * Implemented the mapping function to convert RSS offload types to
>   Packet Classification Types, to isolate the real hardware
>   specific things.
> * Removed initialization of global registers in i40e PMD, as global
>   registers shouldn't be initialized per port.
> * Added more annotations to get code more understandable.
> * Corrected annotation format for documenation.
> 
> v7 changes:
> * Remove swap configurations, as it is not allowed by hardware design.
> * Put symmetric hash per flow type and hash function type into
>   'RTE_ETH_HASH_FILTER_GLOBAL_CONFIG', as they are controlling global
>   registers which will affects all the ports of the same NIC.
> 
> diff --git a/lib/librte_ether/rte_eth_ctrl.h b/lib/librte_ether/rte_eth_ctrl.h
> index 6ab16c2..827d7ba 100644
> --- a/lib/librte_ether/rte_eth_ctrl.h
> +++ b/lib/librte_ether/rte_eth_ctrl.h
> @@ -55,6 +55,7 @@ enum rte_filter_type {
>  	RTE_ETH_FILTER_ETHERTYPE,
>  	RTE_ETH_FILTER_TUNNEL,
>  	RTE_ETH_FILTER_FDIR,
> +	RTE_ETH_FILTER_HASH,
>  	RTE_ETH_FILTER_MAX
>  };
> 
> @@ -449,6 +450,68 @@ struct rte_eth_fdir_stats {
>  	uint32_t best_cnt;     /**< Number of filters in best effort spaces. */
>  };
> 
> +/**
> + * Hash filter information types.
> + * - RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT is for getting/setting the
> + *   information/configuration of 'symmetric hash enable' per port.
> + * - RTE_ETH_HASH_FILTER_GLOBAL_CONFIG is for getting/setting the global
> + *   configurations of hash filters. Those global configurations are valid
> + *   for all ports of the same NIC.
> + */
> +enum rte_eth_hash_filter_info_type {
> +	RTE_ETH_HASH_FILTER_INFO_TYPE_UNKNOWN = 0,
> +	/** Symmetric hash enable per port */
> +	RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT,
> +	/** Configure globally for hash filter */
> +	RTE_ETH_HASH_FILTER_GLOBAL_CONFIG,
> +	RTE_ETH_HASH_FILTER_INFO_TYPE_MAX,
> +};
> +
> +/**
> + * Hash function types.
> + */
> +enum rte_eth_hash_function {
> +	RTE_ETH_HASH_FUNCTION_DEFAULT = 0,
> +	RTE_ETH_HASH_FUNCTION_TOEPLITZ, /**< Toeplitz */
> +	RTE_ETH_HASH_FUNCTION_SIMPLE_XOR, /**< Simple XOR */
> +	RTE_ETH_HASH_FUNCTION_MAX,
> +};
> +
> +#define UINT32_BIT (CHAR_BIT * sizeof(uint32_t))
> +#define RTE_SYM_HASH_MASK_ARRAY_SIZE \
> +	(RTE_ALIGN(RTE_ETH_FLOW_TYPE_MAX, UINT32_BIT)/UINT32_BIT)
> +/**
> + * A structure used to set or get global hash function configurations which
> + * include symmetric hash enable per flow type and hash function type.
> + * Each bit in sym_hash_enable_mask[] indicates if the symmetric hash of the
> + * coresponding flow type is enabled or not.
> + * Each bit in valid_bit_mask[] indicates if the coresponding bit in
> + * sym_hash_enable_mask[] is valid or not. For the configurations gotten, it
> + * also means if the flow type is supported by hardware or not.
> + */
> +struct rte_eth_hash_global_conf {
> +	enum rte_eth_hash_function hash_func; /**< Hash function type */
> +	/** Bit mask for symmetric hash enable per flow type */
> +	uint32_t sym_hash_enable_mask[RTE_SYM_HASH_MASK_ARRAY_SIZE];
> +	/** Bit mask indicates if the coresponding bit is valid */
> +	uint32_t valid_bit_mask[RTE_SYM_HASH_MASK_ARRAY_SIZE];
> +};
> +
> +/**
> + * A structure used to set or get hash filter information, to support filter
> + * type of 'RTE_ETH_FILTER_HASH' and its operations.
> + */
> +struct rte_eth_hash_filter_info {
> +	enum rte_eth_hash_filter_info_type info_type; /**< Information type. */
> +	/** Details of hash filter infomation */
> +	union {
> +		/* For RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT */
> +		uint8_t enable;
> +		/* Global configurations of hash filter */
> +		struct rte_eth_hash_global_conf global_conf;
> +	} info;
> +};
> +
>  #ifdef __cplusplus
>  }
>  #endif
> diff --git a/lib/librte_pmd_i40e/i40e_ethdev.c b/lib/librte_pmd_i40e/i40e_ethdev.c
> index 8fbe25f..ef8edd4 100644
> --- a/lib/librte_pmd_i40e/i40e_ethdev.c
> +++ b/lib/librte_pmd_i40e/i40e_ethdev.c
> @@ -93,6 +93,18 @@
>  		I40E_PFINT_ICR0_ENA_VFLR_MASK | \
>  		I40E_PFINT_ICR0_ENA_ADMINQ_MASK)
> 
> +#define I40E_FLOW_TYPES ( \
> +	(1UL << RTE_ETH_FLOW_TYPE_UDPV4) | \
> +	(1UL << RTE_ETH_FLOW_TYPE_TCPV4) | \
> +	(1UL << RTE_ETH_FLOW_TYPE_SCTPV4) | \
> +	(1UL << RTE_ETH_FLOW_TYPE_IPV4_OTHER) | \
> +	(1UL << RTE_ETH_FLOW_TYPE_FRAG_IPV4) | \
> +	(1UL << RTE_ETH_FLOW_TYPE_UDPV6) | \
> +	(1UL << RTE_ETH_FLOW_TYPE_TCPV6) | \
> +	(1UL << RTE_ETH_FLOW_TYPE_SCTPV6) | \
> +	(1UL << RTE_ETH_FLOW_TYPE_IPV6_OTHER) | \
> +	(1UL << RTE_ETH_FLOW_TYPE_FRAG_IPV6))
> +
>  static int eth_i40e_dev_init(\
>  			__attribute__((unused)) struct eth_driver *eth_drv,
>  			struct rte_eth_dev *eth_dev);
> @@ -198,6 +210,7 @@ static int i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
>  				enum rte_filter_type filter_type,
>  				enum rte_filter_op filter_op,
>  				void *arg);
> +static void i40e_hw_init(struct i40e_hw *hw);
> 
>  static struct rte_pci_id pci_id_i40e_map[] = {
>  #define RTE_PCI_DEV_ID_DECL_I40E(vend, dev) {RTE_PCI_DEVICE(vend, dev)},
> @@ -397,6 +410,9 @@ eth_i40e_dev_init(__rte_unused struct eth_driver *eth_drv,
>  	/* Make sure all is clean before doing PF reset */
>  	i40e_clear_hw(hw);
> 
> +	/* Initialize the hardware */
> +	i40e_hw_init(hw);
> +
>  	/* Reset here to make sure all is clean for each PF */
>  	ret = i40e_pf_reset(hw);
>  	if (ret) {
> @@ -5120,6 +5136,264 @@ i40e_pf_config_mq_rx(struct i40e_pf *pf)
>  	return ret;
>  }
> 
> +/* Get the symmetric hash enable configurations per port */
> +static void
> +i40e_get_symmetric_hash_enable_per_port(struct i40e_hw *hw, uint8_t *enable)
> +{
> +	uint32_t reg = I40E_READ_REG(hw, I40E_PRTQF_CTL_0);
> +
> +	*enable = reg & I40E_PRTQF_CTL_0_HSYM_ENA_MASK ? 1 : 0;
> +}
> +
> +/* Set the symmetric hash enable configurations per port */
> +static void
> +i40e_set_symmetric_hash_enable_per_port(struct i40e_hw *hw, uint8_t enable)
> +{
> +	uint32_t reg = I40E_READ_REG(hw, I40E_PRTQF_CTL_0);
> +
> +	if (enable > 0) {
> +		if (reg & I40E_PRTQF_CTL_0_HSYM_ENA_MASK) {
> +			PMD_DRV_LOG(INFO, "Symmetric hash has already "
> +							"been enabled");
> +			return;
> +		}
> +		reg |= I40E_PRTQF_CTL_0_HSYM_ENA_MASK;
> +	} else {
> +		if (!(reg & I40E_PRTQF_CTL_0_HSYM_ENA_MASK)) {
> +			PMD_DRV_LOG(INFO, "Symmetric hash has already "
> +							"been disabled");
> +			return;
> +		}
> +		reg &= ~I40E_PRTQF_CTL_0_HSYM_ENA_MASK;
> +	}
> +	I40E_WRITE_REG(hw, I40E_PRTQF_CTL_0, reg);
> +	I40E_WRITE_FLUSH(hw);
> +}
> +
> +/*
> + * Get global configurations of hash function type and symmetric hash enable
> + * per flow type (pctype). Note that global configuration means it affects all
> + * the ports on the same NIC.
> + */
> +static int
> +i40e_get_hash_filter_global_config(struct i40e_hw *hw,
> +				   struct rte_eth_hash_global_conf *g_cfg)
> +{
> +	uint32_t reg, mask = I40E_FLOW_TYPES;
> +	enum rte_eth_flow_type i;
> +	enum i40e_filter_pctype pctype;
> +
> +	memset(g_cfg, 0, sizeof(*g_cfg));
> +	reg = I40E_READ_REG(hw, I40E_GLQF_CTL);
> +	if (reg & I40E_GLQF_CTL_HTOEP_MASK)
> +		g_cfg->hash_func = RTE_ETH_HASH_FUNCTION_TOEPLITZ;
> +	else
> +		g_cfg->hash_func = RTE_ETH_HASH_FUNCTION_SIMPLE_XOR;
> +	PMD_DRV_LOG(DEBUG, "Hash function is %s",
> +		(reg & I40E_GLQF_CTL_HTOEP_MASK) ? "Toeplitz" : "Simple XOR");
> +
> +	for (i = 0; mask && i < RTE_ETH_FLOW_TYPE_MAX; i++) {
> +		if (!(mask & (1UL << i)))
> +			continue;
> +		mask &= ~(1UL << i);
> +		/* Bit set indicats the coresponding flow type is supported */
> +		g_cfg->valid_bit_mask[0] |= (1UL << i);
> +		pctype = i40e_flowtype_to_pctype(i);
> +		if (!pctype)
> +			continue;

As I said in offline discussion, we don't need these 2 lines above:
If i40e supports that flow type (bit in a mask is set), then we surely should be able to convert it to pctype.

> +		reg = I40E_READ_REG(hw, I40E_GLQF_HSYM(pctype));
> +		if (reg & I40E_GLQF_HSYM_SYMH_ENA_MASK)
> +			g_cfg->sym_hash_enable_mask[0] |= (1UL << i);
> +	}
> +
> +	return 0;
> +}
> +
> +static int
> +i40e_hash_global_config_check(struct rte_eth_hash_global_conf *g_cfg)
> +{
> +	uint32_t i;
> +	uint32_t mask0, i40e_mask = I40E_FLOW_TYPES;
> +
> +	if (g_cfg->hash_func != RTE_ETH_HASH_FUNCTION_TOEPLITZ &&
> +		g_cfg->hash_func != RTE_ETH_HASH_FUNCTION_SIMPLE_XOR &&
> +		g_cfg->hash_func != RTE_ETH_HASH_FUNCTION_DEFAULT) {
> +		PMD_DRV_LOG(ERR, "Unsupported hash function type %d",
> +						g_cfg->hash_func);
> +		return -EINVAL;
> +	}
> +
> +	/*
> +	 * As i40e supports less than 32 flow types, only first 32 bits need to
> +	 * be checked.
> +	 */
> +	mask0 = g_cfg->valid_bit_mask[0];
> +	for (i = 0; i < RTE_SYM_HASH_MASK_ARRAY_SIZE; i++) {
> +		if (i == 0) {
> +			/* Check if any unsupported flow type configured */
> +			if ((mask0 | i40e_mask) ^ i40e_mask)
> +				goto mask_err;
> +		} else {
> +			if (g_cfg->valid_bit_mask[i])
> +				goto mask_err;
> +		}
> +	}
> +
> +	return 0;
> +
> +mask_err:
> +	PMD_DRV_LOG(ERR, "i40e unsupported flow type bit(s) configured");
> +
> +	return -EINVAL;
> +}
> +
> +/*
> + * Set global configurations of hash function type and symmetric hash enable
> + * per flow type (pctype). Note any modifying global configuration will affect
> + * all the ports on the same NIC.
> + */
> +static int
> +i40e_set_hash_filter_global_config(struct i40e_hw *hw,
> +				   struct rte_eth_hash_global_conf *g_cfg)
> +{
> +	int ret;
> +	uint32_t i, reg;
> +	uint32_t mask0 = g_cfg->valid_bit_mask[0];
> +	enum i40e_filter_pctype pctype;
> +
> +	/* Check the input parameters */
> +	ret = i40e_hash_global_config_check(g_cfg);
> +	if (ret < 0)
> +		return ret;
> +
> +	for (i = 0; mask0 && i < UINT32_BIT; i++) {
> +		if (!(mask0 & (1UL << i)))
> +			continue;
> +		mask0 &= ~(1UL << i);
> +		pctype = i40e_flowtype_to_pctype(i);
> +		if (!pctype)
> +			continue;

As I said in offline discussion, we don't need these 2 lines above:
If i40e supports that flow type (bit in a mask is set), then we surely should be able to convert it to pctype.


> +		reg = (g_cfg->sym_hash_enable_mask[0] & (1UL << i)) ?
> +				I40E_GLQF_HSYM_SYMH_ENA_MASK : 0;
> +		I40E_WRITE_REG(hw, I40E_GLQF_HSYM(pctype), reg);
> +	}
> +
> +	reg = I40E_READ_REG(hw, I40E_GLQF_CTL);
> +	if (g_cfg->hash_func == RTE_ETH_HASH_FUNCTION_TOEPLITZ) {
> +		/* Toeplitz */
> +		if (reg & I40E_GLQF_CTL_HTOEP_MASK) {
> +			PMD_DRV_LOG(DEBUG, "Hash function already set to "
> +								"Toeplitz");
> +			goto out;
> +		}
> +		reg |= I40E_GLQF_CTL_HTOEP_MASK;
> +	} else if (g_cfg->hash_func == RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) {
> +		/* Simple XOR */
> +		if (!(reg & I40E_GLQF_CTL_HTOEP_MASK)) {
> +			PMD_DRV_LOG(DEBUG, "Hash function already set to "
> +							"Simple XOR");
> +			goto out;
> +		}
> +		reg &= ~I40E_GLQF_CTL_HTOEP_MASK;
> +	} else
> +		/* Use the default, and keep it as it is */
> +		goto out;
> +
> +	I40E_WRITE_REG(hw, I40E_GLQF_CTL, reg);
> +
> +out:
> +	I40E_WRITE_FLUSH(hw);
> +
> +	return 0;
> +}
> +
> +static int
> +i40e_hash_filter_get(struct i40e_hw *hw, struct rte_eth_hash_filter_info *info)
> +{
> +	int ret = 0;
> +
> +	if (!hw || !info) {
> +		PMD_DRV_LOG(ERR, "Invalid pointer");
> +		return -EFAULT;
> +	}
> +
> +	switch (info->info_type) {
> +	case RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT:
> +		i40e_get_symmetric_hash_enable_per_port(hw,
> +					&(info->info.enable));
> +		break;
> +	case RTE_ETH_HASH_FILTER_GLOBAL_CONFIG:
> +		ret = i40e_get_hash_filter_global_config(hw,
> +				&(info->info.global_conf));
> +		break;
> +	default:
> +		PMD_DRV_LOG(ERR, "Hash filter info type (%d) not supported",
> +							info->info_type);
> +		ret = -EINVAL;
> +		break;
> +	}
> +
> +	return ret;
> +}
> +
> +static int
> +i40e_hash_filter_set(struct i40e_hw *hw, struct rte_eth_hash_filter_info *info)
> +{
> +	int ret = 0;
> +
> +	if (!hw || !info) {
> +		PMD_DRV_LOG(ERR, "Invalid pointer");
> +		return -EFAULT;
> +	}
> +
> +	switch (info->info_type) {
> +	case RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT:
> +		i40e_set_symmetric_hash_enable_per_port(hw, info->info.enable);
> +		break;
> +	case RTE_ETH_HASH_FILTER_GLOBAL_CONFIG:
> +		ret = i40e_set_hash_filter_global_config(hw,
> +				&(info->info.global_conf));
> +		break;
> +	default:
> +		PMD_DRV_LOG(ERR, "Hash filter info type (%d) not supported",
> +							info->info_type);
> +		ret = -EINVAL;
> +		break;
> +	}
> +
> +	return ret;
> +}
> +
> +/* Operations for hash function */
> +static int
> +i40e_hash_filter_ctrl(struct rte_eth_dev *dev,
> +		      enum rte_filter_op filter_op,
> +		      void *arg)
> +{
> +	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
> +	int ret = 0;
> +
> +	switch (filter_op) {
> +	case RTE_ETH_FILTER_NOP:
> +		break;
> +	case RTE_ETH_FILTER_GET:
> +		ret = i40e_hash_filter_get(hw,
> +			(struct rte_eth_hash_filter_info *)arg);
> +		break;
> +	case RTE_ETH_FILTER_SET:
> +		ret = i40e_hash_filter_set(hw,
> +			(struct rte_eth_hash_filter_info *)arg);
> +		break;
> +	default:
> +		PMD_DRV_LOG(WARNING, "Filter operation (%d) not supported",
> +								filter_op);
> +		ret = -ENOTSUP;
> +		break;
> +	}
> +
> +	return ret;
> +}
> +
>  /*
>   * Configure ethertype filter, which can director packet by filtering
>   * with mac address and ether_type or only ether_type
> @@ -5222,6 +5496,9 @@ i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
>  		return -EINVAL;
> 
>  	switch (filter_type) {
> +	case RTE_ETH_FILTER_HASH:
> +		ret = i40e_hash_filter_ctrl(dev, filter_op, arg);
> +		break;
>  	case RTE_ETH_FILTER_MACVLAN:
>  		ret = i40e_mac_filter_handle(dev, filter_op, arg);
>  		break;
> @@ -5244,10 +5521,26 @@ i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
>  	return ret;
>  }
> 
> +/*
> + * As some registers wouldn't be reset unless a global hardware reset,
> + * hardware initialization is needed to put those registers into an
> + * expected initial state.
> + */
> +static void
> +i40e_hw_init(struct i40e_hw *hw)
> +{
> +	/* clear the PF Queue Filter control register */
> +	I40E_WRITE_REG(hw, I40E_PFQF_CTL_0, 0);
> +
> +	/* Disable symmetric hash per port */
> +	i40e_set_symmetric_hash_enable_per_port(hw, 0);
> +}
> +
>  enum i40e_filter_pctype
>  i40e_flowtype_to_pctype(enum rte_eth_flow_type flow_type)
>  {
> -	static const enum i40e_filter_pctype pctype_table[] = {
> +	static const enum i40e_filter_pctype
> +		pctype_table[RTE_ETH_FLOW_TYPE_MAX] = {
>  		[RTE_ETH_FLOW_TYPE_UDPV4] = I40E_FILTER_PCTYPE_NONF_IPV4_UDP,
>  		[RTE_ETH_FLOW_TYPE_TCPV4] = I40E_FILTER_PCTYPE_NONF_IPV4_TCP,
>  		[RTE_ETH_FLOW_TYPE_SCTPV4] = I40E_FILTER_PCTYPE_NONF_IPV4_SCTP,
> @@ -5270,7 +5563,8 @@ i40e_flowtype_to_pctype(enum rte_eth_flow_type flow_type)
>  enum rte_eth_flow_type
>  i40e_pctype_to_flowtype(enum i40e_filter_pctype pctype)
>  {
> -	static const enum rte_eth_flow_type flowtype_table[] = {
> +	static const enum rte_eth_flow_type
> +		flowtype_table[RTE_ETH_FLOW_TYPE_MAX] = {
>  		[I40E_FILTER_PCTYPE_NONF_IPV4_UDP] = RTE_ETH_FLOW_TYPE_UDPV4,
>  		[I40E_FILTER_PCTYPE_NONF_IPV4_TCP] = RTE_ETH_FLOW_TYPE_TCPV4,
>  		[I40E_FILTER_PCTYPE_NONF_IPV4_SCTP] = RTE_ETH_FLOW_TYPE_SCTPV4,
> --
> 1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v8 0/4] Support configuring hash functions
  2014-11-28 12:14         ` [dpdk-dev] [PATCH v7 0/4] " Helin Zhang
                             ` (3 preceding siblings ...)
  2014-11-28 12:14           ` [dpdk-dev] [PATCH v7 4/4] app/testpmd: app/testpmd: add commands to support " Helin Zhang
@ 2014-12-02  2:19           ` Helin Zhang
  2014-12-02  2:19             ` [dpdk-dev] [PATCH v8 1/4] ethdev: code style fixes Helin Zhang
                               ` (5 more replies)
  4 siblings, 6 replies; 71+ messages in thread
From: Helin Zhang @ 2014-12-02  2:19 UTC (permalink / raw)
  To: dev

These patches mainly support configuring hash functions. In detail,
 - It can get/set global hash configurations.
  * Get/set symmetric hash enable per flow type.
  * Get/set hash function type.
 - It can get/set symmetric hash enable per port.
 - Four commands have been implemented in testpmd to support testing above.
   * get_sym_hash_ena_per_port
   * set_sym_hash_ena_per_port
   * get_hash_global_config
   * set_hash_global_config

It also uses constant hash keys to replace runtime generating hash keys.
Global initialization is added to correctly put registers to an initial state.

v3 changes:
* Removed renamings in rte_ethdev.h.
* Redesigned filter control API and its relevant structures/enums.
* Renamed header file from rte_eth_features.h to rte_eth_ctrol.h.
* Remove public header file of rte_i40e.h specific for i40e.
* Added hardware initialization function during port init.
* Used constant random hash keys in i40e PF.
* renamed the commands in testpmd based on the redesigned filter control API.

v4 changes:
* Fixed a bug in testpmd to support 'set_sym_hash_ena_per_port'.

v5 changes:
* Integrated with filter API defined recently.
* Remove all for filter API definition, as it has already defined and merged
  recently.

v6 changes:
* Flow type strings are used to replace Packet Classification Types, to isolate
  hardware specific things.
* Implemented the mapping function to convert RSS offload types to Packet
  Classification Types, to isolate the real hardware specific things.
* Removed initialization of global registers in i40e PMD, as global registers
  shouldn't be initialized per port.
* Added more annotations to get code more understandable.
* Corrected annotation format for documenation.

v7 changes:
* Removed swap configurations, as it is not allowed by hardware design.
* Put symmetric hash per flow type and hash function type into
  'RTE_ETH_HASH_FILTER_GLOBAL_CONFIG', as they are controlling global registers
  which will affects all the ports of the same NIC.

v8 changes:
* Removed redundant checks in i40e_ethdev.c.
* Solved compile errors on ICC.

Helin Zhang (4):
  ethdev: code style fixes
  i40e: use constant as the default hash keys
  i40e: support of controlling hash functions
  app/testpmd: add commands to support hash functions

 app/test-pmd/cmdline.c            | 333 ++++++++++++++++++++++++++++++++++++++
 lib/librte_ether/rte_eth_ctrl.h   |  72 ++++++++-
 lib/librte_pmd_i40e/i40e_ethdev.c | 308 +++++++++++++++++++++++++++++++++--
 3 files changed, 699 insertions(+), 14 deletions(-)

-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v8 1/4] ethdev: code style fixes
  2014-12-02  2:19           ` [dpdk-dev] [PATCH v8 0/4] Support configuring " Helin Zhang
@ 2014-12-02  2:19             ` Helin Zhang
  2014-12-02  2:19             ` [dpdk-dev] [PATCH v8 2/4] i40e: use constant as the default hash keys Helin Zhang
                               ` (4 subsequent siblings)
  5 siblings, 0 replies; 71+ messages in thread
From: Helin Zhang @ 2014-12-02  2:19 UTC (permalink / raw)
  To: dev

Added code style fixes.

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
---
 lib/librte_ether/rte_eth_ctrl.h | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/lib/librte_ether/rte_eth_ctrl.h b/lib/librte_ether/rte_eth_ctrl.h
index 7088d8d..6ab16c2 100644
--- a/lib/librte_ether/rte_eth_ctrl.h
+++ b/lib/librte_ether/rte_eth_ctrl.h
@@ -62,8 +62,8 @@ enum rte_filter_type {
  * Generic operations on filters
  */
 enum rte_filter_op {
+	/** used to check whether the type filter is supported */
 	RTE_ETH_FILTER_NOP = 0,
-	/**< used to check whether the type filter is supported */
 	RTE_ETH_FILTER_ADD,      /**< add filter entry */
 	RTE_ETH_FILTER_UPDATE,   /**< update filter entry */
 	RTE_ETH_FILTER_DELETE,   /**< delete filter entry */
@@ -75,16 +75,15 @@ enum rte_filter_op {
 	RTE_ETH_FILTER_OP_MAX
 };
 
-/**
+/*
  * MAC filter type
  */
 enum rte_mac_filter_type {
 	RTE_MAC_PERFECT_MATCH = 1, /**< exact match of MAC addr. */
-	RTE_MACVLAN_PERFECT_MATCH,
-	/**< exact match of MAC addr and VLAN ID. */
+	RTE_MACVLAN_PERFECT_MATCH, /**< exact match of MAC addr and VLAN ID. */
 	RTE_MAC_HASH_MATCH, /**< hash match of MAC addr. */
+	/** hash match of MAC addr and exact match of VLAN ID. */
 	RTE_MACVLAN_HASH_MATCH,
-	/**< hash match of MAC addr and exact match of VLAN ID. */
 };
 
 /**
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v8 2/4] i40e: use constant as the default hash keys
  2014-12-02  2:19           ` [dpdk-dev] [PATCH v8 0/4] Support configuring " Helin Zhang
  2014-12-02  2:19             ` [dpdk-dev] [PATCH v8 1/4] ethdev: code style fixes Helin Zhang
@ 2014-12-02  2:19             ` Helin Zhang
  2014-12-02  2:19             ` [dpdk-dev] [PATCH v8 3/4] i40e: support of controlling hash functions Helin Zhang
                               ` (3 subsequent siblings)
  5 siblings, 0 replies; 71+ messages in thread
From: Helin Zhang @ 2014-12-02  2:19 UTC (permalink / raw)
  To: dev

Calculating the default RSS hash keys at run time is not needed
at all, and may have race conditions. The alternative is to use
array of random values which were generated manually as the
default hash keys.

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
---
 lib/librte_pmd_i40e/i40e_ethdev.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/lib/librte_pmd_i40e/i40e_ethdev.c b/lib/librte_pmd_i40e/i40e_ethdev.c
index 87e750a..8fbe25f 100644
--- a/lib/librte_pmd_i40e/i40e_ethdev.c
+++ b/lib/librte_pmd_i40e/i40e_ethdev.c
@@ -73,7 +73,7 @@
 /* Maximun number of VSI */
 #define I40E_MAX_NUM_VSIS          (384UL)
 
-/* Default queue interrupt throttling time in microseconds*/
+/* Default queue interrupt throttling time in microseconds */
 #define I40E_ITR_INDEX_DEFAULT          0
 #define I40E_QUEUE_ITR_INTERVAL_DEFAULT 32 /* 32 us */
 #define I40E_QUEUE_ITR_INTERVAL_MAX     8160 /* 8160 us */
@@ -199,9 +199,6 @@ static int i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
 				enum rte_filter_op filter_op,
 				void *arg);
 
-/* Default hash key buffer for RSS */
-static uint32_t rss_key_default[I40E_PFQF_HKEY_MAX_INDEX + 1];
-
 static struct rte_pci_id pci_id_i40e_map[] = {
 #define RTE_PCI_DEV_ID_DECL_I40E(vend, dev) {RTE_PCI_DEVICE(vend, dev)},
 #include "rte_pci_dev_ids.h"
@@ -5023,9 +5020,12 @@ i40e_pf_config_rss(struct i40e_pf *pf)
 	}
 	if (rss_conf.rss_key == NULL || rss_conf.rss_key_len <
 		(I40E_PFQF_HKEY_MAX_INDEX + 1) * sizeof(uint32_t)) {
-		/* Calculate the default hash key */
-		for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++)
-			rss_key_default[i] = (uint32_t)rte_rand();
+		/* Random default keys */
+		static uint32_t rss_key_default[] = {0x6b793944,
+			0x23504cb5, 0x5bea75b6, 0x309f4f12, 0x3dc0a2b8,
+			0x024ddcdf, 0x339b8ca0, 0x4c4af64a, 0x34fac605,
+			0x55d85839, 0x3a58997d, 0x2ec938e1, 0x66031581};
+
 		rss_conf.rss_key = (uint8_t *)rss_key_default;
 		rss_conf.rss_key_len = (I40E_PFQF_HKEY_MAX_INDEX + 1) *
 							sizeof(uint32_t);
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v8 3/4] i40e: support of controlling hash functions
  2014-12-02  2:19           ` [dpdk-dev] [PATCH v8 0/4] Support configuring " Helin Zhang
  2014-12-02  2:19             ` [dpdk-dev] [PATCH v8 1/4] ethdev: code style fixes Helin Zhang
  2014-12-02  2:19             ` [dpdk-dev] [PATCH v8 2/4] i40e: use constant as the default hash keys Helin Zhang
@ 2014-12-02  2:19             ` Helin Zhang
  2015-01-20  7:54               ` Thomas Monjalon
  2014-12-02  2:19             ` [dpdk-dev] [PATCH v8 4/4] app/testpmd: add commands to support " Helin Zhang
                               ` (2 subsequent siblings)
  5 siblings, 1 reply; 71+ messages in thread
From: Helin Zhang @ 2014-12-02  2:19 UTC (permalink / raw)
  To: dev

Hash filter control has been implemented for i40e. It includes
getting/setting,
- global hash configurations (hash function type, and symmetric
  hash enable per flow type)
- symmetric hash enable per port

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
---
 lib/librte_ether/rte_eth_ctrl.h   |  63 ++++++++
 lib/librte_pmd_i40e/i40e_ethdev.c | 294 +++++++++++++++++++++++++++++++++++++-
 2 files changed, 355 insertions(+), 2 deletions(-)

v5 changes:
* Integrated with filter API defined recently.

v6 changes:
* Implemented the mapping function to convert RSS offload types to Packet
  Classification Types, to isolate the real hardware specific things.
* Removed initialization of global registers in i40e PMD, as global registers
  shouldn't be initialized per port.
* Added more annotations to get code more understandable.
* Corrected annotation format for documenation.

v7 changes:
* Removed swap configurations, as it is not allowed by hardware design.
* Put symmetric hash per flow type and hash function type into
  'RTE_ETH_HASH_FILTER_GLOBAL_CONFIG', as they are controlling global registers
  which will affects all the ports of the same NIC.

v8 changes:
* Removed redundant return value checks of i40e_flowtype_to_pctype(), as it
  should always be correct.
* Fixed the compile issue on ICC, of "error #188: enumerated type mixed with
  another type".

diff --git a/lib/librte_ether/rte_eth_ctrl.h b/lib/librte_ether/rte_eth_ctrl.h
index 6ab16c2..827d7ba 100644
--- a/lib/librte_ether/rte_eth_ctrl.h
+++ b/lib/librte_ether/rte_eth_ctrl.h
@@ -55,6 +55,7 @@ enum rte_filter_type {
 	RTE_ETH_FILTER_ETHERTYPE,
 	RTE_ETH_FILTER_TUNNEL,
 	RTE_ETH_FILTER_FDIR,
+	RTE_ETH_FILTER_HASH,
 	RTE_ETH_FILTER_MAX
 };
 
@@ -449,6 +450,68 @@ struct rte_eth_fdir_stats {
 	uint32_t best_cnt;     /**< Number of filters in best effort spaces. */
 };
 
+/**
+ * Hash filter information types.
+ * - RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT is for getting/setting the
+ *   information/configuration of 'symmetric hash enable' per port.
+ * - RTE_ETH_HASH_FILTER_GLOBAL_CONFIG is for getting/setting the global
+ *   configurations of hash filters. Those global configurations are valid
+ *   for all ports of the same NIC.
+ */
+enum rte_eth_hash_filter_info_type {
+	RTE_ETH_HASH_FILTER_INFO_TYPE_UNKNOWN = 0,
+	/** Symmetric hash enable per port */
+	RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT,
+	/** Configure globally for hash filter */
+	RTE_ETH_HASH_FILTER_GLOBAL_CONFIG,
+	RTE_ETH_HASH_FILTER_INFO_TYPE_MAX,
+};
+
+/**
+ * Hash function types.
+ */
+enum rte_eth_hash_function {
+	RTE_ETH_HASH_FUNCTION_DEFAULT = 0,
+	RTE_ETH_HASH_FUNCTION_TOEPLITZ, /**< Toeplitz */
+	RTE_ETH_HASH_FUNCTION_SIMPLE_XOR, /**< Simple XOR */
+	RTE_ETH_HASH_FUNCTION_MAX,
+};
+
+#define UINT32_BIT (CHAR_BIT * sizeof(uint32_t))
+#define RTE_SYM_HASH_MASK_ARRAY_SIZE \
+	(RTE_ALIGN(RTE_ETH_FLOW_TYPE_MAX, UINT32_BIT)/UINT32_BIT)
+/**
+ * A structure used to set or get global hash function configurations which
+ * include symmetric hash enable per flow type and hash function type.
+ * Each bit in sym_hash_enable_mask[] indicates if the symmetric hash of the
+ * coresponding flow type is enabled or not.
+ * Each bit in valid_bit_mask[] indicates if the coresponding bit in
+ * sym_hash_enable_mask[] is valid or not. For the configurations gotten, it
+ * also means if the flow type is supported by hardware or not.
+ */
+struct rte_eth_hash_global_conf {
+	enum rte_eth_hash_function hash_func; /**< Hash function type */
+	/** Bit mask for symmetric hash enable per flow type */
+	uint32_t sym_hash_enable_mask[RTE_SYM_HASH_MASK_ARRAY_SIZE];
+	/** Bit mask indicates if the coresponding bit is valid */
+	uint32_t valid_bit_mask[RTE_SYM_HASH_MASK_ARRAY_SIZE];
+};
+
+/**
+ * A structure used to set or get hash filter information, to support filter
+ * type of 'RTE_ETH_FILTER_HASH' and its operations.
+ */
+struct rte_eth_hash_filter_info {
+	enum rte_eth_hash_filter_info_type info_type; /**< Information type. */
+	/** Details of hash filter infomation */
+	union {
+		/* For RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT */
+		uint8_t enable;
+		/* Global configurations of hash filter */
+		struct rte_eth_hash_global_conf global_conf;
+	} info;
+};
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_pmd_i40e/i40e_ethdev.c b/lib/librte_pmd_i40e/i40e_ethdev.c
index 8fbe25f..fa9cac8 100644
--- a/lib/librte_pmd_i40e/i40e_ethdev.c
+++ b/lib/librte_pmd_i40e/i40e_ethdev.c
@@ -93,6 +93,18 @@
 		I40E_PFINT_ICR0_ENA_VFLR_MASK | \
 		I40E_PFINT_ICR0_ENA_ADMINQ_MASK)
 
+#define I40E_FLOW_TYPES ( \
+	(1UL << RTE_ETH_FLOW_TYPE_UDPV4) | \
+	(1UL << RTE_ETH_FLOW_TYPE_TCPV4) | \
+	(1UL << RTE_ETH_FLOW_TYPE_SCTPV4) | \
+	(1UL << RTE_ETH_FLOW_TYPE_IPV4_OTHER) | \
+	(1UL << RTE_ETH_FLOW_TYPE_FRAG_IPV4) | \
+	(1UL << RTE_ETH_FLOW_TYPE_UDPV6) | \
+	(1UL << RTE_ETH_FLOW_TYPE_TCPV6) | \
+	(1UL << RTE_ETH_FLOW_TYPE_SCTPV6) | \
+	(1UL << RTE_ETH_FLOW_TYPE_IPV6_OTHER) | \
+	(1UL << RTE_ETH_FLOW_TYPE_FRAG_IPV6))
+
 static int eth_i40e_dev_init(\
 			__attribute__((unused)) struct eth_driver *eth_drv,
 			struct rte_eth_dev *eth_dev);
@@ -198,6 +210,7 @@ static int i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
 				enum rte_filter_type filter_type,
 				enum rte_filter_op filter_op,
 				void *arg);
+static void i40e_hw_init(struct i40e_hw *hw);
 
 static struct rte_pci_id pci_id_i40e_map[] = {
 #define RTE_PCI_DEV_ID_DECL_I40E(vend, dev) {RTE_PCI_DEVICE(vend, dev)},
@@ -397,6 +410,9 @@ eth_i40e_dev_init(__rte_unused struct eth_driver *eth_drv,
 	/* Make sure all is clean before doing PF reset */
 	i40e_clear_hw(hw);
 
+	/* Initialize the hardware */
+	i40e_hw_init(hw);
+
 	/* Reset here to make sure all is clean for each PF */
 	ret = i40e_pf_reset(hw);
 	if (ret) {
@@ -5120,6 +5136,260 @@ i40e_pf_config_mq_rx(struct i40e_pf *pf)
 	return ret;
 }
 
+/* Get the symmetric hash enable configurations per port */
+static void
+i40e_get_symmetric_hash_enable_per_port(struct i40e_hw *hw, uint8_t *enable)
+{
+	uint32_t reg = I40E_READ_REG(hw, I40E_PRTQF_CTL_0);
+
+	*enable = reg & I40E_PRTQF_CTL_0_HSYM_ENA_MASK ? 1 : 0;
+}
+
+/* Set the symmetric hash enable configurations per port */
+static void
+i40e_set_symmetric_hash_enable_per_port(struct i40e_hw *hw, uint8_t enable)
+{
+	uint32_t reg = I40E_READ_REG(hw, I40E_PRTQF_CTL_0);
+
+	if (enable > 0) {
+		if (reg & I40E_PRTQF_CTL_0_HSYM_ENA_MASK) {
+			PMD_DRV_LOG(INFO, "Symmetric hash has already "
+							"been enabled");
+			return;
+		}
+		reg |= I40E_PRTQF_CTL_0_HSYM_ENA_MASK;
+	} else {
+		if (!(reg & I40E_PRTQF_CTL_0_HSYM_ENA_MASK)) {
+			PMD_DRV_LOG(INFO, "Symmetric hash has already "
+							"been disabled");
+			return;
+		}
+		reg &= ~I40E_PRTQF_CTL_0_HSYM_ENA_MASK;
+	}
+	I40E_WRITE_REG(hw, I40E_PRTQF_CTL_0, reg);
+	I40E_WRITE_FLUSH(hw);
+}
+
+/*
+ * Get global configurations of hash function type and symmetric hash enable
+ * per flow type (pctype). Note that global configuration means it affects all
+ * the ports on the same NIC.
+ */
+static int
+i40e_get_hash_filter_global_config(struct i40e_hw *hw,
+				   struct rte_eth_hash_global_conf *g_cfg)
+{
+	uint32_t reg, mask = I40E_FLOW_TYPES;
+	uint32_t i;
+	enum i40e_filter_pctype pctype;
+
+	memset(g_cfg, 0, sizeof(*g_cfg));
+	reg = I40E_READ_REG(hw, I40E_GLQF_CTL);
+	if (reg & I40E_GLQF_CTL_HTOEP_MASK)
+		g_cfg->hash_func = RTE_ETH_HASH_FUNCTION_TOEPLITZ;
+	else
+		g_cfg->hash_func = RTE_ETH_HASH_FUNCTION_SIMPLE_XOR;
+	PMD_DRV_LOG(DEBUG, "Hash function is %s",
+		(reg & I40E_GLQF_CTL_HTOEP_MASK) ? "Toeplitz" : "Simple XOR");
+
+	for (i = 0; mask && i < RTE_ETH_FLOW_TYPE_MAX; i++) {
+		if (!(mask & (1UL << i)))
+			continue;
+		mask &= ~(1UL << i);
+		/* Bit set indicats the coresponding flow type is supported */
+		g_cfg->valid_bit_mask[0] |= (1UL << i);
+		pctype = i40e_flowtype_to_pctype((enum rte_eth_flow_type)i);
+		reg = I40E_READ_REG(hw, I40E_GLQF_HSYM(pctype));
+		if (reg & I40E_GLQF_HSYM_SYMH_ENA_MASK)
+			g_cfg->sym_hash_enable_mask[0] |= (1UL << i);
+	}
+
+	return 0;
+}
+
+static int
+i40e_hash_global_config_check(struct rte_eth_hash_global_conf *g_cfg)
+{
+	uint32_t i;
+	uint32_t mask0, i40e_mask = I40E_FLOW_TYPES;
+
+	if (g_cfg->hash_func != RTE_ETH_HASH_FUNCTION_TOEPLITZ &&
+		g_cfg->hash_func != RTE_ETH_HASH_FUNCTION_SIMPLE_XOR &&
+		g_cfg->hash_func != RTE_ETH_HASH_FUNCTION_DEFAULT) {
+		PMD_DRV_LOG(ERR, "Unsupported hash function type %d",
+						g_cfg->hash_func);
+		return -EINVAL;
+	}
+
+	/*
+	 * As i40e supports less than 32 flow types, only first 32 bits need to
+	 * be checked.
+	 */
+	mask0 = g_cfg->valid_bit_mask[0];
+	for (i = 0; i < RTE_SYM_HASH_MASK_ARRAY_SIZE; i++) {
+		if (i == 0) {
+			/* Check if any unsupported flow type configured */
+			if ((mask0 | i40e_mask) ^ i40e_mask)
+				goto mask_err;
+		} else {
+			if (g_cfg->valid_bit_mask[i])
+				goto mask_err;
+		}
+	}
+
+	return 0;
+
+mask_err:
+	PMD_DRV_LOG(ERR, "i40e unsupported flow type bit(s) configured");
+
+	return -EINVAL;
+}
+
+/*
+ * Set global configurations of hash function type and symmetric hash enable
+ * per flow type (pctype). Note any modifying global configuration will affect
+ * all the ports on the same NIC.
+ */
+static int
+i40e_set_hash_filter_global_config(struct i40e_hw *hw,
+				   struct rte_eth_hash_global_conf *g_cfg)
+{
+	int ret;
+	uint32_t i, reg;
+	uint32_t mask0 = g_cfg->valid_bit_mask[0];
+	enum i40e_filter_pctype pctype;
+
+	/* Check the input parameters */
+	ret = i40e_hash_global_config_check(g_cfg);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; mask0 && i < UINT32_BIT; i++) {
+		if (!(mask0 & (1UL << i)))
+			continue;
+		mask0 &= ~(1UL << i);
+		pctype = i40e_flowtype_to_pctype((enum rte_eth_flow_type)i);
+		reg = (g_cfg->sym_hash_enable_mask[0] & (1UL << i)) ?
+				I40E_GLQF_HSYM_SYMH_ENA_MASK : 0;
+		I40E_WRITE_REG(hw, I40E_GLQF_HSYM(pctype), reg);
+	}
+
+	reg = I40E_READ_REG(hw, I40E_GLQF_CTL);
+	if (g_cfg->hash_func == RTE_ETH_HASH_FUNCTION_TOEPLITZ) {
+		/* Toeplitz */
+		if (reg & I40E_GLQF_CTL_HTOEP_MASK) {
+			PMD_DRV_LOG(DEBUG, "Hash function already set to "
+								"Toeplitz");
+			goto out;
+		}
+		reg |= I40E_GLQF_CTL_HTOEP_MASK;
+	} else if (g_cfg->hash_func == RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) {
+		/* Simple XOR */
+		if (!(reg & I40E_GLQF_CTL_HTOEP_MASK)) {
+			PMD_DRV_LOG(DEBUG, "Hash function already set to "
+							"Simple XOR");
+			goto out;
+		}
+		reg &= ~I40E_GLQF_CTL_HTOEP_MASK;
+	} else
+		/* Use the default, and keep it as it is */
+		goto out;
+
+	I40E_WRITE_REG(hw, I40E_GLQF_CTL, reg);
+
+out:
+	I40E_WRITE_FLUSH(hw);
+
+	return 0;
+}
+
+static int
+i40e_hash_filter_get(struct i40e_hw *hw, struct rte_eth_hash_filter_info *info)
+{
+	int ret = 0;
+
+	if (!hw || !info) {
+		PMD_DRV_LOG(ERR, "Invalid pointer");
+		return -EFAULT;
+	}
+
+	switch (info->info_type) {
+	case RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT:
+		i40e_get_symmetric_hash_enable_per_port(hw,
+					&(info->info.enable));
+		break;
+	case RTE_ETH_HASH_FILTER_GLOBAL_CONFIG:
+		ret = i40e_get_hash_filter_global_config(hw,
+				&(info->info.global_conf));
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "Hash filter info type (%d) not supported",
+							info->info_type);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int
+i40e_hash_filter_set(struct i40e_hw *hw, struct rte_eth_hash_filter_info *info)
+{
+	int ret = 0;
+
+	if (!hw || !info) {
+		PMD_DRV_LOG(ERR, "Invalid pointer");
+		return -EFAULT;
+	}
+
+	switch (info->info_type) {
+	case RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT:
+		i40e_set_symmetric_hash_enable_per_port(hw, info->info.enable);
+		break;
+	case RTE_ETH_HASH_FILTER_GLOBAL_CONFIG:
+		ret = i40e_set_hash_filter_global_config(hw,
+				&(info->info.global_conf));
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "Hash filter info type (%d) not supported",
+							info->info_type);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+/* Operations for hash function */
+static int
+i40e_hash_filter_ctrl(struct rte_eth_dev *dev,
+		      enum rte_filter_op filter_op,
+		      void *arg)
+{
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	int ret = 0;
+
+	switch (filter_op) {
+	case RTE_ETH_FILTER_NOP:
+		break;
+	case RTE_ETH_FILTER_GET:
+		ret = i40e_hash_filter_get(hw,
+			(struct rte_eth_hash_filter_info *)arg);
+		break;
+	case RTE_ETH_FILTER_SET:
+		ret = i40e_hash_filter_set(hw,
+			(struct rte_eth_hash_filter_info *)arg);
+		break;
+	default:
+		PMD_DRV_LOG(WARNING, "Filter operation (%d) not supported",
+								filter_op);
+		ret = -ENOTSUP;
+		break;
+	}
+
+	return ret;
+}
+
 /*
  * Configure ethertype filter, which can director packet by filtering
  * with mac address and ether_type or only ether_type
@@ -5222,6 +5492,9 @@ i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
 		return -EINVAL;
 
 	switch (filter_type) {
+	case RTE_ETH_FILTER_HASH:
+		ret = i40e_hash_filter_ctrl(dev, filter_op, arg);
+		break;
 	case RTE_ETH_FILTER_MACVLAN:
 		ret = i40e_mac_filter_handle(dev, filter_op, arg);
 		break;
@@ -5244,10 +5517,26 @@ i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
 	return ret;
 }
 
+/*
+ * As some registers wouldn't be reset unless a global hardware reset,
+ * hardware initialization is needed to put those registers into an
+ * expected initial state.
+ */
+static void
+i40e_hw_init(struct i40e_hw *hw)
+{
+	/* clear the PF Queue Filter control register */
+	I40E_WRITE_REG(hw, I40E_PFQF_CTL_0, 0);
+
+	/* Disable symmetric hash per port */
+	i40e_set_symmetric_hash_enable_per_port(hw, 0);
+}
+
 enum i40e_filter_pctype
 i40e_flowtype_to_pctype(enum rte_eth_flow_type flow_type)
 {
-	static const enum i40e_filter_pctype pctype_table[] = {
+	static const enum i40e_filter_pctype
+		pctype_table[RTE_ETH_FLOW_TYPE_MAX] = {
 		[RTE_ETH_FLOW_TYPE_UDPV4] = I40E_FILTER_PCTYPE_NONF_IPV4_UDP,
 		[RTE_ETH_FLOW_TYPE_TCPV4] = I40E_FILTER_PCTYPE_NONF_IPV4_TCP,
 		[RTE_ETH_FLOW_TYPE_SCTPV4] = I40E_FILTER_PCTYPE_NONF_IPV4_SCTP,
@@ -5270,7 +5559,8 @@ i40e_flowtype_to_pctype(enum rte_eth_flow_type flow_type)
 enum rte_eth_flow_type
 i40e_pctype_to_flowtype(enum i40e_filter_pctype pctype)
 {
-	static const enum rte_eth_flow_type flowtype_table[] = {
+	static const enum rte_eth_flow_type
+		flowtype_table[RTE_ETH_FLOW_TYPE_MAX] = {
 		[I40E_FILTER_PCTYPE_NONF_IPV4_UDP] = RTE_ETH_FLOW_TYPE_UDPV4,
 		[I40E_FILTER_PCTYPE_NONF_IPV4_TCP] = RTE_ETH_FLOW_TYPE_TCPV4,
 		[I40E_FILTER_PCTYPE_NONF_IPV4_SCTP] = RTE_ETH_FLOW_TYPE_SCTPV4,
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v8 4/4] app/testpmd: add commands to support hash functions
  2014-12-02  2:19           ` [dpdk-dev] [PATCH v8 0/4] Support configuring " Helin Zhang
                               ` (2 preceding siblings ...)
  2014-12-02  2:19             ` [dpdk-dev] [PATCH v8 3/4] i40e: support of controlling hash functions Helin Zhang
@ 2014-12-02  2:19             ` Helin Zhang
  2014-12-02 13:15             ` [dpdk-dev] [PATCH v8 0/4] Support configuring " Ananyev, Konstantin
  2015-01-22  7:36             ` [dpdk-dev] [PATCH v9 0/5] " Helin Zhang
  5 siblings, 0 replies; 71+ messages in thread
From: Helin Zhang @ 2014-12-02  2:19 UTC (permalink / raw)
  To: dev

To demonstrate the hash filter control, commands are added.
They are,
- get_sym_hash_ena_per_port
- set_sym_hash_ena_per_port
- get_hash_global_config
- set_hash_global_config

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
---
 app/test-pmd/cmdline.c | 333 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 333 insertions(+)

v6 changes:
* Flow type strings are used to replace Packet Classification Types, to isolate
  hardware specific things.

v7 changes:
* Removed commands of,
  get_sym_hash_ena_per_pctype
  set_sym_hash_ena_per_pctype
  get_filter_swap
  set_filter_swap
  get_hash_function
  set_hash_function.
* Added new commands of,
  get_hash_global_config
  set_hash_global_config

v8 changes:
* Fixed the compile issue on ICC, of "error #188: enumerated type mixed with
  another type".

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index c61c3a0..f1b92a7 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -75,6 +75,7 @@
 #include <rte_ethdev.h>
 #include <rte_string_fns.h>
 #include <rte_devargs.h>
+#include <rte_eth_ctrl.h>
 
 #include <cmdline_rdline.h>
 #include <cmdline_parse.h>
@@ -740,6 +741,21 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"flow_director_flex_payload (port_id)"
 			" (l2|l3|l4) (config)\n"
 			"    Configure flex payload selection.\n\n"
+
+			"get_sym_hash_ena_per_port (port_id)\n"
+			"    get symmetric hash enable configuration per port.\n\n"
+
+			"set_sym_hash_ena_per_port (port_id) (enable|disable)\n"
+			"    set symmetric hash enable configuration per port"
+			" to enable or disable.\n\n"
+
+			"get_hash_global_config (port_id)\n"
+			"    Get the global configurations of hash filters.\n\n"
+
+			"set_hash_global_config (port_id) (toeplitz|simple_xor|default)"
+			" (ip4|ip4-frag|tcp4|udp4|#sctp4|ip6|ip6-frag|tcp6|udp6|sctp6)"
+			" (enable|disable)\n"
+			"    Set the global configurations of hash filters.\n\n"
 		);
 	}
 }
@@ -8697,6 +8713,319 @@ cmdline_parse_inst_t cmd_set_flow_director_flex_payload = {
 	},
 };
 
+/* *** Classification Filters Control *** */
+/* *** Get symmetric hash enable per port *** */
+struct cmd_get_sym_hash_ena_per_port_result {
+	cmdline_fixed_string_t get_sym_hash_ena_per_port;
+	uint8_t port_id;
+};
+
+static void
+cmd_get_sym_hash_per_port_parsed(void *parsed_result,
+				 __rte_unused struct cmdline *cl,
+				 __rte_unused void *data)
+{
+	struct cmd_get_sym_hash_ena_per_port_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port: %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT;
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+						RTE_ETH_FILTER_GET, &info);
+
+	if (ret < 0) {
+		printf("Cannot get symmetric hash enable per port "
+					"on port %u\n", res->port_id);
+		return;
+	}
+
+	printf("Symmetric hash is %s on port %u\n", info.info.enable ?
+				"enabled" : "disabled", res->port_id);
+}
+
+cmdline_parse_token_string_t cmd_get_sym_hash_ena_per_port_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_get_sym_hash_ena_per_port_result,
+		get_sym_hash_ena_per_port, "get_sym_hash_ena_per_port");
+cmdline_parse_token_num_t cmd_get_sym_hash_ena_per_port_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_get_sym_hash_ena_per_port_result,
+		port_id, UINT8);
+
+cmdline_parse_inst_t cmd_get_sym_hash_ena_per_port = {
+	.f = cmd_get_sym_hash_per_port_parsed,
+	.data = NULL,
+	.help_str = "get_sym_hash_ena_per_port port_id",
+	.tokens = {
+		(void *)&cmd_get_sym_hash_ena_per_port_all,
+		(void *)&cmd_get_sym_hash_ena_per_port_port_id,
+		NULL,
+	},
+};
+
+/* *** Set symmetric hash enable per port *** */
+struct cmd_set_sym_hash_ena_per_port_result {
+	cmdline_fixed_string_t set_sym_hash_ena_per_port;
+	cmdline_fixed_string_t enable;
+	uint8_t port_id;
+};
+
+static void
+cmd_set_sym_hash_per_port_parsed(void *parsed_result,
+				 __rte_unused struct cmdline *cl,
+				 __rte_unused void *data)
+{
+	struct cmd_set_sym_hash_ena_per_port_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port: %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT;
+	if (!strcmp(res->enable, "enable"))
+		info.info.enable = 1;
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+					RTE_ETH_FILTER_SET, &info);
+	if (ret < 0) {
+		printf("Cannot set symmetric hash enable per port on "
+					"port %u\n", res->port_id);
+		return;
+	}
+	printf("Symmetric hash has been set to %s on port %u\n",
+					res->enable, res->port_id);
+}
+
+cmdline_parse_token_string_t cmd_set_sym_hash_ena_per_port_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_sym_hash_ena_per_port_result,
+		set_sym_hash_ena_per_port, "set_sym_hash_ena_per_port");
+cmdline_parse_token_num_t cmd_set_sym_hash_ena_per_port_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_sym_hash_ena_per_port_result,
+		port_id, UINT8);
+cmdline_parse_token_string_t cmd_set_sym_hash_ena_per_port_enable =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_sym_hash_ena_per_port_result,
+		enable, "enable#disable");
+
+cmdline_parse_inst_t cmd_set_sym_hash_ena_per_port = {
+	.f = cmd_set_sym_hash_per_port_parsed,
+	.data = NULL,
+	.help_str = "set_sym_hash_ena_per_port port_id enable|disable",
+	.tokens = {
+		(void *)&cmd_set_sym_hash_ena_per_port_all,
+		(void *)&cmd_set_sym_hash_ena_per_port_port_id,
+		(void *)&cmd_set_sym_hash_ena_per_port_enable,
+		NULL,
+	},
+};
+
+/* Get global config of hash function */
+struct cmd_get_hash_global_config_result {
+	cmdline_fixed_string_t get_hash_global_config;
+	uint8_t port_id;
+};
+
+static char *
+flowtype_to_str(enum rte_eth_flow_type ftype)
+{
+	uint16_t i;
+	static struct {
+		char str[16];
+		enum rte_eth_flow_type ftype;
+	} ftype_table[] = {
+		{"ip4", RTE_ETH_FLOW_TYPE_IPV4_OTHER},
+		{"ip4-frag", RTE_ETH_FLOW_TYPE_FRAG_IPV4},
+		{"udp4", RTE_ETH_FLOW_TYPE_UDPV4},
+		{"tcp4", RTE_ETH_FLOW_TYPE_TCPV4},
+		{"sctp4", RTE_ETH_FLOW_TYPE_SCTPV4},
+		{"ip6", RTE_ETH_FLOW_TYPE_IPV6_OTHER},
+		{"ip6-frag", RTE_ETH_FLOW_TYPE_FRAG_IPV6},
+		{"udp6", RTE_ETH_FLOW_TYPE_UDPV6},
+		{"tcp6", RTE_ETH_FLOW_TYPE_TCPV6},
+		{"sctp6", RTE_ETH_FLOW_TYPE_TCPV6},
+	};
+
+	for (i = 0; i < RTE_DIM(ftype_table); i++) {
+		if (ftype_table[i].ftype == ftype)
+			return ftype_table[i].str;
+	}
+
+	return NULL;
+}
+
+static void
+cmd_get_hash_global_config_parsed(void *parsed_result,
+				  __rte_unused struct cmdline *cl,
+				  __rte_unused void *data)
+{
+	struct cmd_get_hash_global_config_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	uint32_t idx, offset, i;
+	char *str;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+			RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_GLOBAL_CONFIG;
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+					RTE_ETH_FILTER_GET, &info);
+	if (ret < 0) {
+		printf("Cannot get hash global configurations by port %d\n",
+							res->port_id);
+		return;
+	}
+
+	switch (info.info.global_conf.hash_func) {
+	case RTE_ETH_HASH_FUNCTION_TOEPLITZ:
+		printf("Hash function is Toeplitz\n");
+		break;
+	case RTE_ETH_HASH_FUNCTION_SIMPLE_XOR:
+		printf("Hash function is Simple XOR\n");
+		break;
+	default:
+		printf("Unknown hash function\n");
+		break;
+	}
+
+	for (i = 0; i < RTE_ETH_FLOW_TYPE_MAX; i++) {
+		idx = i / UINT32_BIT;
+		offset = i % UINT32_BIT;
+		if (!(info.info.global_conf.valid_bit_mask[idx] &
+						(1UL << offset)))
+			continue;
+		str = flowtype_to_str((enum rte_eth_flow_type)i);
+		if (!str)
+			continue;
+		printf("Symmetric hash is %s globally for flow type %s "
+							"by port %d\n",
+			((info.info.global_conf.sym_hash_enable_mask[idx] &
+			(1UL << offset)) ? "enabled" : "disabled"), str,
+							res->port_id);
+	}
+}
+
+cmdline_parse_token_string_t cmd_get_hash_global_config_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_get_hash_global_config_result,
+		get_hash_global_config, "get_hash_global_config");
+cmdline_parse_token_num_t cmd_get_hash_global_config_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_get_hash_global_config_result,
+		port_id, UINT8);
+
+cmdline_parse_inst_t cmd_get_hash_global_config = {
+	.f = cmd_get_hash_global_config_parsed,
+	.data = NULL,
+	.help_str = "get_hash_global_config port_id",
+	.tokens = {
+		(void *)&cmd_get_hash_global_config_all,
+		(void *)&cmd_get_hash_global_config_port_id,
+		NULL,
+	},
+};
+
+/* Set global config of hash function */
+struct cmd_set_hash_global_config_result {
+	cmdline_fixed_string_t set_hash_global_config;
+	uint8_t port_id;
+	cmdline_fixed_string_t hash_func;
+	cmdline_fixed_string_t flow_type;
+	cmdline_fixed_string_t enable;
+};
+
+static void
+cmd_set_hash_global_config_parsed(void *parsed_result,
+				  __rte_unused struct cmdline *cl,
+				  __rte_unused void *data)
+{
+	struct cmd_set_hash_global_config_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	uint32_t ftype, idx, offset;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port %d\n",
+							res->port_id);
+		return;
+	}
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_GLOBAL_CONFIG;
+	if (!strcmp(res->hash_func, "toeplitz"))
+		info.info.global_conf.hash_func =
+			RTE_ETH_HASH_FUNCTION_TOEPLITZ;
+	else if (!strcmp(res->hash_func, "simple_xor"))
+		info.info.global_conf.hash_func =
+			RTE_ETH_HASH_FUNCTION_SIMPLE_XOR;
+	else if (!strcmp(res->hash_func, "default"))
+		info.info.global_conf.hash_func =
+			RTE_ETH_HASH_FUNCTION_DEFAULT;
+
+	ftype = str2flowtype(res->flow_type);
+	idx = ftype / (CHAR_BIT * sizeof(uint32_t));
+	offset = ftype % (CHAR_BIT * sizeof(uint32_t));
+	info.info.global_conf.valid_bit_mask[idx] |= (1UL << offset);
+	if (!strcmp(res->enable, "enable"))
+		info.info.global_conf.sym_hash_enable_mask[idx] |=
+						(1UL << offset);
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+					RTE_ETH_FILTER_SET, &info);
+	if (ret < 0)
+		printf("Cannot set global hash configurations by port %d\n",
+							res->port_id);
+	else
+		printf("Global hash configurations have been set "
+			"succcessfully by port %d\n", res->port_id);
+}
+
+cmdline_parse_token_string_t cmd_set_hash_global_config_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_hash_global_config_result,
+		set_hash_global_config, "set_hash_global_config");
+cmdline_parse_token_num_t cmd_set_hash_global_config_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_hash_global_config_result,
+		port_id, UINT8);
+cmdline_parse_token_string_t cmd_set_hash_global_config_hash_func =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_hash_global_config_result,
+		hash_func, "toeplitz#simple_xor#default");
+cmdline_parse_token_string_t cmd_set_hash_global_config_flow_type =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_hash_global_config_result,
+		flow_type,
+		"ip4#ip4-frag#tcp4#udp4#sctp4#ip6#ip6-frag#tcp6#udp6#sctp6");
+cmdline_parse_token_string_t cmd_set_hash_global_config_enable =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_hash_global_config_result,
+		enable, "enable#disable");
+
+cmdline_parse_inst_t cmd_set_hash_global_config = {
+	.f = cmd_set_hash_global_config_parsed,
+	.data = NULL,
+	.help_str = "set_hash_global_config port_id "
+		"toeplitz|simple_xor|default "
+		"ip4|ip4-frag|tcp4|udp4|#sctp4|ip6|ip6-frag|tcp6|udp6|sctp6 "
+		"enable|disable",
+	.tokens = {
+		(void *)&cmd_set_hash_global_config_all,
+		(void *)&cmd_set_hash_global_config_port_id,
+		(void *)&cmd_set_hash_global_config_hash_func,
+		(void *)&cmd_set_hash_global_config_flow_type,
+		(void *)&cmd_set_hash_global_config_enable,
+		NULL,
+	},
+};
+
 /* ******************************************************************************** */
 
 /* list of instructions */
@@ -8836,6 +9165,10 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_flush_flow_director,
 	(cmdline_parse_inst_t *)&cmd_set_flow_director_flex_mask,
 	(cmdline_parse_inst_t *)&cmd_set_flow_director_flex_payload,
+	(cmdline_parse_inst_t *)&cmd_get_sym_hash_ena_per_port,
+	(cmdline_parse_inst_t *)&cmd_set_sym_hash_ena_per_port,
+	(cmdline_parse_inst_t *)&cmd_get_hash_global_config,
+	(cmdline_parse_inst_t *)&cmd_set_hash_global_config,
 	NULL,
 };
 
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [dpdk-dev] [PATCH v8 0/4] Support configuring hash functions
  2014-12-02  2:19           ` [dpdk-dev] [PATCH v8 0/4] Support configuring " Helin Zhang
                               ` (3 preceding siblings ...)
  2014-12-02  2:19             ` [dpdk-dev] [PATCH v8 4/4] app/testpmd: add commands to support " Helin Zhang
@ 2014-12-02 13:15             ` Ananyev, Konstantin
  2015-01-22  7:36             ` [dpdk-dev] [PATCH v9 0/5] " Helin Zhang
  5 siblings, 0 replies; 71+ messages in thread
From: Ananyev, Konstantin @ 2014-12-02 13:15 UTC (permalink / raw)
  To: Zhang, Helin, dev



> -----Original Message-----
> From: Zhang, Helin
> Sent: Tuesday, December 02, 2014 2:19 AM
> To: dev@dpdk.org
> Cc: Cao, Waterman; Cao, Min; Ananyev, Konstantin; Zhang, Helin
> Subject: [PATCH v8 0/4] Support configuring hash functions
> 
> These patches mainly support configuring hash functions. In detail,
>  - It can get/set global hash configurations.
>   * Get/set symmetric hash enable per flow type.
>   * Get/set hash function type.
>  - It can get/set symmetric hash enable per port.
>  - Four commands have been implemented in testpmd to support testing above.
>    * get_sym_hash_ena_per_port
>    * set_sym_hash_ena_per_port
>    * get_hash_global_config
>    * set_hash_global_config
> 
> It also uses constant hash keys to replace runtime generating hash keys.
> Global initialization is added to correctly put registers to an initial state.
> 
> v3 changes:
> * Removed renamings in rte_ethdev.h.
> * Redesigned filter control API and its relevant structures/enums.
> * Renamed header file from rte_eth_features.h to rte_eth_ctrol.h.
> * Remove public header file of rte_i40e.h specific for i40e.
> * Added hardware initialization function during port init.
> * Used constant random hash keys in i40e PF.
> * renamed the commands in testpmd based on the redesigned filter control API.
> 
> v4 changes:
> * Fixed a bug in testpmd to support 'set_sym_hash_ena_per_port'.
> 
> v5 changes:
> * Integrated with filter API defined recently.
> * Remove all for filter API definition, as it has already defined and merged
>   recently.
> 
> v6 changes:
> * Flow type strings are used to replace Packet Classification Types, to isolate
>   hardware specific things.
> * Implemented the mapping function to convert RSS offload types to Packet
>   Classification Types, to isolate the real hardware specific things.
> * Removed initialization of global registers in i40e PMD, as global registers
>   shouldn't be initialized per port.
> * Added more annotations to get code more understandable.
> * Corrected annotation format for documenation.
> 
> v7 changes:
> * Removed swap configurations, as it is not allowed by hardware design.
> * Put symmetric hash per flow type and hash function type into
>   'RTE_ETH_HASH_FILTER_GLOBAL_CONFIG', as they are controlling global registers
>   which will affects all the ports of the same NIC.
> 
> v8 changes:
> * Removed redundant checks in i40e_ethdev.c.
> * Solved compile errors on ICC.
> 
> Helin Zhang (4):
>   ethdev: code style fixes
>   i40e: use constant as the default hash keys
>   i40e: support of controlling hash functions
>   app/testpmd: add commands to support hash functions
> 
>  app/test-pmd/cmdline.c            | 333 ++++++++++++++++++++++++++++++++++++++
>  lib/librte_ether/rte_eth_ctrl.h   |  72 ++++++++-
>  lib/librte_pmd_i40e/i40e_ethdev.c | 308 +++++++++++++++++++++++++++++++++--
>  3 files changed, 699 insertions(+), 14 deletions(-)
> 
> --
> 1.8.1.4

Acked-by: Konstantin Ananyev <konstantin.ananyev@intel.com>

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [dpdk-dev] [PATCH v8 3/4] i40e: support of controlling hash functions
  2014-12-02  2:19             ` [dpdk-dev] [PATCH v8 3/4] i40e: support of controlling hash functions Helin Zhang
@ 2015-01-20  7:54               ` Thomas Monjalon
  2015-01-21  0:13                 ` Zhang, Helin
  2015-01-22  7:44                 ` Zhang, Helin
  0 siblings, 2 replies; 71+ messages in thread
From: Thomas Monjalon @ 2015-01-20  7:54 UTC (permalink / raw)
  To: Helin Zhang; +Cc: dev

Hi Helin,

2014-12-02 10:19, Helin Zhang:
> Hash filter control has been implemented for i40e. It includes
> getting/setting,
> - global hash configurations (hash function type, and symmetric
>   hash enable per flow type)
> - symmetric hash enable per port
> 
> Signed-off-by: Helin Zhang <helin.zhang@intel.com>
> ---
>  lib/librte_ether/rte_eth_ctrl.h   |  63 ++++++++
>  lib/librte_pmd_i40e/i40e_ethdev.c | 294 +++++++++++++++++++++++++++++++++++++-
>  2 files changed, 355 insertions(+), 2 deletions(-)

Please, could you split ethdev and i40e parts while keeping Konstantin's ack?

[...]
> + * Each bit in valid_bit_mask[] indicates if the coresponding bit in

Typo: corresponding

[...]
> +	/** Bit mask indicates if the coresponding bit is valid */

Same typo

[...]
> +	/** Details of hash filter infomation */

Typo: information

> +	union {
> +		/* For RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT */
> +		uint8_t enable;
> +		/* Global configurations of hash filter */
> +		struct rte_eth_hash_global_conf global_conf;
> +	} info;

Why these comments are not doxygen'ed?

Sorry for nitpicking, that's the last review pass ;)
-- 
Thomas

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [dpdk-dev] [PATCH v8 3/4] i40e: support of controlling hash functions
  2015-01-20  7:54               ` Thomas Monjalon
@ 2015-01-21  0:13                 ` Zhang, Helin
  2015-01-22  7:44                 ` Zhang, Helin
  1 sibling, 0 replies; 71+ messages in thread
From: Zhang, Helin @ 2015-01-21  0:13 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev

Hi Thomas

Sure, I will do it ASAP! Thank you for the helps!

Regards,
Helin

> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Tuesday, January 20, 2015 3:54 PM
> To: Zhang, Helin
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v8 3/4] i40e: support of controlling hash
> functions
> 
> Hi Helin,
> 
> 2014-12-02 10:19, Helin Zhang:
> > Hash filter control has been implemented for i40e. It includes
> > getting/setting,
> > - global hash configurations (hash function type, and symmetric
> >   hash enable per flow type)
> > - symmetric hash enable per port
> >
> > Signed-off-by: Helin Zhang <helin.zhang@intel.com>
> > ---
> >  lib/librte_ether/rte_eth_ctrl.h   |  63 ++++++++
> >  lib/librte_pmd_i40e/i40e_ethdev.c | 294
> > +++++++++++++++++++++++++++++++++++++-
> >  2 files changed, 355 insertions(+), 2 deletions(-)
> 
> Please, could you split ethdev and i40e parts while keeping Konstantin's ack?
> 
> [...]
> > + * Each bit in valid_bit_mask[] indicates if the coresponding bit in
> 
> Typo: corresponding
> 
> [...]
> > +	/** Bit mask indicates if the coresponding bit is valid */
> 
> Same typo
> 
> [...]
> > +	/** Details of hash filter infomation */
> 
> Typo: information
> 
> > +	union {
> > +		/* For RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT */
> > +		uint8_t enable;
> > +		/* Global configurations of hash filter */
> > +		struct rte_eth_hash_global_conf global_conf;
> > +	} info;
> 
> Why these comments are not doxygen'ed?
> 
> Sorry for nitpicking, that's the last review pass ;)
> --
> Thomas

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v9 0/5] Support configuring hash functions
  2014-12-02  2:19           ` [dpdk-dev] [PATCH v8 0/4] Support configuring " Helin Zhang
                               ` (4 preceding siblings ...)
  2014-12-02 13:15             ` [dpdk-dev] [PATCH v8 0/4] Support configuring " Ananyev, Konstantin
@ 2015-01-22  7:36             ` Helin Zhang
  2015-01-22  7:36               ` [dpdk-dev] [PATCH v9 1/5] i40e: use constant as the default hash keys Helin Zhang
                                 ` (4 more replies)
  5 siblings, 5 replies; 71+ messages in thread
From: Helin Zhang @ 2015-01-22  7:36 UTC (permalink / raw)
  To: dev

These patches mainly support configuring hash functions. In detail,
 - It can get/set global hash configurations.
  * Get/set symmetric hash enable per flow type.
  * Get/set hash function type.
 - It can get/set symmetric hash enable per port.
 - Four commands have been implemented in testpmd to support testing above.
   * get_sym_hash_ena_per_port
   * set_sym_hash_ena_per_port
   * get_hash_global_config
   * set_hash_global_config

It also uses constant hash keys to replace runtime generating hash keys.
Global initialization is added to correctly put registers to an initial state.

v3 changes:
* Removed renamings in rte_ethdev.h.
* Redesigned filter control API and its relevant structures/enums.
* Renamed header file from rte_eth_features.h to rte_eth_ctrol.h.
* Remove public header file of rte_i40e.h specific for i40e.
* Added hardware initialization function during port init.
* Used constant random hash keys in i40e PF.
* renamed the commands in testpmd based on the redesigned filter control API.

v4 changes:
* Fixed a bug in testpmd to support 'set_sym_hash_ena_per_port'.

v5 changes:
* Integrated with filter API defined recently.
* Remove all for filter API definition, as it has already defined and merged
  recently.

v6 changes:
* Flow type strings are used to replace Packet Classification Types, to isolate
  hardware specific things.
* Implemented the mapping function to convert RSS offload types to Packet
  Classification Types, to isolate the real hardware specific things.
* Removed initialization of global registers in i40e PMD, as global registers
  shouldn't be initialized per port.
* Added more annotations to get code more understandable.
* Corrected annotation format for documenation.

v7 changes:
* Removed swap configurations, as it is not allowed by hardware design.
* Put symmetric hash per flow type and hash function type into
  'RTE_ETH_HASH_FILTER_GLOBAL_CONFIG', as they are controlling global registers
  which will affects all the ports of the same NIC.

v8 changes:
* Removed redundant checks in i40e_ethdev.c.
* Solved compile errors on ICC.

v9 changes:
* Added typo fixes in rte_eth_ctrl.h.
* Splitted modifications in both rte_eth_ctrl.h and i40e, one patch is for ethdev,
  the other one is for i40e.

Helin Zhang (5):
  i40e: use constant as the default hash keys
  ethdev: code style fixes
  ethdev: support of configuring hash functions
  i40e: support of controlling hash functions
  app/testpmd: add commands to support hash functions

 app/test-pmd/cmdline.c            | 333 ++++++++++++++++++++++++++++++++++++++
 lib/librte_ether/rte_eth_ctrl.h   |  72 ++++++++-
 lib/librte_pmd_i40e/i40e_ethdev.c | 308 +++++++++++++++++++++++++++++++++--
 3 files changed, 699 insertions(+), 14 deletions(-)

-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v9 1/5] i40e: use constant as the default hash keys
  2015-01-22  7:36             ` [dpdk-dev] [PATCH v9 0/5] " Helin Zhang
@ 2015-01-22  7:36               ` Helin Zhang
  2015-01-22  7:36               ` [dpdk-dev] [PATCH v9 2/5] ethdev: code style fixes Helin Zhang
                                 ` (3 subsequent siblings)
  4 siblings, 0 replies; 71+ messages in thread
From: Helin Zhang @ 2015-01-22  7:36 UTC (permalink / raw)
  To: dev

Calculating the default RSS hash keys at run time is not needed
at all, and may have race conditions. The alternative is to use
array of random values which were generated manually as the
default hash keys.

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
---
 lib/librte_pmd_i40e/i40e_ethdev.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/lib/librte_pmd_i40e/i40e_ethdev.c b/lib/librte_pmd_i40e/i40e_ethdev.c
index b47a3d2..48bc34d 100644
--- a/lib/librte_pmd_i40e/i40e_ethdev.c
+++ b/lib/librte_pmd_i40e/i40e_ethdev.c
@@ -73,7 +73,7 @@
 /* Maximun number of VSI */
 #define I40E_MAX_NUM_VSIS          (384UL)
 
-/* Default queue interrupt throttling time in microseconds*/
+/* Default queue interrupt throttling time in microseconds */
 #define I40E_ITR_INDEX_DEFAULT          0
 #define I40E_QUEUE_ITR_INTERVAL_DEFAULT 32 /* 32 us */
 #define I40E_QUEUE_ITR_INTERVAL_MAX     8160 /* 8160 us */
@@ -200,9 +200,6 @@ static int i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
 				void *arg);
 static void i40e_configure_registers(struct i40e_hw *hw);
 
-/* Default hash key buffer for RSS */
-static uint32_t rss_key_default[I40E_PFQF_HKEY_MAX_INDEX + 1];
-
 static struct rte_pci_id pci_id_i40e_map[] = {
 #define RTE_PCI_DEV_ID_DECL_I40E(vend, dev) {RTE_PCI_DEVICE(vend, dev)},
 #include "rte_pci_dev_ids.h"
@@ -5039,9 +5036,12 @@ i40e_pf_config_rss(struct i40e_pf *pf)
 	}
 	if (rss_conf.rss_key == NULL || rss_conf.rss_key_len <
 		(I40E_PFQF_HKEY_MAX_INDEX + 1) * sizeof(uint32_t)) {
-		/* Calculate the default hash key */
-		for (i = 0; i <= I40E_PFQF_HKEY_MAX_INDEX; i++)
-			rss_key_default[i] = (uint32_t)rte_rand();
+		/* Random default keys */
+		static uint32_t rss_key_default[] = {0x6b793944,
+			0x23504cb5, 0x5bea75b6, 0x309f4f12, 0x3dc0a2b8,
+			0x024ddcdf, 0x339b8ca0, 0x4c4af64a, 0x34fac605,
+			0x55d85839, 0x3a58997d, 0x2ec938e1, 0x66031581};
+
 		rss_conf.rss_key = (uint8_t *)rss_key_default;
 		rss_conf.rss_key_len = (I40E_PFQF_HKEY_MAX_INDEX + 1) *
 							sizeof(uint32_t);
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v9 2/5] ethdev: code style fixes
  2015-01-22  7:36             ` [dpdk-dev] [PATCH v9 0/5] " Helin Zhang
  2015-01-22  7:36               ` [dpdk-dev] [PATCH v9 1/5] i40e: use constant as the default hash keys Helin Zhang
@ 2015-01-22  7:36               ` Helin Zhang
  2015-01-22  7:36               ` [dpdk-dev] [PATCH v9 3/5] ethdev: support of configuring hash functions Helin Zhang
                                 ` (2 subsequent siblings)
  4 siblings, 0 replies; 71+ messages in thread
From: Helin Zhang @ 2015-01-22  7:36 UTC (permalink / raw)
  To: dev

Added code style fixes.

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
---
 lib/librte_ether/rte_eth_ctrl.h | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/lib/librte_ether/rte_eth_ctrl.h b/lib/librte_ether/rte_eth_ctrl.h
index 5d9c387..4b3c5fc 100644
--- a/lib/librte_ether/rte_eth_ctrl.h
+++ b/lib/librte_ether/rte_eth_ctrl.h
@@ -62,8 +62,8 @@ enum rte_filter_type {
  * Generic operations on filters
  */
 enum rte_filter_op {
+	/** used to check whether the type filter is supported */
 	RTE_ETH_FILTER_NOP = 0,
-	/**< used to check whether the type filter is supported */
 	RTE_ETH_FILTER_ADD,      /**< add filter entry */
 	RTE_ETH_FILTER_UPDATE,   /**< update filter entry */
 	RTE_ETH_FILTER_DELETE,   /**< delete filter entry */
@@ -75,16 +75,15 @@ enum rte_filter_op {
 	RTE_ETH_FILTER_OP_MAX
 };
 
-/**
+/*
  * MAC filter type
  */
 enum rte_mac_filter_type {
 	RTE_MAC_PERFECT_MATCH = 1, /**< exact match of MAC addr. */
-	RTE_MACVLAN_PERFECT_MATCH,
-	/**< exact match of MAC addr and VLAN ID. */
+	RTE_MACVLAN_PERFECT_MATCH, /**< exact match of MAC addr and VLAN ID. */
 	RTE_MAC_HASH_MATCH, /**< hash match of MAC addr. */
+	/** hash match of MAC addr and exact match of VLAN ID. */
 	RTE_MACVLAN_HASH_MATCH,
-	/**< hash match of MAC addr and exact match of VLAN ID. */
 };
 
 /**
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v9 3/5] ethdev: support of configuring hash functions
  2015-01-22  7:36             ` [dpdk-dev] [PATCH v9 0/5] " Helin Zhang
  2015-01-22  7:36               ` [dpdk-dev] [PATCH v9 1/5] i40e: use constant as the default hash keys Helin Zhang
  2015-01-22  7:36               ` [dpdk-dev] [PATCH v9 2/5] ethdev: code style fixes Helin Zhang
@ 2015-01-22  7:36               ` Helin Zhang
  2015-01-22  7:36               ` [dpdk-dev] [PATCH v9 4/5] i40e: support of controlling " Helin Zhang
  2015-01-22  7:36               ` [dpdk-dev] [PATCH v9 5/5] app/testpmd: add commands to support " Helin Zhang
  4 siblings, 0 replies; 71+ messages in thread
From: Helin Zhang @ 2015-01-22  7:36 UTC (permalink / raw)
  To: dev

In order to support hash filter configuration, filter type of hash
is added, also the corresponding structures, macros and definitions
are added.

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
---
 lib/librte_ether/rte_eth_ctrl.h | 63 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 63 insertions(+)

v9 changes:
* Added typo fixes.
* Splitted the patch, one is for ethdev only.

diff --git a/lib/librte_ether/rte_eth_ctrl.h b/lib/librte_ether/rte_eth_ctrl.h
index 4b3c5fc..0ce241e 100644
--- a/lib/librte_ether/rte_eth_ctrl.h
+++ b/lib/librte_ether/rte_eth_ctrl.h
@@ -55,6 +55,7 @@ enum rte_filter_type {
 	RTE_ETH_FILTER_ETHERTYPE,
 	RTE_ETH_FILTER_TUNNEL,
 	RTE_ETH_FILTER_FDIR,
+	RTE_ETH_FILTER_HASH,
 	RTE_ETH_FILTER_MAX
 };
 
@@ -449,6 +450,68 @@ struct rte_eth_fdir_stats {
 	uint32_t best_cnt;     /**< Number of filters in best effort spaces. */
 };
 
+/**
+ * Hash filter information types.
+ * - RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT is for getting/setting the
+ *   information/configuration of 'symmetric hash enable' per port.
+ * - RTE_ETH_HASH_FILTER_GLOBAL_CONFIG is for getting/setting the global
+ *   configurations of hash filters. Those global configurations are valid
+ *   for all ports of the same NIC.
+ */
+enum rte_eth_hash_filter_info_type {
+	RTE_ETH_HASH_FILTER_INFO_TYPE_UNKNOWN = 0,
+	/** Symmetric hash enable per port */
+	RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT,
+	/** Configure globally for hash filter */
+	RTE_ETH_HASH_FILTER_GLOBAL_CONFIG,
+	RTE_ETH_HASH_FILTER_INFO_TYPE_MAX,
+};
+
+/**
+ * Hash function types.
+ */
+enum rte_eth_hash_function {
+	RTE_ETH_HASH_FUNCTION_DEFAULT = 0,
+	RTE_ETH_HASH_FUNCTION_TOEPLITZ, /**< Toeplitz */
+	RTE_ETH_HASH_FUNCTION_SIMPLE_XOR, /**< Simple XOR */
+	RTE_ETH_HASH_FUNCTION_MAX,
+};
+
+#define UINT32_BIT (CHAR_BIT * sizeof(uint32_t))
+#define RTE_SYM_HASH_MASK_ARRAY_SIZE \
+	(RTE_ALIGN(RTE_ETH_FLOW_TYPE_MAX, UINT32_BIT)/UINT32_BIT)
+/**
+ * A structure used to set or get global hash function configurations which
+ * include symmetric hash enable per flow type and hash function type.
+ * Each bit in sym_hash_enable_mask[] indicates if the symmetric hash of the
+ * coresponding flow type is enabled or not.
+ * Each bit in valid_bit_mask[] indicates if the corresponding bit in
+ * sym_hash_enable_mask[] is valid or not. For the configurations gotten, it
+ * also means if the flow type is supported by hardware or not.
+ */
+struct rte_eth_hash_global_conf {
+	enum rte_eth_hash_function hash_func; /**< Hash function type */
+	/** Bit mask for symmetric hash enable per flow type */
+	uint32_t sym_hash_enable_mask[RTE_SYM_HASH_MASK_ARRAY_SIZE];
+	/** Bit mask indicates if the corresponding bit is valid */
+	uint32_t valid_bit_mask[RTE_SYM_HASH_MASK_ARRAY_SIZE];
+};
+
+/**
+ * A structure used to set or get hash filter information, to support filter
+ * type of 'RTE_ETH_FILTER_HASH' and its operations.
+ */
+struct rte_eth_hash_filter_info {
+	enum rte_eth_hash_filter_info_type info_type; /**< Information type */
+	/** Details of hash filter information */
+	union {
+		/** For RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT */
+		uint8_t enable;
+		/** Global configurations of hash filter */
+		struct rte_eth_hash_global_conf global_conf;
+	} info;
+};
+
 #ifdef __cplusplus
 }
 #endif
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v9 4/5] i40e: support of controlling hash functions
  2015-01-22  7:36             ` [dpdk-dev] [PATCH v9 0/5] " Helin Zhang
                                 ` (2 preceding siblings ...)
  2015-01-22  7:36               ` [dpdk-dev] [PATCH v9 3/5] ethdev: support of configuring hash functions Helin Zhang
@ 2015-01-22  7:36               ` Helin Zhang
  2015-01-22  7:36               ` [dpdk-dev] [PATCH v9 5/5] app/testpmd: add commands to support " Helin Zhang
  4 siblings, 0 replies; 71+ messages in thread
From: Helin Zhang @ 2015-01-22  7:36 UTC (permalink / raw)
  To: dev

Hash filter control has been implemented for i40e. It includes
getting/setting,
- global hash configurations (hash function type, and symmetric
  hash enable per flow type)
- symmetric hash enable per port

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
---
 lib/librte_pmd_i40e/i40e_ethdev.c | 294 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 292 insertions(+), 2 deletions(-)

v5 changes:
* Integrated with filter API defined recently.

v6 changes:
* Implemented the mapping function to convert RSS offload types to Packet
  Classification Types, to isolate the real hardware specific things.
* Removed initialization of global registers in i40e PMD, as global registers
  shouldn't be initialized per port.
* Added more annotations to get code more understandable.
* Corrected annotation format for documenation.

v7 changes:
* Removed swap configurations, as it is not allowed by hardware design.
* Put symmetric hash per flow type and hash function type into
  'RTE_ETH_HASH_FILTER_GLOBAL_CONFIG', as they are controlling global registers
  which will affects all the ports of the same NIC.

v8 changes:
* Removed redundant return value checks of i40e_flowtype_to_pctype(), as it
  should always be correct.
* Fixed the compile issue on ICC, of "error #188: enumerated type mixed with
  another type".

v9 changes:
* Splitted the patch, one is for i40e only.

diff --git a/lib/librte_pmd_i40e/i40e_ethdev.c b/lib/librte_pmd_i40e/i40e_ethdev.c
index 48bc34d..9fa6bec 100644
--- a/lib/librte_pmd_i40e/i40e_ethdev.c
+++ b/lib/librte_pmd_i40e/i40e_ethdev.c
@@ -93,6 +93,18 @@
 		I40E_PFINT_ICR0_ENA_VFLR_MASK | \
 		I40E_PFINT_ICR0_ENA_ADMINQ_MASK)
 
+#define I40E_FLOW_TYPES ( \
+	(1UL << RTE_ETH_FLOW_TYPE_UDPV4) | \
+	(1UL << RTE_ETH_FLOW_TYPE_TCPV4) | \
+	(1UL << RTE_ETH_FLOW_TYPE_SCTPV4) | \
+	(1UL << RTE_ETH_FLOW_TYPE_IPV4_OTHER) | \
+	(1UL << RTE_ETH_FLOW_TYPE_FRAG_IPV4) | \
+	(1UL << RTE_ETH_FLOW_TYPE_UDPV6) | \
+	(1UL << RTE_ETH_FLOW_TYPE_TCPV6) | \
+	(1UL << RTE_ETH_FLOW_TYPE_SCTPV6) | \
+	(1UL << RTE_ETH_FLOW_TYPE_IPV6_OTHER) | \
+	(1UL << RTE_ETH_FLOW_TYPE_FRAG_IPV6))
+
 static int eth_i40e_dev_init(\
 			__attribute__((unused)) struct eth_driver *eth_drv,
 			struct rte_eth_dev *eth_dev);
@@ -199,6 +211,7 @@ static int i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
 				enum rte_filter_op filter_op,
 				void *arg);
 static void i40e_configure_registers(struct i40e_hw *hw);
+static void i40e_hw_init(struct i40e_hw *hw);
 
 static struct rte_pci_id pci_id_i40e_map[] = {
 #define RTE_PCI_DEV_ID_DECL_I40E(vend, dev) {RTE_PCI_DEVICE(vend, dev)},
@@ -398,6 +411,9 @@ eth_i40e_dev_init(__rte_unused struct eth_driver *eth_drv,
 	/* Make sure all is clean before doing PF reset */
 	i40e_clear_hw(hw);
 
+	/* Initialize the hardware */
+	i40e_hw_init(hw);
+
 	/* Reset here to make sure all is clean for each PF */
 	ret = i40e_pf_reset(hw);
 	if (ret) {
@@ -5136,6 +5152,260 @@ i40e_pf_config_mq_rx(struct i40e_pf *pf)
 	return ret;
 }
 
+/* Get the symmetric hash enable configurations per port */
+static void
+i40e_get_symmetric_hash_enable_per_port(struct i40e_hw *hw, uint8_t *enable)
+{
+	uint32_t reg = I40E_READ_REG(hw, I40E_PRTQF_CTL_0);
+
+	*enable = reg & I40E_PRTQF_CTL_0_HSYM_ENA_MASK ? 1 : 0;
+}
+
+/* Set the symmetric hash enable configurations per port */
+static void
+i40e_set_symmetric_hash_enable_per_port(struct i40e_hw *hw, uint8_t enable)
+{
+	uint32_t reg = I40E_READ_REG(hw, I40E_PRTQF_CTL_0);
+
+	if (enable > 0) {
+		if (reg & I40E_PRTQF_CTL_0_HSYM_ENA_MASK) {
+			PMD_DRV_LOG(INFO, "Symmetric hash has already "
+							"been enabled");
+			return;
+		}
+		reg |= I40E_PRTQF_CTL_0_HSYM_ENA_MASK;
+	} else {
+		if (!(reg & I40E_PRTQF_CTL_0_HSYM_ENA_MASK)) {
+			PMD_DRV_LOG(INFO, "Symmetric hash has already "
+							"been disabled");
+			return;
+		}
+		reg &= ~I40E_PRTQF_CTL_0_HSYM_ENA_MASK;
+	}
+	I40E_WRITE_REG(hw, I40E_PRTQF_CTL_0, reg);
+	I40E_WRITE_FLUSH(hw);
+}
+
+/*
+ * Get global configurations of hash function type and symmetric hash enable
+ * per flow type (pctype). Note that global configuration means it affects all
+ * the ports on the same NIC.
+ */
+static int
+i40e_get_hash_filter_global_config(struct i40e_hw *hw,
+				   struct rte_eth_hash_global_conf *g_cfg)
+{
+	uint32_t reg, mask = I40E_FLOW_TYPES;
+	uint32_t i;
+	enum i40e_filter_pctype pctype;
+
+	memset(g_cfg, 0, sizeof(*g_cfg));
+	reg = I40E_READ_REG(hw, I40E_GLQF_CTL);
+	if (reg & I40E_GLQF_CTL_HTOEP_MASK)
+		g_cfg->hash_func = RTE_ETH_HASH_FUNCTION_TOEPLITZ;
+	else
+		g_cfg->hash_func = RTE_ETH_HASH_FUNCTION_SIMPLE_XOR;
+	PMD_DRV_LOG(DEBUG, "Hash function is %s",
+		(reg & I40E_GLQF_CTL_HTOEP_MASK) ? "Toeplitz" : "Simple XOR");
+
+	for (i = 0; mask && i < RTE_ETH_FLOW_TYPE_MAX; i++) {
+		if (!(mask & (1UL << i)))
+			continue;
+		mask &= ~(1UL << i);
+		/* Bit set indicats the coresponding flow type is supported */
+		g_cfg->valid_bit_mask[0] |= (1UL << i);
+		pctype = i40e_flowtype_to_pctype((enum rte_eth_flow_type)i);
+		reg = I40E_READ_REG(hw, I40E_GLQF_HSYM(pctype));
+		if (reg & I40E_GLQF_HSYM_SYMH_ENA_MASK)
+			g_cfg->sym_hash_enable_mask[0] |= (1UL << i);
+	}
+
+	return 0;
+}
+
+static int
+i40e_hash_global_config_check(struct rte_eth_hash_global_conf *g_cfg)
+{
+	uint32_t i;
+	uint32_t mask0, i40e_mask = I40E_FLOW_TYPES;
+
+	if (g_cfg->hash_func != RTE_ETH_HASH_FUNCTION_TOEPLITZ &&
+		g_cfg->hash_func != RTE_ETH_HASH_FUNCTION_SIMPLE_XOR &&
+		g_cfg->hash_func != RTE_ETH_HASH_FUNCTION_DEFAULT) {
+		PMD_DRV_LOG(ERR, "Unsupported hash function type %d",
+						g_cfg->hash_func);
+		return -EINVAL;
+	}
+
+	/*
+	 * As i40e supports less than 32 flow types, only first 32 bits need to
+	 * be checked.
+	 */
+	mask0 = g_cfg->valid_bit_mask[0];
+	for (i = 0; i < RTE_SYM_HASH_MASK_ARRAY_SIZE; i++) {
+		if (i == 0) {
+			/* Check if any unsupported flow type configured */
+			if ((mask0 | i40e_mask) ^ i40e_mask)
+				goto mask_err;
+		} else {
+			if (g_cfg->valid_bit_mask[i])
+				goto mask_err;
+		}
+	}
+
+	return 0;
+
+mask_err:
+	PMD_DRV_LOG(ERR, "i40e unsupported flow type bit(s) configured");
+
+	return -EINVAL;
+}
+
+/*
+ * Set global configurations of hash function type and symmetric hash enable
+ * per flow type (pctype). Note any modifying global configuration will affect
+ * all the ports on the same NIC.
+ */
+static int
+i40e_set_hash_filter_global_config(struct i40e_hw *hw,
+				   struct rte_eth_hash_global_conf *g_cfg)
+{
+	int ret;
+	uint32_t i, reg;
+	uint32_t mask0 = g_cfg->valid_bit_mask[0];
+	enum i40e_filter_pctype pctype;
+
+	/* Check the input parameters */
+	ret = i40e_hash_global_config_check(g_cfg);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; mask0 && i < UINT32_BIT; i++) {
+		if (!(mask0 & (1UL << i)))
+			continue;
+		mask0 &= ~(1UL << i);
+		pctype = i40e_flowtype_to_pctype((enum rte_eth_flow_type)i);
+		reg = (g_cfg->sym_hash_enable_mask[0] & (1UL << i)) ?
+				I40E_GLQF_HSYM_SYMH_ENA_MASK : 0;
+		I40E_WRITE_REG(hw, I40E_GLQF_HSYM(pctype), reg);
+	}
+
+	reg = I40E_READ_REG(hw, I40E_GLQF_CTL);
+	if (g_cfg->hash_func == RTE_ETH_HASH_FUNCTION_TOEPLITZ) {
+		/* Toeplitz */
+		if (reg & I40E_GLQF_CTL_HTOEP_MASK) {
+			PMD_DRV_LOG(DEBUG, "Hash function already set to "
+								"Toeplitz");
+			goto out;
+		}
+		reg |= I40E_GLQF_CTL_HTOEP_MASK;
+	} else if (g_cfg->hash_func == RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) {
+		/* Simple XOR */
+		if (!(reg & I40E_GLQF_CTL_HTOEP_MASK)) {
+			PMD_DRV_LOG(DEBUG, "Hash function already set to "
+							"Simple XOR");
+			goto out;
+		}
+		reg &= ~I40E_GLQF_CTL_HTOEP_MASK;
+	} else
+		/* Use the default, and keep it as it is */
+		goto out;
+
+	I40E_WRITE_REG(hw, I40E_GLQF_CTL, reg);
+
+out:
+	I40E_WRITE_FLUSH(hw);
+
+	return 0;
+}
+
+static int
+i40e_hash_filter_get(struct i40e_hw *hw, struct rte_eth_hash_filter_info *info)
+{
+	int ret = 0;
+
+	if (!hw || !info) {
+		PMD_DRV_LOG(ERR, "Invalid pointer");
+		return -EFAULT;
+	}
+
+	switch (info->info_type) {
+	case RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT:
+		i40e_get_symmetric_hash_enable_per_port(hw,
+					&(info->info.enable));
+		break;
+	case RTE_ETH_HASH_FILTER_GLOBAL_CONFIG:
+		ret = i40e_get_hash_filter_global_config(hw,
+				&(info->info.global_conf));
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "Hash filter info type (%d) not supported",
+							info->info_type);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static int
+i40e_hash_filter_set(struct i40e_hw *hw, struct rte_eth_hash_filter_info *info)
+{
+	int ret = 0;
+
+	if (!hw || !info) {
+		PMD_DRV_LOG(ERR, "Invalid pointer");
+		return -EFAULT;
+	}
+
+	switch (info->info_type) {
+	case RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT:
+		i40e_set_symmetric_hash_enable_per_port(hw, info->info.enable);
+		break;
+	case RTE_ETH_HASH_FILTER_GLOBAL_CONFIG:
+		ret = i40e_set_hash_filter_global_config(hw,
+				&(info->info.global_conf));
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "Hash filter info type (%d) not supported",
+							info->info_type);
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+/* Operations for hash function */
+static int
+i40e_hash_filter_ctrl(struct rte_eth_dev *dev,
+		      enum rte_filter_op filter_op,
+		      void *arg)
+{
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	int ret = 0;
+
+	switch (filter_op) {
+	case RTE_ETH_FILTER_NOP:
+		break;
+	case RTE_ETH_FILTER_GET:
+		ret = i40e_hash_filter_get(hw,
+			(struct rte_eth_hash_filter_info *)arg);
+		break;
+	case RTE_ETH_FILTER_SET:
+		ret = i40e_hash_filter_set(hw,
+			(struct rte_eth_hash_filter_info *)arg);
+		break;
+	default:
+		PMD_DRV_LOG(WARNING, "Filter operation (%d) not supported",
+								filter_op);
+		ret = -ENOTSUP;
+		break;
+	}
+
+	return ret;
+}
+
 /*
  * Configure ethertype filter, which can director packet by filtering
  * with mac address and ether_type or only ether_type
@@ -5238,6 +5508,9 @@ i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
 		return -EINVAL;
 
 	switch (filter_type) {
+	case RTE_ETH_FILTER_HASH:
+		ret = i40e_hash_filter_ctrl(dev, filter_op, arg);
+		break;
 	case RTE_ETH_FILTER_MACVLAN:
 		ret = i40e_mac_filter_handle(dev, filter_op, arg);
 		break;
@@ -5260,10 +5533,26 @@ i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
 	return ret;
 }
 
+/*
+ * As some registers wouldn't be reset unless a global hardware reset,
+ * hardware initialization is needed to put those registers into an
+ * expected initial state.
+ */
+static void
+i40e_hw_init(struct i40e_hw *hw)
+{
+	/* clear the PF Queue Filter control register */
+	I40E_WRITE_REG(hw, I40E_PFQF_CTL_0, 0);
+
+	/* Disable symmetric hash per port */
+	i40e_set_symmetric_hash_enable_per_port(hw, 0);
+}
+
 enum i40e_filter_pctype
 i40e_flowtype_to_pctype(enum rte_eth_flow_type flow_type)
 {
-	static const enum i40e_filter_pctype pctype_table[] = {
+	static const enum i40e_filter_pctype
+		pctype_table[RTE_ETH_FLOW_TYPE_MAX] = {
 		[RTE_ETH_FLOW_TYPE_UDPV4] = I40E_FILTER_PCTYPE_NONF_IPV4_UDP,
 		[RTE_ETH_FLOW_TYPE_TCPV4] = I40E_FILTER_PCTYPE_NONF_IPV4_TCP,
 		[RTE_ETH_FLOW_TYPE_SCTPV4] = I40E_FILTER_PCTYPE_NONF_IPV4_SCTP,
@@ -5286,7 +5575,8 @@ i40e_flowtype_to_pctype(enum rte_eth_flow_type flow_type)
 enum rte_eth_flow_type
 i40e_pctype_to_flowtype(enum i40e_filter_pctype pctype)
 {
-	static const enum rte_eth_flow_type flowtype_table[] = {
+	static const enum rte_eth_flow_type
+		flowtype_table[RTE_ETH_FLOW_TYPE_MAX] = {
 		[I40E_FILTER_PCTYPE_NONF_IPV4_UDP] = RTE_ETH_FLOW_TYPE_UDPV4,
 		[I40E_FILTER_PCTYPE_NONF_IPV4_TCP] = RTE_ETH_FLOW_TYPE_TCPV4,
 		[I40E_FILTER_PCTYPE_NONF_IPV4_SCTP] = RTE_ETH_FLOW_TYPE_SCTPV4,
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [dpdk-dev] [PATCH v9 5/5] app/testpmd: add commands to support hash functions
  2015-01-22  7:36             ` [dpdk-dev] [PATCH v9 0/5] " Helin Zhang
                                 ` (3 preceding siblings ...)
  2015-01-22  7:36               ` [dpdk-dev] [PATCH v9 4/5] i40e: support of controlling " Helin Zhang
@ 2015-01-22  7:36               ` Helin Zhang
       [not found]                 ` <5028514.8nkR6oWFO2@xps13>
  4 siblings, 1 reply; 71+ messages in thread
From: Helin Zhang @ 2015-01-22  7:36 UTC (permalink / raw)
  To: dev

To demonstrate the hash filter control, commands are added.
They are,
- get_sym_hash_ena_per_port
- set_sym_hash_ena_per_port
- get_hash_global_config
- set_hash_global_config

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
---
 app/test-pmd/cmdline.c | 333 +++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 333 insertions(+)

v6 changes:
* Flow type strings are used to replace Packet Classification Types, to isolate
  hardware specific things.

v7 changes:
* Removed commands of,
  get_sym_hash_ena_per_pctype
  set_sym_hash_ena_per_pctype
  get_filter_swap
  set_filter_swap
  get_hash_function
  set_hash_function.
* Added new commands of,
  get_hash_global_config
  set_hash_global_config

v8 changes:
* Fixed the compile issue on ICC, of "error #188: enumerated type mixed with
  another type".

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 4beb404..590e427 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -75,6 +75,7 @@
 #include <rte_ethdev.h>
 #include <rte_string_fns.h>
 #include <rte_devargs.h>
+#include <rte_eth_ctrl.h>
 
 #include <cmdline_rdline.h>
 #include <cmdline_parse.h>
@@ -735,6 +736,21 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"flow_director_flex_payload (port_id)"
 			" (l2|l3|l4) (config)\n"
 			"    Configure flex payload selection.\n\n"
+
+			"get_sym_hash_ena_per_port (port_id)\n"
+			"    get symmetric hash enable configuration per port.\n\n"
+
+			"set_sym_hash_ena_per_port (port_id) (enable|disable)\n"
+			"    set symmetric hash enable configuration per port"
+			" to enable or disable.\n\n"
+
+			"get_hash_global_config (port_id)\n"
+			"    Get the global configurations of hash filters.\n\n"
+
+			"set_hash_global_config (port_id) (toeplitz|simple_xor|default)"
+			" (ip4|ip4-frag|tcp4|udp4|#sctp4|ip6|ip6-frag|tcp6|udp6|sctp6)"
+			" (enable|disable)\n"
+			"    Set the global configurations of hash filters.\n\n"
 		);
 	}
 }
@@ -8670,6 +8686,319 @@ cmdline_parse_inst_t cmd_set_flow_director_flex_payload = {
 	},
 };
 
+/* *** Classification Filters Control *** */
+/* *** Get symmetric hash enable per port *** */
+struct cmd_get_sym_hash_ena_per_port_result {
+	cmdline_fixed_string_t get_sym_hash_ena_per_port;
+	uint8_t port_id;
+};
+
+static void
+cmd_get_sym_hash_per_port_parsed(void *parsed_result,
+				 __rte_unused struct cmdline *cl,
+				 __rte_unused void *data)
+{
+	struct cmd_get_sym_hash_ena_per_port_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port: %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT;
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+						RTE_ETH_FILTER_GET, &info);
+
+	if (ret < 0) {
+		printf("Cannot get symmetric hash enable per port "
+					"on port %u\n", res->port_id);
+		return;
+	}
+
+	printf("Symmetric hash is %s on port %u\n", info.info.enable ?
+				"enabled" : "disabled", res->port_id);
+}
+
+cmdline_parse_token_string_t cmd_get_sym_hash_ena_per_port_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_get_sym_hash_ena_per_port_result,
+		get_sym_hash_ena_per_port, "get_sym_hash_ena_per_port");
+cmdline_parse_token_num_t cmd_get_sym_hash_ena_per_port_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_get_sym_hash_ena_per_port_result,
+		port_id, UINT8);
+
+cmdline_parse_inst_t cmd_get_sym_hash_ena_per_port = {
+	.f = cmd_get_sym_hash_per_port_parsed,
+	.data = NULL,
+	.help_str = "get_sym_hash_ena_per_port port_id",
+	.tokens = {
+		(void *)&cmd_get_sym_hash_ena_per_port_all,
+		(void *)&cmd_get_sym_hash_ena_per_port_port_id,
+		NULL,
+	},
+};
+
+/* *** Set symmetric hash enable per port *** */
+struct cmd_set_sym_hash_ena_per_port_result {
+	cmdline_fixed_string_t set_sym_hash_ena_per_port;
+	cmdline_fixed_string_t enable;
+	uint8_t port_id;
+};
+
+static void
+cmd_set_sym_hash_per_port_parsed(void *parsed_result,
+				 __rte_unused struct cmdline *cl,
+				 __rte_unused void *data)
+{
+	struct cmd_set_sym_hash_ena_per_port_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port: %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT;
+	if (!strcmp(res->enable, "enable"))
+		info.info.enable = 1;
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+					RTE_ETH_FILTER_SET, &info);
+	if (ret < 0) {
+		printf("Cannot set symmetric hash enable per port on "
+					"port %u\n", res->port_id);
+		return;
+	}
+	printf("Symmetric hash has been set to %s on port %u\n",
+					res->enable, res->port_id);
+}
+
+cmdline_parse_token_string_t cmd_set_sym_hash_ena_per_port_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_sym_hash_ena_per_port_result,
+		set_sym_hash_ena_per_port, "set_sym_hash_ena_per_port");
+cmdline_parse_token_num_t cmd_set_sym_hash_ena_per_port_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_sym_hash_ena_per_port_result,
+		port_id, UINT8);
+cmdline_parse_token_string_t cmd_set_sym_hash_ena_per_port_enable =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_sym_hash_ena_per_port_result,
+		enable, "enable#disable");
+
+cmdline_parse_inst_t cmd_set_sym_hash_ena_per_port = {
+	.f = cmd_set_sym_hash_per_port_parsed,
+	.data = NULL,
+	.help_str = "set_sym_hash_ena_per_port port_id enable|disable",
+	.tokens = {
+		(void *)&cmd_set_sym_hash_ena_per_port_all,
+		(void *)&cmd_set_sym_hash_ena_per_port_port_id,
+		(void *)&cmd_set_sym_hash_ena_per_port_enable,
+		NULL,
+	},
+};
+
+/* Get global config of hash function */
+struct cmd_get_hash_global_config_result {
+	cmdline_fixed_string_t get_hash_global_config;
+	uint8_t port_id;
+};
+
+static char *
+flowtype_to_str(enum rte_eth_flow_type ftype)
+{
+	uint16_t i;
+	static struct {
+		char str[16];
+		enum rte_eth_flow_type ftype;
+	} ftype_table[] = {
+		{"ip4", RTE_ETH_FLOW_TYPE_IPV4_OTHER},
+		{"ip4-frag", RTE_ETH_FLOW_TYPE_FRAG_IPV4},
+		{"udp4", RTE_ETH_FLOW_TYPE_UDPV4},
+		{"tcp4", RTE_ETH_FLOW_TYPE_TCPV4},
+		{"sctp4", RTE_ETH_FLOW_TYPE_SCTPV4},
+		{"ip6", RTE_ETH_FLOW_TYPE_IPV6_OTHER},
+		{"ip6-frag", RTE_ETH_FLOW_TYPE_FRAG_IPV6},
+		{"udp6", RTE_ETH_FLOW_TYPE_UDPV6},
+		{"tcp6", RTE_ETH_FLOW_TYPE_TCPV6},
+		{"sctp6", RTE_ETH_FLOW_TYPE_TCPV6},
+	};
+
+	for (i = 0; i < RTE_DIM(ftype_table); i++) {
+		if (ftype_table[i].ftype == ftype)
+			return ftype_table[i].str;
+	}
+
+	return NULL;
+}
+
+static void
+cmd_get_hash_global_config_parsed(void *parsed_result,
+				  __rte_unused struct cmdline *cl,
+				  __rte_unused void *data)
+{
+	struct cmd_get_hash_global_config_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	uint32_t idx, offset, i;
+	char *str;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+			RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port %d\n",
+							res->port_id);
+		return;
+	}
+
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_GLOBAL_CONFIG;
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+					RTE_ETH_FILTER_GET, &info);
+	if (ret < 0) {
+		printf("Cannot get hash global configurations by port %d\n",
+							res->port_id);
+		return;
+	}
+
+	switch (info.info.global_conf.hash_func) {
+	case RTE_ETH_HASH_FUNCTION_TOEPLITZ:
+		printf("Hash function is Toeplitz\n");
+		break;
+	case RTE_ETH_HASH_FUNCTION_SIMPLE_XOR:
+		printf("Hash function is Simple XOR\n");
+		break;
+	default:
+		printf("Unknown hash function\n");
+		break;
+	}
+
+	for (i = 0; i < RTE_ETH_FLOW_TYPE_MAX; i++) {
+		idx = i / UINT32_BIT;
+		offset = i % UINT32_BIT;
+		if (!(info.info.global_conf.valid_bit_mask[idx] &
+						(1UL << offset)))
+			continue;
+		str = flowtype_to_str((enum rte_eth_flow_type)i);
+		if (!str)
+			continue;
+		printf("Symmetric hash is %s globally for flow type %s "
+							"by port %d\n",
+			((info.info.global_conf.sym_hash_enable_mask[idx] &
+			(1UL << offset)) ? "enabled" : "disabled"), str,
+							res->port_id);
+	}
+}
+
+cmdline_parse_token_string_t cmd_get_hash_global_config_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_get_hash_global_config_result,
+		get_hash_global_config, "get_hash_global_config");
+cmdline_parse_token_num_t cmd_get_hash_global_config_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_get_hash_global_config_result,
+		port_id, UINT8);
+
+cmdline_parse_inst_t cmd_get_hash_global_config = {
+	.f = cmd_get_hash_global_config_parsed,
+	.data = NULL,
+	.help_str = "get_hash_global_config port_id",
+	.tokens = {
+		(void *)&cmd_get_hash_global_config_all,
+		(void *)&cmd_get_hash_global_config_port_id,
+		NULL,
+	},
+};
+
+/* Set global config of hash function */
+struct cmd_set_hash_global_config_result {
+	cmdline_fixed_string_t set_hash_global_config;
+	uint8_t port_id;
+	cmdline_fixed_string_t hash_func;
+	cmdline_fixed_string_t flow_type;
+	cmdline_fixed_string_t enable;
+};
+
+static void
+cmd_set_hash_global_config_parsed(void *parsed_result,
+				  __rte_unused struct cmdline *cl,
+				  __rte_unused void *data)
+{
+	struct cmd_set_hash_global_config_result *res = parsed_result;
+	struct rte_eth_hash_filter_info info;
+	uint32_t ftype, idx, offset;
+	int ret;
+
+	if (rte_eth_dev_filter_supported(res->port_id,
+				RTE_ETH_FILTER_HASH) < 0) {
+		printf("RTE_ETH_FILTER_HASH not supported on port %d\n",
+							res->port_id);
+		return;
+	}
+	memset(&info, 0, sizeof(info));
+	info.info_type = RTE_ETH_HASH_FILTER_GLOBAL_CONFIG;
+	if (!strcmp(res->hash_func, "toeplitz"))
+		info.info.global_conf.hash_func =
+			RTE_ETH_HASH_FUNCTION_TOEPLITZ;
+	else if (!strcmp(res->hash_func, "simple_xor"))
+		info.info.global_conf.hash_func =
+			RTE_ETH_HASH_FUNCTION_SIMPLE_XOR;
+	else if (!strcmp(res->hash_func, "default"))
+		info.info.global_conf.hash_func =
+			RTE_ETH_HASH_FUNCTION_DEFAULT;
+
+	ftype = str2flowtype(res->flow_type);
+	idx = ftype / (CHAR_BIT * sizeof(uint32_t));
+	offset = ftype % (CHAR_BIT * sizeof(uint32_t));
+	info.info.global_conf.valid_bit_mask[idx] |= (1UL << offset);
+	if (!strcmp(res->enable, "enable"))
+		info.info.global_conf.sym_hash_enable_mask[idx] |=
+						(1UL << offset);
+	ret = rte_eth_dev_filter_ctrl(res->port_id, RTE_ETH_FILTER_HASH,
+					RTE_ETH_FILTER_SET, &info);
+	if (ret < 0)
+		printf("Cannot set global hash configurations by port %d\n",
+							res->port_id);
+	else
+		printf("Global hash configurations have been set "
+			"succcessfully by port %d\n", res->port_id);
+}
+
+cmdline_parse_token_string_t cmd_set_hash_global_config_all =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_hash_global_config_result,
+		set_hash_global_config, "set_hash_global_config");
+cmdline_parse_token_num_t cmd_set_hash_global_config_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_hash_global_config_result,
+		port_id, UINT8);
+cmdline_parse_token_string_t cmd_set_hash_global_config_hash_func =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_hash_global_config_result,
+		hash_func, "toeplitz#simple_xor#default");
+cmdline_parse_token_string_t cmd_set_hash_global_config_flow_type =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_hash_global_config_result,
+		flow_type,
+		"ip4#ip4-frag#tcp4#udp4#sctp4#ip6#ip6-frag#tcp6#udp6#sctp6");
+cmdline_parse_token_string_t cmd_set_hash_global_config_enable =
+	TOKEN_STRING_INITIALIZER(struct cmd_set_hash_global_config_result,
+		enable, "enable#disable");
+
+cmdline_parse_inst_t cmd_set_hash_global_config = {
+	.f = cmd_set_hash_global_config_parsed,
+	.data = NULL,
+	.help_str = "set_hash_global_config port_id "
+		"toeplitz|simple_xor|default "
+		"ip4|ip4-frag|tcp4|udp4|#sctp4|ip6|ip6-frag|tcp6|udp6|sctp6 "
+		"enable|disable",
+	.tokens = {
+		(void *)&cmd_set_hash_global_config_all,
+		(void *)&cmd_set_hash_global_config_port_id,
+		(void *)&cmd_set_hash_global_config_hash_func,
+		(void *)&cmd_set_hash_global_config_flow_type,
+		(void *)&cmd_set_hash_global_config_enable,
+		NULL,
+	},
+};
+
 /* ******************************************************************************** */
 
 /* list of instructions */
@@ -8807,6 +9136,10 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_flush_flow_director,
 	(cmdline_parse_inst_t *)&cmd_set_flow_director_flex_mask,
 	(cmdline_parse_inst_t *)&cmd_set_flow_director_flex_payload,
+	(cmdline_parse_inst_t *)&cmd_get_sym_hash_ena_per_port,
+	(cmdline_parse_inst_t *)&cmd_set_sym_hash_ena_per_port,
+	(cmdline_parse_inst_t *)&cmd_get_hash_global_config,
+	(cmdline_parse_inst_t *)&cmd_set_hash_global_config,
 	NULL,
 };
 
-- 
1.8.1.4

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [dpdk-dev] [PATCH v8 3/4] i40e: support of controlling hash functions
  2015-01-20  7:54               ` Thomas Monjalon
  2015-01-21  0:13                 ` Zhang, Helin
@ 2015-01-22  7:44                 ` Zhang, Helin
  1 sibling, 0 replies; 71+ messages in thread
From: Zhang, Helin @ 2015-01-22  7:44 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev

Hi Thomas

I have sent out v9 of this patch set, with adopting your comments. Thank you very much!

> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Tuesday, January 20, 2015 3:54 PM
> To: Zhang, Helin
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v8 3/4] i40e: support of controlling hash
> functions
> 
> Hi Helin,
> 
> 2014-12-02 10:19, Helin Zhang:
> > Hash filter control has been implemented for i40e. It includes
> > getting/setting,
> > - global hash configurations (hash function type, and symmetric
> >   hash enable per flow type)
> > - symmetric hash enable per port
> >
> > Signed-off-by: Helin Zhang <helin.zhang@intel.com>
> > ---
> >  lib/librte_ether/rte_eth_ctrl.h   |  63 ++++++++
> >  lib/librte_pmd_i40e/i40e_ethdev.c | 294
> > +++++++++++++++++++++++++++++++++++++-
> >  2 files changed, 355 insertions(+), 2 deletions(-)
> 
> Please, could you split ethdev and i40e parts while keeping Konstantin's ack?
I have split it into two patches. Please forgive my typo (splitted->split) in changes logs
which will not occur in commits.
Do I need ask Konstantin to send out his Acked-by again? Or we can just add it?
The only differences is just as below.

--- a/lib/librte_ether/rte_eth_ctrl.h
+++ b/lib/librte_ether/rte_eth_ctrl.h
@@ -485,7 +485,7 @@ enum rte_eth_hash_function {
  * include symmetric hash enable per flow type and hash function type.
  * Each bit in sym_hash_enable_mask[] indicates if the symmetric hash of the
  * coresponding flow type is enabled or not.
- * Each bit in valid_bit_mask[] indicates if the corresponding bit in
+ * Each bit in valid_bit_mask[] indicates if the coresponding bit in
  * sym_hash_enable_mask[] is valid or not. For the configurations gotten, it
  * also means if the flow type is supported by hardware or not.
  */
@@ -493,7 +493,7 @@ struct rte_eth_hash_global_conf {
        enum rte_eth_hash_function hash_func; /**< Hash function type */
        /** Bit mask for symmetric hash enable per flow type */
        uint32_t sym_hash_enable_mask[RTE_SYM_HASH_MASK_ARRAY_SIZE];
-       /** Bit mask indicates if the corresponding bit is valid */
+       /** Bit mask indicates if the coresponding bit is valid */
        uint32_t valid_bit_mask[RTE_SYM_HASH_MASK_ARRAY_SIZE];
 };
 
@@ -502,12 +502,12 @@ struct rte_eth_hash_global_conf {
  * type of 'RTE_ETH_FILTER_HASH' and its operations.
  */
 struct rte_eth_hash_filter_info {
-       enum rte_eth_hash_filter_info_type info_type; /**< Information type */
-       /** Details of hash filter information */
+       enum rte_eth_hash_filter_info_type info_type; /**< Information type. */
+       /** Details of hash filter infomation */
        union {
-               /** For RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT */
+               /* For RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT */
                uint8_t enable;
-               /** Global configurations of hash filter */
+               /* Global configurations of hash filter */
                struct rte_eth_hash_global_conf global_conf;
        } info;
 };

> 
> [...]
> > + * Each bit in valid_bit_mask[] indicates if the coresponding bit in
> 
> Typo: corresponding
Thanks, it is corrected in v9.

> 
> [...]
> > +	/** Bit mask indicates if the coresponding bit is valid */
> 
> Same typo
Thanks, it is corrected in v9.

> 
> [...]
> > +	/** Details of hash filter infomation */
> 
> Typo: information
Thanks, it is corrected in v9.

> 
> > +	union {
> > +		/* For RTE_ETH_HASH_FILTER_SYM_HASH_ENA_PER_PORT */
> > +		uint8_t enable;
> > +		/* Global configurations of hash filter */
> > +		struct rte_eth_hash_global_conf global_conf;
> > +	} info;
> 
> Why these comments are not doxygen'ed?
Thanks, it is enabled in v9.

> 
> Sorry for nitpicking, that's the last review pass ;)
Don't worry, it is not nitpicking from my point of view. I really appreciate your hard works!
Thank you!

Regards,
Helin

> --
> Thomas

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [dpdk-dev] [PATCH v9 5/5] app/testpmd: add commands to support hash functions
       [not found]                 ` <5028514.8nkR6oWFO2@xps13>
@ 2015-02-03  2:35                   ` Zhang, Helin
  0 siblings, 0 replies; 71+ messages in thread
From: Zhang, Helin @ 2015-02-03  2:35 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev

Hi Thomas

Yes, I agree with you. Documentation is needed. I will update it soon later together with others I need to update. Thanks for your reminder!

Regards,
Helin

> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Monday, February 2, 2015 10:57 PM
> To: Zhang, Helin
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v9 5/5] app/testpmd: add commands to support
> hash functions
> 
> 2015-01-22 15:36, Helin Zhang:
> > To demonstrate the hash filter control, commands are added.
> > They are,
> > - get_sym_hash_ena_per_port
> > - set_sym_hash_ena_per_port
> > - get_hash_global_config
> > - set_hash_global_config
> >
> > Signed-off-by: Helin Zhang <helin.zhang@intel.com>
> > ---
> >  app/test-pmd/cmdline.c | 333
> > +++++++++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 333 insertions(+)
> 
> The new testpmd functions should be documented in
> doc/guides/testpmd_app_ug/testpmd_funcs.rst.
> The patch won't be blocked waiting for documentation because it is an old
> patchset and the doc requirement is newer.
> Please, don't forget to submit a doc patch.
> --
> Thomas

^ permalink raw reply	[flat|nested] 71+ messages in thread

end of thread, other threads:[~2015-02-03  2:35 UTC | newest]

Thread overview: 71+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-09-30  6:20 [dpdk-dev] [PATCH v3 0/7] Support configuring hash functions Helin Zhang
2014-09-30  6:20 ` [dpdk-dev] [PATCH v3 1/7] ethdev: add more annotations Helin Zhang
2014-10-13  6:12   ` [dpdk-dev] [PATCH v4 0/7] Support configuring hash functions Helin Zhang
2014-10-13  6:12     ` [dpdk-dev] [PATCH v4 1/7] ethdev: add more annotations Helin Zhang
2014-10-13  6:12     ` [dpdk-dev] [PATCH v4 2/7] ethdev: add interfaces and relevant for filter control Helin Zhang
2014-10-13  6:12     ` [dpdk-dev] [PATCH v4 3/7] ethdev: add structures and enum for hash " Helin Zhang
2014-10-13  6:12     ` [dpdk-dev] [PATCH v4 4/7] i40e: add hash filter control implementation Helin Zhang
2014-10-13 10:23       ` Chilikin, Andrey
2014-10-14  0:42         ` Zhang, Helin
2014-10-13  6:12     ` [dpdk-dev] [PATCH v4 5/7] i40e: add hardware initialization Helin Zhang
2014-10-13  6:12     ` [dpdk-dev] [PATCH v4 6/7] i40e: Use constant random hash keys Helin Zhang
2014-10-13  6:12     ` [dpdk-dev] [PATCH v4 7/7] app/testpmd: add commands to support hash filter control Helin Zhang
2014-10-13 12:27     ` [dpdk-dev] [PATCH v4 0/7] Support configuring hash functions Zhan, Zhaochen
2014-10-14  3:32     ` Wu, Jingjing
2014-10-21  3:14     ` [dpdk-dev] [PATCH v5 0/5] " Helin Zhang
2014-10-21  3:14       ` [dpdk-dev] [PATCH v5 1/5] i40e: Use constant random hash keys Helin Zhang
2014-11-03  7:49         ` Thomas Monjalon
2014-11-03  8:18           ` Zhang, Helin
2014-11-03  8:59             ` Thomas Monjalon
2014-11-06  7:52               ` Zhang, Helin
2014-11-11  3:30               ` Zhang, Helin
2014-10-21  3:14       ` [dpdk-dev] [PATCH v5 2/5] ethdev: add enum type and relevant structures for hash filter control Helin Zhang
2014-11-03  7:57         ` Thomas Monjalon
2014-11-06  3:41           ` Zhang, Helin
2014-11-06  8:43             ` Thomas Monjalon
2014-11-06  8:54               ` Zhang, Helin
2014-11-11  3:27           ` Zhang, Helin
2014-11-11  6:46           ` Zhang, Helin
2014-11-11 21:08             ` Thomas Monjalon
2014-11-12  5:52               ` Zhang, Helin
2014-11-12  9:30                 ` Thomas Monjalon
2014-11-12 14:22                   ` Zhang, Helin
2014-10-21  3:14       ` [dpdk-dev] [PATCH v5 3/5] i40e: add hash filter control implementation Helin Zhang
2014-10-21  3:14       ` [dpdk-dev] [PATCH v5 4/5] i40e: add hardware initialization Helin Zhang
2014-10-21  3:14       ` [dpdk-dev] [PATCH v5 5/5] app/testpmd: add commands to support hash filter Helin Zhang
2014-11-07  3:45       ` [dpdk-dev] [PATCH v5 0/5] Support configuring hash functions Chen, Erlu
2014-11-07  6:12       ` Chen, Erlu
2014-11-19 14:58       ` [dpdk-dev] [PATCH v6 0/3] " Helin Zhang
2014-11-19 14:58         ` [dpdk-dev] [PATCH v6 1/3] i40e: Use constant as the default hash keys Helin Zhang
2014-11-19 14:58         ` [dpdk-dev] [PATCH v6 2/3] i40e: support of controlling hash functions Helin Zhang
2014-11-19 14:58         ` [dpdk-dev] [PATCH v6 3/3] app/testpmd: add commands to support " Helin Zhang
2014-11-27 15:45         ` [dpdk-dev] [PATCH v6 0/3] Support configuring " Thomas Monjalon
2014-11-27 16:17           ` Zhang, Helin
2014-11-28 12:14         ` [dpdk-dev] [PATCH v7 0/4] " Helin Zhang
2014-11-28 12:14           ` [dpdk-dev] [PATCH v7 1/4] ethdev: code style fixes Helin Zhang
2014-11-28 12:14           ` [dpdk-dev] [PATCH v7 2/4] i40e: use constant as the default hash keys Helin Zhang
2014-11-28 12:14           ` [dpdk-dev] [PATCH v7 3/4] i40e: support of controlling hash functions Helin Zhang
2014-11-28 12:52             ` Ananyev, Konstantin
2014-11-28 12:14           ` [dpdk-dev] [PATCH v7 4/4] app/testpmd: app/testpmd: add commands to support " Helin Zhang
2014-12-02  2:19           ` [dpdk-dev] [PATCH v8 0/4] Support configuring " Helin Zhang
2014-12-02  2:19             ` [dpdk-dev] [PATCH v8 1/4] ethdev: code style fixes Helin Zhang
2014-12-02  2:19             ` [dpdk-dev] [PATCH v8 2/4] i40e: use constant as the default hash keys Helin Zhang
2014-12-02  2:19             ` [dpdk-dev] [PATCH v8 3/4] i40e: support of controlling hash functions Helin Zhang
2015-01-20  7:54               ` Thomas Monjalon
2015-01-21  0:13                 ` Zhang, Helin
2015-01-22  7:44                 ` Zhang, Helin
2014-12-02  2:19             ` [dpdk-dev] [PATCH v8 4/4] app/testpmd: add commands to support " Helin Zhang
2014-12-02 13:15             ` [dpdk-dev] [PATCH v8 0/4] Support configuring " Ananyev, Konstantin
2015-01-22  7:36             ` [dpdk-dev] [PATCH v9 0/5] " Helin Zhang
2015-01-22  7:36               ` [dpdk-dev] [PATCH v9 1/5] i40e: use constant as the default hash keys Helin Zhang
2015-01-22  7:36               ` [dpdk-dev] [PATCH v9 2/5] ethdev: code style fixes Helin Zhang
2015-01-22  7:36               ` [dpdk-dev] [PATCH v9 3/5] ethdev: support of configuring hash functions Helin Zhang
2015-01-22  7:36               ` [dpdk-dev] [PATCH v9 4/5] i40e: support of controlling " Helin Zhang
2015-01-22  7:36               ` [dpdk-dev] [PATCH v9 5/5] app/testpmd: add commands to support " Helin Zhang
     [not found]                 ` <5028514.8nkR6oWFO2@xps13>
2015-02-03  2:35                   ` Zhang, Helin
2014-09-30  6:20 ` [dpdk-dev] [PATCH v3 2/7] ethdev: add interfaces and relevant for filter control Helin Zhang
2014-09-30  6:20 ` [dpdk-dev] [PATCH v3 3/7] ethdev: add structures and enum for hash " Helin Zhang
2014-09-30  6:20 ` [dpdk-dev] [PATCH v3 4/7] i40e: add hash filter control implementation Helin Zhang
2014-09-30  6:20 ` [dpdk-dev] [PATCH v3 5/7] i40e: add hardware initialization Helin Zhang
2014-09-30  6:20 ` [dpdk-dev] [PATCH v3 6/7] i40e: Use constant random hash keys Helin Zhang
2014-09-30  6:20 ` [dpdk-dev] [PATCH v3 7/7] app/testpmd: add commands to support hash filter control Helin Zhang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).