[v3,11/22] net/hns3: add support for RSS of hns3 PMD driver
diff mbox series

Message ID 1569506528-60464-12-git-send-email-xavier.huwei@huawei.com
State Accepted, archived
Delegated to: Ferruh Yigit
Headers show
Series
  • add hns3 ethernet PMD driver
Related show

Checks

Context Check Description
ci/checkpatch warning coding style issues

Commit Message

Wei Hu (Xavier) Sept. 26, 2019, 2:01 p.m. UTC
This patch adds support for RSS of hns3 PMD driver. It included the follow
functions:
In file hns3_rss.c:
1) Set/query hash key, rss_hf by .rss_hash_update/.rss_hash_conf_get ops
   callback functions.
2) Set/query redirection table by .reta_update/.reta_query. ops callback
   functions.
3) Set/query hash algorithm by .filter_ctrl ops callback function when
   the 'filter_type' is RTE_ETH_FILTER_HASH.

In file hns3_flow.c:
1) Set hash key, rss_hf, redirection table and algorithm by .create ops
   callback function.
2) Disable RSS by .destroy or .flush ops callback function.
3) Check the effectiveness of the RSS's configuration by .validate ops
   callback function.

Signed-off-by: Hao Chen <chenhao164@huawei.com>
Signed-off-by: Wei Hu (Xavier) <xavier.huwei@huawei.com>
Signed-off-by: Chunsong Feng <fengchunsong@huawei.com>
Signed-off-by: Min Hu (Connor) <humin29@huawei.com>
Signed-off-by: Huisong Li <lihuisong@huawei.com>
---
v1 -> v2:
	Address Ferruh Yigit's comments as follows:
	https://inbox.dpdk.org/dev/bfee6344-4953-a042-dbb6-efb3d95d77b7@intel.com
---
 doc/guides/nics/features/hns3.ini |   3 +
 drivers/net/hns3/Makefile         |   1 +
 drivers/net/hns3/hns3_ethdev.c    |  11 +
 drivers/net/hns3/hns3_ethdev.h    |   4 +
 drivers/net/hns3/hns3_fdir.h      |   8 +
 drivers/net/hns3/hns3_flow.c      | 454 +++++++++++++++++++++++++++++
 drivers/net/hns3/hns3_rss.c       | 584 ++++++++++++++++++++++++++++++++++++++
 drivers/net/hns3/hns3_rss.h       | 124 ++++++++
 drivers/net/hns3/meson.build      |   1 +
 9 files changed, 1190 insertions(+)
 create mode 100644 drivers/net/hns3/hns3_rss.c
 create mode 100644 drivers/net/hns3/hns3_rss.h

Patch
diff mbox series

diff --git a/doc/guides/nics/features/hns3.ini b/doc/guides/nics/features/hns3.ini
index 74161b6..bdbff51 100644
--- a/doc/guides/nics/features/hns3.ini
+++ b/doc/guides/nics/features/hns3.ini
@@ -8,6 +8,9 @@  Link status          = Y
 MTU update           = Y
 Unicast MAC filter   = Y
 Multicast MAC filter = Y
+RSS hash             = Y
+RSS key update       = Y
+RSS reta update      = Y
 Flow director        = Y
 Flow API             = Y
 FW version           = Y
diff --git a/drivers/net/hns3/Makefile b/drivers/net/hns3/Makefile
index 50ce1d6..5aa0362 100644
--- a/drivers/net/hns3/Makefile
+++ b/drivers/net/hns3/Makefile
@@ -24,6 +24,7 @@  LIBABIVER := 1
 #
 SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_ethdev.c
 SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_cmd.c
+SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_rss.c
 SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_flow.c
 SRCS-$(CONFIG_RTE_LIBRTE_HNS3_PMD) += hns3_fdir.c
 
diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
index 575cad9..d7a36da 100644
--- a/drivers/net/hns3/hns3_ethdev.c
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -1027,6 +1027,10 @@  hns3_dev_infos_get(struct rte_eth_dev *eth_dev, struct rte_eth_dev_info *info)
 
 	info->vmdq_queue_num = 0;
 
+	info->reta_size = HNS3_RSS_IND_TBL_SIZE;
+	info->hash_key_size = HNS3_RSS_KEY_SIZE;
+	info->flow_type_rss_offloads = HNS3_ETH_RSS_SUPPORT;
+
 	info->default_rxportconf.burst_size = HNS3_DEFAULT_PORT_CONF_BURST_SIZE;
 	info->default_txportconf.burst_size = HNS3_DEFAULT_PORT_CONF_BURST_SIZE;
 	info->default_rxportconf.nb_queues = HNS3_DEFAULT_PORT_CONF_QUEUES_NUM;
@@ -2572,6 +2576,8 @@  hns3_init_pf(struct rte_eth_dev *eth_dev)
 		goto err_hw_init;
 	}
 
+	hns3_set_default_rss_args(hw);
+
 	return 0;
 
 err_hw_init:
@@ -2597,6 +2603,7 @@  hns3_uninit_pf(struct rte_eth_dev *eth_dev)
 
 	PMD_INIT_FUNC_TRACE();
 
+	hns3_rss_uninit(hns);
 	hns3_fdir_filter_uninit(hns);
 	hns3_uninit_umv_space(hw);
 	hns3_cmd_uninit(hw);
@@ -2630,6 +2637,10 @@  static const struct eth_dev_ops hns3_eth_dev_ops = {
 	.mac_addr_set           = hns3_set_default_mac_addr,
 	.set_mc_addr_list       = hns3_set_mc_mac_addr_list,
 	.link_update            = hns3_dev_link_update,
+	.rss_hash_update        = hns3_dev_rss_hash_update,
+	.rss_hash_conf_get      = hns3_dev_rss_hash_conf_get,
+	.reta_update            = hns3_dev_rss_reta_update,
+	.reta_query             = hns3_dev_rss_reta_query,
 	.filter_ctrl            = hns3_dev_filter_ctrl,
 };
 
diff --git a/drivers/net/hns3/hns3_ethdev.h b/drivers/net/hns3/hns3_ethdev.h
index a64db64..87e3bbc 100644
--- a/drivers/net/hns3/hns3_ethdev.h
+++ b/drivers/net/hns3/hns3_ethdev.h
@@ -9,6 +9,7 @@ 
 #include <rte_alarm.h>
 
 #include "hns3_cmd.h"
+#include "hns3_rss.h"
 #include "hns3_fdir.h"
 
 /* Vendor ID */
@@ -346,6 +347,9 @@  struct hns3_hw {
 	struct rte_ether_addr mc_addrs[HNS3_MC_MACADDR_NUM];
 	int mc_addrs_num; /* Multicast mac addresses number */
 
+	/* The configuration info of RSS */
+	struct hns3_rss_conf rss_info;
+
 	uint8_t num_tc;             /* Total number of enabled TCs */
 	uint8_t hw_tc_map;
 	enum hns3_fc_mode current_mode;
diff --git a/drivers/net/hns3/hns3_fdir.h b/drivers/net/hns3/hns3_fdir.h
index c1137b7..f7b4216 100644
--- a/drivers/net/hns3/hns3_fdir.h
+++ b/drivers/net/hns3/hns3_fdir.h
@@ -152,6 +152,12 @@  struct hns3_fdir_rule_ele {
 	struct hns3_fdir_rule fdir_conf;
 };
 
+/* rss filter list structure */
+struct hns3_rss_conf_ele {
+	TAILQ_ENTRY(hns3_rss_conf_ele) entries;
+	struct hns3_rss_conf filter_info;
+};
+
 /* hns3_flow memory list structure */
 struct hns3_flow_mem {
 	TAILQ_ENTRY(hns3_flow_mem) entries;
@@ -159,10 +165,12 @@  struct hns3_flow_mem {
 };
 
 TAILQ_HEAD(hns3_fdir_rule_list, hns3_fdir_rule_ele);
+TAILQ_HEAD(hns3_rss_filter_list, hns3_rss_conf_ele);
 TAILQ_HEAD(hns3_flow_mem_list, hns3_flow_mem);
 
 struct hns3_process_private {
 	struct hns3_fdir_rule_list fdir_list;
+	struct hns3_rss_filter_list filter_rss_list;
 	struct hns3_flow_mem_list flow_list;
 };
 
diff --git a/drivers/net/hns3/hns3_flow.c b/drivers/net/hns3/hns3_flow.c
index 06fabcd..bcd121f 100644
--- a/drivers/net/hns3/hns3_flow.c
+++ b/drivers/net/hns3/hns3_flow.c
@@ -11,6 +11,15 @@ 
 #include "hns3_ethdev.h"
 #include "hns3_logs.h"
 
+/* Default default keys */
+static uint8_t hns3_hash_key[] = {
+	0x6D, 0x5A, 0x56, 0xDA, 0x25, 0x5B, 0x0E, 0xC2,
+	0x41, 0x67, 0x25, 0x3D, 0x43, 0xA3, 0x8F, 0xB0,
+	0xD0, 0xCA, 0x2B, 0xCB, 0xAE, 0x7B, 0x30, 0xB4,
+	0x77, 0xCB, 0x2D, 0xA3, 0x80, 0x30, 0xF2, 0x0C,
+	0x6A, 0x42, 0xB7, 0x3B, 0xBE, 0xAC, 0x01, 0xFA
+};
+
 static const uint8_t full_mask[VNI_OR_TNI_LEN] = { 0xFF, 0xFF, 0xFF };
 static const uint8_t zero_mask[VNI_OR_TNI_LEN] = { 0x00, 0x00, 0x00 };
 
@@ -81,6 +90,18 @@  net_addr_to_host(uint32_t *dst, const rte_be32_t *src, size_t len)
 		dst[i] = rte_be_to_cpu_32(src[i]);
 }
 
+static inline const struct rte_flow_action *
+find_rss_action(const struct rte_flow_action actions[])
+{
+	const struct rte_flow_action *next = &actions[0];
+
+	for (; next->type != RTE_FLOW_ACTION_TYPE_END; next++) {
+		if (next->type == RTE_FLOW_ACTION_TYPE_RSS)
+			return next;
+	}
+	return NULL;
+}
+
 static inline struct hns3_flow_counter *
 hns3_counter_lookup(struct rte_eth_dev *dev, uint32_t id)
 {
@@ -1132,6 +1153,7 @@  hns3_filterlist_init(struct rte_eth_dev *dev)
 	struct hns3_process_private *process_list = dev->process_private;
 
 	TAILQ_INIT(&process_list->fdir_list);
+	TAILQ_INIT(&process_list->filter_rss_list);
 	TAILQ_INIT(&process_list->flow_list);
 }
 
@@ -1140,6 +1162,7 @@  hns3_filterlist_flush(struct rte_eth_dev *dev)
 {
 	struct hns3_process_private *process_list = dev->process_private;
 	struct hns3_fdir_rule_ele *fdir_rule_ptr;
+	struct hns3_rss_conf_ele *rss_filter_ptr;
 	struct hns3_flow_mem *flow_node;
 
 	fdir_rule_ptr = TAILQ_FIRST(&process_list->fdir_list);
@@ -1149,6 +1172,14 @@  hns3_filterlist_flush(struct rte_eth_dev *dev)
 		fdir_rule_ptr = TAILQ_FIRST(&process_list->fdir_list);
 	}
 
+	rss_filter_ptr = TAILQ_FIRST(&process_list->filter_rss_list);
+	while (rss_filter_ptr) {
+		TAILQ_REMOVE(&process_list->filter_rss_list, rss_filter_ptr,
+			     entries);
+		rte_free(rss_filter_ptr);
+		rss_filter_ptr = TAILQ_FIRST(&process_list->filter_rss_list);
+	}
+
 	flow_node = TAILQ_FIRST(&process_list->flow_list);
 	while (flow_node) {
 		TAILQ_REMOVE(&process_list->flow_list, flow_node, entries);
@@ -1158,6 +1189,376 @@  hns3_filterlist_flush(struct rte_eth_dev *dev)
 	}
 }
 
+static bool
+hns3_action_rss_same(const struct rte_flow_action_rss *comp,
+		     const struct rte_flow_action_rss *with)
+{
+	return (comp->func == with->func &&
+		comp->level == with->level &&
+		comp->types == with->types &&
+		comp->key_len == with->key_len &&
+		comp->queue_num == with->queue_num &&
+		!memcmp(comp->key, with->key, with->key_len) &&
+		!memcmp(comp->queue, with->queue,
+			sizeof(*with->queue) * with->queue_num));
+}
+
+static int
+hns3_rss_conf_copy(struct hns3_rss_conf *out,
+		   const struct rte_flow_action_rss *in)
+{
+	if (in->key_len > RTE_DIM(out->key) ||
+	    in->queue_num > RTE_DIM(out->queue))
+		return -EINVAL;
+	if (in->key == NULL && in->key_len)
+		return -EINVAL;
+	out->conf = (struct rte_flow_action_rss) {
+		.func = in->func,
+		.level = in->level,
+		.types = in->types,
+		.key_len = in->key_len,
+		.queue_num = in->queue_num,
+	};
+	out->conf.queue =
+		memcpy(out->queue, in->queue,
+		       sizeof(*in->queue) * in->queue_num);
+	if (in->key)
+		out->conf.key = memcpy(out->key, in->key, in->key_len);
+
+	return 0;
+}
+
+/*
+ * This function is used to parse rss action validatation.
+ */
+static int
+hns3_parse_rss_filter(struct rte_eth_dev *dev,
+		      const struct rte_flow_action *actions,
+		      struct rte_flow_error *error)
+{
+	struct hns3_adapter *hns = dev->data->dev_private;
+	struct hns3_hw *hw = &hns->hw;
+	struct hns3_rss_conf *rss_conf = &hw->rss_info;
+	const struct rte_flow_action_rss *rss;
+	const struct rte_flow_action *act;
+	uint32_t act_index = 0;
+	uint64_t flow_types;
+	uint16_t n;
+
+	NEXT_ITEM_OF_ACTION(act, actions, act_index);
+	/* Get configuration args from APP cmdline input */
+	rss = act->conf;
+
+	if (rss == NULL || rss->queue_num == 0) {
+		return rte_flow_error_set(error, EINVAL,
+					  RTE_FLOW_ERROR_TYPE_ACTION,
+					  act, "no valid queues");
+	}
+
+	for (n = 0; n < rss->queue_num; n++) {
+		if (rss->queue[n] < dev->data->nb_rx_queues)
+			continue;
+		return rte_flow_error_set(error, EINVAL,
+					  RTE_FLOW_ERROR_TYPE_ACTION,
+					  act,
+					  "queue id > max number of queues");
+	}
+
+	/* Parse flow types of RSS */
+	if (!(rss->types & HNS3_ETH_RSS_SUPPORT) && rss->types)
+		return rte_flow_error_set(error, EINVAL,
+					  RTE_FLOW_ERROR_TYPE_ACTION,
+					  act,
+					  "Flow types is unsupported by "
+					  "hns3's RSS");
+
+	flow_types = rss->types & HNS3_ETH_RSS_SUPPORT;
+	if (flow_types != rss->types)
+		hns3_warn(hw, "RSS flow types(%" PRIx64 ") include unsupported "
+			  "flow types", rss->types);
+
+	/* Parse RSS related parameters from RSS configuration */
+	switch (rss->func) {
+	case RTE_ETH_HASH_FUNCTION_DEFAULT:
+	case RTE_ETH_HASH_FUNCTION_TOEPLITZ:
+	case RTE_ETH_HASH_FUNCTION_SIMPLE_XOR:
+		break;
+	default:
+		return rte_flow_error_set(error, ENOTSUP,
+					  RTE_FLOW_ERROR_TYPE_ACTION, act,
+					  "input RSS hash functions are not supported");
+	}
+
+	if (rss->level)
+		return rte_flow_error_set(error, ENOTSUP,
+					  RTE_FLOW_ERROR_TYPE_ACTION, act,
+					  "a nonzero RSS encapsulation level is not supported");
+	if (rss->key_len && rss->key_len != RTE_DIM(rss_conf->key))
+		return rte_flow_error_set(error, ENOTSUP,
+					  RTE_FLOW_ERROR_TYPE_ACTION, act,
+					  "RSS hash key must be exactly 40 bytes");
+	if (rss->queue_num > RTE_DIM(rss_conf->queue))
+		return rte_flow_error_set(error, ENOTSUP,
+					  RTE_FLOW_ERROR_TYPE_ACTION, act,
+					  "too many queues for RSS context");
+
+	act_index++;
+
+	/* Check if the next not void action is END */
+	NEXT_ITEM_OF_ACTION(act, actions, act_index);
+	if (act->type != RTE_FLOW_ACTION_TYPE_END) {
+		memset(rss_conf, 0, sizeof(struct hns3_rss_conf));
+		return rte_flow_error_set(error, EINVAL,
+					  RTE_FLOW_ERROR_TYPE_ACTION,
+					  act, "Not supported action.");
+	}
+
+	return 0;
+}
+
+static int
+hns3_disable_rss(struct hns3_hw *hw)
+{
+	int ret;
+
+	/* Redirected the redirection table to queue 0 */
+	ret = hns3_rss_reset_indir_table(hw);
+	if (ret)
+		return ret;
+
+	/* Disable RSS */
+	hw->rss_info.conf.types = 0;
+
+	return 0;
+}
+
+static void
+hns3_parse_rss_key(struct hns3_hw *hw, struct rte_flow_action_rss *rss_conf)
+{
+	if (rss_conf->key == NULL ||
+	    rss_conf->key_len < HNS3_RSS_KEY_SIZE) {
+		hns3_info(hw, "Default RSS hash key to be set");
+		rss_conf->key = hns3_hash_key;
+		rss_conf->key_len = HNS3_RSS_KEY_SIZE;
+	}
+}
+
+static int
+hns3_parse_rss_algorithm(struct hns3_hw *hw, enum rte_eth_hash_function *func,
+			 uint8_t *hash_algo)
+{
+	enum rte_eth_hash_function algo_func = *func;
+	switch (algo_func) {
+	case RTE_ETH_HASH_FUNCTION_DEFAULT:
+		/* Keep *hash_algo as what it used to be */
+		algo_func = hw->rss_info.conf.func;
+		break;
+	case RTE_ETH_HASH_FUNCTION_TOEPLITZ:
+		*hash_algo = HNS3_RSS_HASH_ALGO_TOEPLITZ;
+		break;
+	case RTE_ETH_HASH_FUNCTION_SIMPLE_XOR:
+		*hash_algo = HNS3_RSS_HASH_ALGO_SIMPLE;
+		break;
+	default:
+		hns3_err(hw, "Invalid RSS algorithm configuration(%u)",
+			 algo_func);
+		return -EINVAL;
+	}
+	*func = algo_func;
+
+	return 0;
+}
+
+static int
+hns3_hw_rss_hash_set(struct hns3_hw *hw, struct rte_flow_action_rss *rss_config)
+{
+	uint8_t hash_algo =
+		(hw->rss_info.conf.func == RTE_ETH_HASH_FUNCTION_TOEPLITZ ?
+		 HNS3_RSS_HASH_ALGO_TOEPLITZ : HNS3_RSS_HASH_ALGO_SIMPLE);
+	struct hns3_rss_tuple_cfg *tuple;
+	int ret;
+
+	/* Parse hash key */
+	hns3_parse_rss_key(hw, rss_config);
+
+	/* Parse hash algorithm */
+	ret = hns3_parse_rss_algorithm(hw, &rss_config->func, &hash_algo);
+	if (ret)
+		return ret;
+
+	ret = hns3_set_rss_algo_key(hw, hash_algo, rss_config->key);
+	if (ret)
+		return ret;
+
+	/* Update algorithm of hw */
+	hw->rss_info.conf.func = rss_config->func;
+
+	/* Set flow type supported */
+	tuple = &hw->rss_info.rss_tuple_sets;
+	ret = hns3_set_rss_tuple_by_rss_hf(hw, tuple, rss_config->types);
+	if (ret)
+		hns3_err(hw, "Update RSS tuples by rss hf failed %d", ret);
+
+	return ret;
+}
+
+static int
+hns3_update_indir_table(struct rte_eth_dev *dev,
+			const struct rte_flow_action_rss *conf, uint16_t num)
+{
+	struct hns3_adapter *hns = dev->data->dev_private;
+	struct hns3_hw *hw = &hns->hw;
+	uint8_t indir_tbl[HNS3_RSS_IND_TBL_SIZE];
+	uint16_t j, allow_rss_queues;
+	uint8_t queue_id;
+	uint32_t i;
+
+	if (num == 0) {
+		hns3_err(hw, "No PF queues are configured to enable RSS");
+		return -ENOTSUP;
+	}
+
+	allow_rss_queues = RTE_MIN(dev->data->nb_rx_queues, hw->rss_size_max);
+	/* Fill in redirection table */
+	memcpy(indir_tbl, hw->rss_info.rss_indirection_tbl,
+	       HNS3_RSS_IND_TBL_SIZE);
+	for (i = 0, j = 0; i < HNS3_RSS_IND_TBL_SIZE; i++, j++) {
+		j %= num;
+		if (conf->queue[j] >= allow_rss_queues) {
+			hns3_err(hw, "Invalid queue id(%u) to be set in "
+				     "redirection table, max number of rss "
+				     "queues: %u", conf->queue[j],
+				 allow_rss_queues);
+			return -EINVAL;
+		}
+		queue_id = conf->queue[j];
+		indir_tbl[i] = queue_id;
+	}
+
+	return hns3_set_rss_indir_table(hw, indir_tbl, HNS3_RSS_IND_TBL_SIZE);
+}
+
+static int
+hns3_config_rss_filter(struct rte_eth_dev *dev,
+		       const struct hns3_rss_conf *conf, bool add)
+{
+	struct hns3_adapter *hns = dev->data->dev_private;
+	struct hns3_hw *hw = &hns->hw;
+	struct hns3_rss_conf *rss_info;
+	uint64_t flow_types;
+	uint16_t num;
+	int ret;
+
+	struct rte_flow_action_rss rss_flow_conf = {
+		.func = conf->conf.func,
+		.level = conf->conf.level,
+		.types = conf->conf.types,
+		.key_len = conf->conf.key_len,
+		.queue_num = conf->conf.queue_num,
+		.key = conf->conf.key_len ?
+		    (void *)(uintptr_t)conf->conf.key : NULL,
+		.queue = conf->conf.queue,
+	};
+
+	/* The types is Unsupported by hns3' RSS */
+	if (!(rss_flow_conf.types & HNS3_ETH_RSS_SUPPORT) &&
+	    rss_flow_conf.types) {
+		hns3_err(hw,
+			 "Flow types(%" PRIx64 ") is unsupported by hns3's RSS",
+			 rss_flow_conf.types);
+		return -EINVAL;
+	}
+
+	/* Filter the unsupported flow types */
+	flow_types = rss_flow_conf.types & HNS3_ETH_RSS_SUPPORT;
+	if (flow_types != rss_flow_conf.types)
+		hns3_warn(hw, "modified RSS types based on hardware support, "
+			      "requested:%" PRIx64 " configured:%" PRIx64,
+			  rss_flow_conf.types, flow_types);
+	/* Update the useful flow types */
+	rss_flow_conf.types = flow_types;
+
+	if ((rss_flow_conf.types & ETH_RSS_PROTO_MASK) == 0)
+		return hns3_disable_rss(hw);
+
+	rss_info = &hw->rss_info;
+	if (!add) {
+		if (hns3_action_rss_same(&rss_info->conf, &rss_flow_conf)) {
+			ret = hns3_disable_rss(hw);
+			if (ret) {
+				hns3_err(hw, "RSS disable failed(%d)", ret);
+				return ret;
+			}
+			memset(rss_info, 0, sizeof(struct hns3_rss_conf));
+			return 0;
+		}
+		return -EINVAL;
+	}
+
+	/* Get rx queues num */
+	num = dev->data->nb_rx_queues;
+
+	/* Set rx queues to use */
+	num = RTE_MIN(num, rss_flow_conf.queue_num);
+	if (rss_flow_conf.queue_num > num)
+		hns3_warn(hw, "Config queue numbers %u are beyond the scope of truncated",
+			  rss_flow_conf.queue_num);
+	hns3_info(hw, "Max of contiguous %u PF queues are configured", num);
+
+	rte_spinlock_lock(&hw->lock);
+	/* Update redirection talbe of rss */
+	ret = hns3_update_indir_table(dev, &rss_flow_conf, num);
+	if (ret)
+		goto rss_config_err;
+
+	/* Set hash algorithm and flow types by the user's config */
+	ret = hns3_hw_rss_hash_set(hw, &rss_flow_conf);
+	if (ret)
+		goto rss_config_err;
+
+	ret = hns3_rss_conf_copy(rss_info, &rss_flow_conf);
+	if (ret) {
+		hns3_err(hw, "RSS config init fail(%d)", ret);
+		goto rss_config_err;
+	}
+
+rss_config_err:
+	rte_spinlock_unlock(&hw->lock);
+
+	return ret;
+}
+
+/* Remove the rss filter */
+static int
+hns3_clear_rss_filter(struct rte_eth_dev *dev)
+{
+	struct hns3_adapter *hns = dev->data->dev_private;
+	struct hns3_hw *hw = &hns->hw;
+
+	if (hw->rss_info.conf.queue_num == 0)
+		return 0;
+
+	return hns3_config_rss_filter(dev, &hw->rss_info, false);
+}
+
+static int
+hns3_flow_parse_rss(struct rte_eth_dev *dev,
+		    const struct hns3_rss_conf *conf, bool add)
+{
+	struct hns3_adapter *hns = dev->data->dev_private;
+	struct hns3_hw *hw = &hns->hw;
+	bool ret;
+
+	/* Action rss same */
+	ret = hns3_action_rss_same(&hw->rss_info.conf, &conf->conf);
+	if (ret) {
+		hns3_err(hw, "Enter duplicate RSS configuration : %d", ret);
+		return -EINVAL;
+	}
+
+	return hns3_config_rss_filter(dev, conf, add);
+}
+
 static int
 hns3_flow_args_check(const struct rte_flow_attr *attr,
 		     const struct rte_flow_item pattern[],
@@ -1200,6 +1601,9 @@  hns3_flow_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
 	if (ret)
 		return ret;
 
+	if (find_rss_action(actions))
+		return hns3_parse_rss_filter(dev, actions, error);
+
 	memset(&fdir_rule, 0, sizeof(struct hns3_fdir_rule));
 	return hns3_parse_fdir_filter(dev, pattern, actions, &fdir_rule, error);
 }
@@ -1219,8 +1623,11 @@  hns3_flow_create(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
 	struct hns3_process_private *process_list = dev->process_private;
 	struct hns3_adapter *hns = dev->data->dev_private;
 	struct hns3_hw *hw = &hns->hw;
+	const struct hns3_rss_conf *rss_conf;
 	struct hns3_fdir_rule_ele *fdir_rule_ptr;
+	struct hns3_rss_conf_ele *rss_filter_ptr;
 	struct hns3_flow_mem *flow_node;
+	const struct rte_flow_action *act;
 	struct rte_flow *flow;
 	struct hns3_fdir_rule fdir_rule;
 	int ret;
@@ -1249,6 +1656,33 @@  hns3_flow_create(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
 	flow_node->flow = flow;
 	TAILQ_INSERT_TAIL(&process_list->flow_list, flow_node, entries);
 
+	act = find_rss_action(actions);
+	if (act) {
+		rss_conf = act->conf;
+
+		ret = hns3_flow_parse_rss(dev, rss_conf, true);
+		if (ret)
+			goto err;
+
+		rss_filter_ptr = rte_zmalloc("hns3 rss filter",
+					     sizeof(struct hns3_rss_conf_ele),
+					     0);
+		if (rss_filter_ptr == NULL) {
+			hns3_err(hw,
+				    "Failed to allocate hns3_rss_filter memory");
+			ret = -ENOMEM;
+			goto err;
+		}
+		memcpy(&rss_filter_ptr->filter_info, rss_conf,
+			sizeof(struct hns3_rss_conf));
+		TAILQ_INSERT_TAIL(&process_list->filter_rss_list,
+				  rss_filter_ptr, entries);
+
+		flow->rule = rss_filter_ptr;
+		flow->filter_type = RTE_ETH_FILTER_HASH;
+		return flow;
+	}
+
 	memset(&fdir_rule, 0, sizeof(struct hns3_fdir_rule));
 	ret = hns3_parse_fdir_filter(dev, pattern, actions, &fdir_rule, error);
 	if (ret)
@@ -1286,6 +1720,7 @@  hns3_flow_create(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
 	if (fdir_rule.flags & HNS3_RULE_FLAG_COUNTER)
 		hns3_counter_release(dev, fdir_rule.act_cnt.id);
 
+err:
 	rte_flow_error_set(error, -ret, RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
 			   "Failed to create flow");
 out:
@@ -1303,7 +1738,9 @@  hns3_flow_destroy(struct rte_eth_dev *dev, struct rte_flow *flow,
 	struct hns3_process_private *process_list = dev->process_private;
 	struct hns3_adapter *hns = dev->data->dev_private;
 	struct hns3_fdir_rule_ele *fdir_rule_ptr;
+	struct hns3_rss_conf_ele *rss_filter_ptr;
 	struct hns3_flow_mem *flow_node;
+	struct hns3_hw *hw = &hns->hw;
 	enum rte_filter_type filter_type;
 	struct hns3_fdir_rule fdir_rule;
 	int ret;
@@ -1331,6 +1768,19 @@  hns3_flow_destroy(struct rte_eth_dev *dev, struct rte_flow *flow,
 		rte_free(fdir_rule_ptr);
 		fdir_rule_ptr = NULL;
 		break;
+	case RTE_ETH_FILTER_HASH:
+		rss_filter_ptr = (struct hns3_rss_conf_ele *)flow->rule;
+		ret = hns3_config_rss_filter(dev, &hw->rss_info, false);
+		if (ret)
+			return rte_flow_error_set(error, EIO,
+						  RTE_FLOW_ERROR_TYPE_HANDLE,
+						  flow,
+						  "Destroy RSS fail.Try again");
+		TAILQ_REMOVE(&process_list->filter_rss_list, rss_filter_ptr,
+			     entries);
+		rte_free(rss_filter_ptr);
+		rss_filter_ptr = NULL;
+		break;
 	default:
 		return rte_flow_error_set(error, EINVAL,
 					  RTE_FLOW_ERROR_TYPE_HANDLE, flow,
@@ -1371,6 +1821,10 @@  hns3_flow_flush(struct rte_eth_dev *dev, struct rte_flow_error *error)
 		hns3_counter_flush(dev);
 	}
 
+	ret = hns3_clear_rss_filter(dev);
+	if (ret)
+		return ret;
+
 	hns3_filterlist_flush(dev);
 
 	return 0;
diff --git a/drivers/net/hns3/hns3_rss.c b/drivers/net/hns3/hns3_rss.c
new file mode 100644
index 0000000..6a5d633
--- /dev/null
+++ b/drivers/net/hns3/hns3_rss.c
@@ -0,0 +1,584 @@ 
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018-2019 Hisilicon Limited.
+ */
+
+#include <stdbool.h>
+#include <rte_ethdev.h>
+#include <rte_io.h>
+#include <rte_malloc.h>
+#include <rte_memcpy.h>
+#include <rte_spinlock.h>
+
+#include "hns3_ethdev.h"
+#include "hns3_logs.h"
+
+/*
+ * The hash key used for rss initialization.
+ */
+static const uint8_t hns3_hash_key[] = {
+	0x6D, 0x5A, 0x56, 0xDA, 0x25, 0x5B, 0x0E, 0xC2,
+	0x41, 0x67, 0x25, 0x3D, 0x43, 0xA3, 0x8F, 0xB0,
+	0xD0, 0xCA, 0x2B, 0xCB, 0xAE, 0x7B, 0x30, 0xB4,
+	0x77, 0xCB, 0x2D, 0xA3, 0x80, 0x30, 0xF2, 0x0C,
+	0x6A, 0x42, 0xB7, 0x3B, 0xBE, 0xAC, 0x01, 0xFA
+};
+
+/*
+ * rss_generic_config command function, opcode:0x0D01.
+ * Used to set algorithm, key_offset and hash key of rss.
+ */
+int
+hns3_set_rss_algo_key(struct hns3_hw *hw, uint8_t hash_algo, const uint8_t *key)
+{
+#define HNS3_KEY_OFFSET_MAX	3
+#define HNS3_SET_HASH_KEY_BYTE_FOUR	2
+
+	struct hns3_rss_generic_config_cmd *req;
+	struct hns3_cmd_desc desc;
+	uint32_t key_offset, key_size;
+	const uint8_t *key_cur;
+	uint8_t cur_offset;
+	int ret;
+
+	req = (struct hns3_rss_generic_config_cmd *)desc.data;
+
+	/*
+	 * key_offset=0, hash key byte0~15 is set to hardware.
+	 * key_offset=1, hash key byte16~31 is set to hardware.
+	 * key_offset=2, hash key byte32~39 is set to hardware.
+	 */
+	for (key_offset = 0; key_offset < HNS3_KEY_OFFSET_MAX; key_offset++) {
+		hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_RSS_GENERIC_CONFIG,
+					  false);
+
+		req->hash_config |= (hash_algo & HNS3_RSS_HASH_ALGO_MASK);
+		req->hash_config |= (key_offset << HNS3_RSS_HASH_KEY_OFFSET_B);
+
+		if (key_offset == HNS3_SET_HASH_KEY_BYTE_FOUR)
+			key_size = HNS3_RSS_KEY_SIZE - HNS3_RSS_HASH_KEY_NUM *
+			HNS3_SET_HASH_KEY_BYTE_FOUR;
+		else
+			key_size = HNS3_RSS_HASH_KEY_NUM;
+
+		cur_offset = key_offset * HNS3_RSS_HASH_KEY_NUM;
+		key_cur = key + cur_offset;
+		memcpy(req->hash_key, key_cur, key_size);
+
+		ret = hns3_cmd_send(hw, &desc, 1);
+		if (ret) {
+			hns3_err(hw, "Configure RSS algo key failed %d", ret);
+			return ret;
+		}
+	}
+	/* Update the shadow RSS key with user specified */
+	memcpy(hw->rss_info.key, key, HNS3_RSS_KEY_SIZE);
+	return 0;
+}
+
+/*
+ * Used to configure the tuple selection for RSS hash input.
+ */
+static int
+hns3_set_rss_input_tuple(struct hns3_hw *hw)
+{
+	struct hns3_rss_conf *rss_config = &hw->rss_info;
+	struct hns3_rss_input_tuple_cmd *req;
+	struct hns3_cmd_desc desc_tuple;
+	int ret;
+
+	hns3_cmd_setup_basic_desc(&desc_tuple, HNS3_OPC_RSS_INPUT_TUPLE, false);
+
+	req = (struct hns3_rss_input_tuple_cmd *)desc_tuple.data;
+
+	req->ipv4_tcp_en = rss_config->rss_tuple_sets.ipv4_tcp_en;
+	req->ipv4_udp_en = rss_config->rss_tuple_sets.ipv4_udp_en;
+	req->ipv4_sctp_en = rss_config->rss_tuple_sets.ipv4_sctp_en;
+	req->ipv4_fragment_en = rss_config->rss_tuple_sets.ipv4_fragment_en;
+	req->ipv6_tcp_en = rss_config->rss_tuple_sets.ipv6_tcp_en;
+	req->ipv6_udp_en = rss_config->rss_tuple_sets.ipv6_udp_en;
+	req->ipv6_sctp_en = rss_config->rss_tuple_sets.ipv6_sctp_en;
+	req->ipv6_fragment_en = rss_config->rss_tuple_sets.ipv6_fragment_en;
+
+	ret = hns3_cmd_send(hw, &desc_tuple, 1);
+	if (ret)
+		hns3_err(hw, "Configure RSS input tuple mode failed %d", ret);
+
+	return ret;
+}
+
+/*
+ * rss_indirection_table command function, opcode:0x0D07.
+ * Used to configure the indirection table of rss.
+ */
+int
+hns3_set_rss_indir_table(struct hns3_hw *hw, uint8_t *indir, uint16_t size)
+{
+	struct hns3_rss_indirection_table_cmd *req;
+	struct hns3_cmd_desc desc;
+	int ret, i, j, num;
+
+	req = (struct hns3_rss_indirection_table_cmd *)desc.data;
+
+	for (i = 0; i < size / HNS3_RSS_CFG_TBL_SIZE; i++) {
+		hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_RSS_INDIR_TABLE,
+					  false);
+		req->start_table_index =
+				rte_cpu_to_le_16(i * HNS3_RSS_CFG_TBL_SIZE);
+		req->rss_set_bitmap = rte_cpu_to_le_16(HNS3_RSS_SET_BITMAP_MSK);
+		for (j = 0; j < HNS3_RSS_CFG_TBL_SIZE; j++) {
+			num = i * HNS3_RSS_CFG_TBL_SIZE + j;
+			req->rss_result[j] = indir[num] % hw->alloc_rss_size;
+		}
+		ret = hns3_cmd_send(hw, &desc, 1);
+		if (ret) {
+			hns3_err(hw,
+				 "Sets RSS indirection table failed %d size %u",
+				 ret, size);
+			return ret;
+		}
+	}
+
+	/* Update redirection table of hw */
+	memcpy(hw->rss_info.rss_indirection_tbl, indir,	HNS3_RSS_IND_TBL_SIZE);
+
+	return 0;
+}
+
+int
+hns3_rss_reset_indir_table(struct hns3_hw *hw)
+{
+	uint8_t *lut;
+	int ret;
+
+	lut = rte_zmalloc("hns3_rss_lut", HNS3_RSS_IND_TBL_SIZE, 0);
+	if (lut == NULL) {
+		hns3_err(hw, "No hns3_rss_lut memory can be allocated");
+		return -ENOMEM;
+	}
+
+	ret = hns3_set_rss_indir_table(hw, lut, HNS3_RSS_IND_TBL_SIZE);
+	if (ret)
+		hns3_err(hw, "RSS uninit indir table failed: %d", ret);
+	rte_free(lut);
+
+	return ret;
+}
+
+int
+hns3_set_rss_tuple_by_rss_hf(struct hns3_hw *hw,
+			     struct hns3_rss_tuple_cfg *tuple, uint64_t rss_hf)
+{
+	struct hns3_rss_input_tuple_cmd *req;
+	struct hns3_cmd_desc desc;
+	uint32_t i;
+	int ret;
+
+	hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_RSS_INPUT_TUPLE, false);
+
+	req = (struct hns3_rss_input_tuple_cmd *)desc.data;
+
+	/* Enable ipv4 or ipv6 tuple by flow type */
+	for (i = 0; i < RTE_ETH_FLOW_MAX; i++) {
+		switch (rss_hf & (1ULL << i)) {
+		case ETH_RSS_NONFRAG_IPV4_TCP:
+			req->ipv4_tcp_en = HNS3_RSS_INPUT_TUPLE_OTHER;
+			break;
+		case ETH_RSS_NONFRAG_IPV4_UDP:
+			req->ipv4_udp_en = HNS3_RSS_INPUT_TUPLE_OTHER;
+			break;
+		case ETH_RSS_NONFRAG_IPV4_SCTP:
+			req->ipv4_sctp_en = HNS3_RSS_INPUT_TUPLE_SCTP;
+			break;
+		case ETH_RSS_FRAG_IPV4:
+			req->ipv4_fragment_en |= HNS3_IP_FRAG_BIT_MASK;
+			break;
+		case ETH_RSS_NONFRAG_IPV4_OTHER:
+			req->ipv4_fragment_en |= HNS3_IP_OTHER_BIT_MASK;
+			break;
+		case ETH_RSS_NONFRAG_IPV6_TCP:
+			req->ipv6_tcp_en = HNS3_RSS_INPUT_TUPLE_OTHER;
+			break;
+		case ETH_RSS_NONFRAG_IPV6_UDP:
+			req->ipv6_udp_en = HNS3_RSS_INPUT_TUPLE_OTHER;
+			break;
+		case ETH_RSS_NONFRAG_IPV6_SCTP:
+			req->ipv6_sctp_en = HNS3_RSS_INPUT_TUPLE_SCTP;
+			break;
+		case ETH_RSS_FRAG_IPV6:
+			req->ipv6_fragment_en |= HNS3_IP_FRAG_BIT_MASK;
+			break;
+		case ETH_RSS_NONFRAG_IPV6_OTHER:
+			req->ipv6_fragment_en |= HNS3_IP_OTHER_BIT_MASK;
+			break;
+		default:
+			/* Other unsupported flow types won't change tuples */
+			break;
+		}
+	}
+
+	ret = hns3_cmd_send(hw, &desc, 1);
+	if (ret) {
+		hns3_err(hw, "Update RSS flow types tuples failed %d", ret);
+		return ret;
+	}
+
+	tuple->ipv4_tcp_en = req->ipv4_tcp_en;
+	tuple->ipv4_udp_en = req->ipv4_udp_en;
+	tuple->ipv4_sctp_en = req->ipv4_sctp_en;
+	tuple->ipv4_fragment_en = req->ipv4_fragment_en;
+	tuple->ipv6_tcp_en = req->ipv6_tcp_en;
+	tuple->ipv6_udp_en = req->ipv6_udp_en;
+	tuple->ipv6_sctp_en = req->ipv6_sctp_en;
+	tuple->ipv6_fragment_en = req->ipv6_fragment_en;
+
+	return 0;
+}
+
+/*
+ * Configure RSS hash protocols and hash key.
+ * @param dev
+ *   Pointer to Ethernet device.
+ * @praram rss_conf
+ *   The configuration select of  rss key size and tuple flow_types.
+ * @return
+ *   0 on success, a negative errno value otherwise is set.
+ */
+int
+hns3_dev_rss_hash_update(struct rte_eth_dev *dev,
+			 struct rte_eth_rss_conf *rss_conf)
+{
+	struct hns3_adapter *hns = dev->data->dev_private;
+	struct hns3_hw *hw = &hns->hw;
+	struct hns3_rss_tuple_cfg *tuple = &hw->rss_info.rss_tuple_sets;
+	struct hns3_rss_conf *rss_cfg = &hw->rss_info;
+	uint8_t algo = rss_cfg->conf.func;
+	uint8_t key_len = rss_conf->rss_key_len;
+	uint64_t rss_hf = rss_conf->rss_hf;
+	uint8_t *key = rss_conf->rss_key;
+	int ret;
+
+	rte_spinlock_lock(&hw->lock);
+	ret = hns3_set_rss_tuple_by_rss_hf(hw, tuple, rss_hf);
+	if (ret)
+		goto conf_err;
+
+	if (rss_cfg->conf.types && rss_hf == 0) {
+		/* Disable RSS, reset indirection table by local variable */
+		ret = hns3_rss_reset_indir_table(hw);
+		if (ret)
+			goto conf_err;
+	} else if (rss_hf && rss_cfg->conf.types == 0) {
+		/* Enable RSS, restore indirection table by hw's config */
+		ret = hns3_set_rss_indir_table(hw, rss_cfg->rss_indirection_tbl,
+					       HNS3_RSS_IND_TBL_SIZE);
+		if (ret)
+			goto conf_err;
+	}
+
+	/* Update supported flow types when set tuple success */
+	rss_cfg->conf.types = rss_hf;
+
+	if (key) {
+		if (key_len != HNS3_RSS_KEY_SIZE) {
+			hns3_err(hw, "The hash key len(%u) is invalid",
+				 key_len);
+			ret = -EINVAL;
+			goto conf_err;
+		}
+		ret = hns3_set_rss_algo_key(hw, algo, key);
+		if (ret)
+			goto conf_err;
+	}
+	rte_spinlock_unlock(&hw->lock);
+
+	return 0;
+
+conf_err:
+	rte_spinlock_unlock(&hw->lock);
+	return ret;
+}
+
+/*
+ * Get rss key and rss_hf types set of RSS hash configuration.
+ * @param dev
+ *   Pointer to Ethernet device.
+ * @praram rss_conf
+ *   The buffer to get rss key size and tuple types.
+ * @return
+ *   0 on success.
+ */
+int
+hns3_dev_rss_hash_conf_get(struct rte_eth_dev *dev,
+			   struct rte_eth_rss_conf *rss_conf)
+{
+	struct hns3_adapter *hns = dev->data->dev_private;
+	struct hns3_hw *hw = &hns->hw;
+	struct hns3_rss_conf *rss_cfg = &hw->rss_info;
+
+	rte_spinlock_lock(&hw->lock);
+	rss_conf->rss_hf = rss_cfg->conf.types;
+
+	/* Get the RSS Key required by the user */
+	if (rss_conf->rss_key)
+		memcpy(rss_conf->rss_key, rss_cfg->key, HNS3_RSS_KEY_SIZE);
+	rte_spinlock_unlock(&hw->lock);
+
+	return 0;
+}
+
+/*
+ * Update rss redirection table of RSS.
+ * @param dev
+ *   Pointer to Ethernet device.
+ * @praram reta_conf
+ *   Pointer to the configuration select of mask and redirection tables.
+ * @param reta_size
+ *   Redirection table size.
+ * @return
+ *   0 on success, a negative errno value otherwise is set.
+ */
+int
+hns3_dev_rss_reta_update(struct rte_eth_dev *dev,
+			 struct rte_eth_rss_reta_entry64 *reta_conf,
+			 uint16_t reta_size)
+{
+	struct hns3_adapter *hns = dev->data->dev_private;
+	struct hns3_hw *hw = &hns->hw;
+	struct hns3_rss_conf *rss_cfg = &hw->rss_info;
+	uint16_t i, indir_size = HNS3_RSS_IND_TBL_SIZE; /* Table size is 512 */
+	uint8_t indirection_tbl[HNS3_RSS_IND_TBL_SIZE];
+	uint16_t idx, shift, allow_rss_queues;
+	int ret;
+
+	if (reta_size != indir_size || reta_size > ETH_RSS_RETA_SIZE_512) {
+		hns3_err(hw, "The size of hash lookup table configured (%u)"
+			 "doesn't match the number hardware can supported"
+			 "(%u)", reta_size, indir_size);
+		return -EINVAL;
+	}
+	rte_spinlock_lock(&hw->lock);
+	memcpy(indirection_tbl, rss_cfg->rss_indirection_tbl,
+		HNS3_RSS_IND_TBL_SIZE);
+	allow_rss_queues = RTE_MIN(dev->data->nb_rx_queues, hw->rss_size_max);
+	for (i = 0; i < reta_size; i++) {
+		idx = i / RTE_RETA_GROUP_SIZE;
+		shift = i % RTE_RETA_GROUP_SIZE;
+		if (reta_conf[idx].reta[shift] >= allow_rss_queues) {
+			rte_spinlock_unlock(&hw->lock);
+			hns3_err(hw, "Invalid queue id(%u) to be set in "
+				 "redirection table, max number of rss "
+				 "queues: %u", reta_conf[idx].reta[shift],
+				 allow_rss_queues);
+			return -EINVAL;
+		}
+
+		if (reta_conf[idx].mask & (1ULL << shift))
+			indirection_tbl[i] = reta_conf[idx].reta[shift];
+	}
+
+	ret = hns3_set_rss_indir_table(hw, indirection_tbl,
+				       HNS3_RSS_IND_TBL_SIZE);
+
+	rte_spinlock_unlock(&hw->lock);
+	return ret;
+}
+
+/*
+ * Get rss redirection table of RSS hash configuration.
+ * @param dev
+ *   Pointer to Ethernet device.
+ * @praram reta_conf
+ *   Pointer to the configuration select of mask and redirection tables.
+ * @param reta_size
+ *   Redirection table size.
+ * @return
+ *   0 on success, a negative errno value otherwise is set.
+ */
+int
+hns3_dev_rss_reta_query(struct rte_eth_dev *dev,
+			struct rte_eth_rss_reta_entry64 *reta_conf,
+			uint16_t reta_size)
+{
+	struct hns3_adapter *hns = dev->data->dev_private;
+	struct hns3_hw *hw = &hns->hw;
+	struct hns3_rss_conf *rss_cfg = &hw->rss_info;
+	uint16_t i, indir_size = HNS3_RSS_IND_TBL_SIZE; /* Table size is 512 */
+	uint16_t idx, shift;
+
+	if (reta_size != indir_size || reta_size > ETH_RSS_RETA_SIZE_512) {
+		hns3_err(hw, "The size of hash lookup table configured (%u)"
+			 " doesn't match the number hardware can supported"
+			 "(%u)", reta_size, indir_size);
+		return -EINVAL;
+	}
+	rte_spinlock_lock(&hw->lock);
+	for (i = 0; i < reta_size; i++) {
+		idx = i / RTE_RETA_GROUP_SIZE;
+		shift = i % RTE_RETA_GROUP_SIZE;
+		if (reta_conf[idx].mask & (1ULL << shift))
+			reta_conf[idx].reta[shift] =
+			  rss_cfg->rss_indirection_tbl[i] % hw->alloc_rss_size;
+	}
+	rte_spinlock_unlock(&hw->lock);
+	return 0;
+}
+
+/*
+ * Used to configure the tc_size and tc_offset.
+ */
+static int
+hns3_set_rss_tc_mode(struct hns3_hw *hw)
+{
+	uint16_t rss_size = hw->alloc_rss_size;
+	struct hns3_rss_tc_mode_cmd *req;
+	uint16_t tc_offset[HNS3_MAX_TC_NUM];
+	uint8_t tc_valid[HNS3_MAX_TC_NUM];
+	uint16_t tc_size[HNS3_MAX_TC_NUM];
+	struct hns3_cmd_desc desc;
+	uint16_t roundup_size;
+	uint16_t i;
+	int ret;
+
+	req = (struct hns3_rss_tc_mode_cmd *)desc.data;
+
+	roundup_size = roundup_pow_of_two(rss_size);
+	roundup_size = ilog2(roundup_size);
+
+	for (i = 0; i < HNS3_MAX_TC_NUM; i++) {
+		tc_valid[i] = !!(hw->hw_tc_map & BIT(i));
+		tc_size[i] = roundup_size;
+		tc_offset[i] = rss_size * i;
+	}
+
+	hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_RSS_TC_MODE, false);
+	for (i = 0; i < HNS3_MAX_TC_NUM; i++) {
+		uint16_t mode = 0;
+
+		hns3_set_bit(mode, HNS3_RSS_TC_VALID_B, (tc_valid[i] & 0x1));
+		hns3_set_field(mode, HNS3_RSS_TC_SIZE_M, HNS3_RSS_TC_SIZE_S,
+			       tc_size[i]);
+		hns3_set_field(mode, HNS3_RSS_TC_OFFSET_M, HNS3_RSS_TC_OFFSET_S,
+			       tc_offset[i]);
+
+		req->rss_tc_mode[i] = rte_cpu_to_le_16(mode);
+	}
+	ret = hns3_cmd_send(hw, &desc, 1);
+	if (ret)
+		hns3_err(hw, "Sets rss tc mode failed %d", ret);
+
+	return ret;
+}
+
+static void
+hns3_rss_tuple_uninit(struct hns3_hw *hw)
+{
+	struct hns3_rss_input_tuple_cmd *req;
+	struct hns3_cmd_desc desc;
+	int ret;
+
+	hns3_cmd_setup_basic_desc(&desc, HNS3_OPC_RSS_INPUT_TUPLE, false);
+
+	req = (struct hns3_rss_input_tuple_cmd *)desc.data;
+
+	memset(req, 0, sizeof(struct hns3_rss_tuple_cfg));
+
+	ret = hns3_cmd_send(hw, &desc, 1);
+	if (ret) {
+		hns3_err(hw, "RSS uninit tuple failed %d", ret);
+		return;
+	}
+}
+
+/*
+ * Set the default rss configuration in the init of driver.
+ */
+void
+hns3_set_default_rss_args(struct hns3_hw *hw)
+{
+	struct hns3_rss_conf *rss_cfg = &hw->rss_info;
+	uint16_t queue_num = hw->alloc_rss_size;
+	int i;
+
+	/* Default hash algorithm */
+	rss_cfg->conf.func = RTE_ETH_HASH_FUNCTION_SIMPLE_XOR;
+	memcpy(rss_cfg->key, hns3_hash_key, HNS3_RSS_KEY_SIZE);
+
+	/* Initialize RSS indirection table */
+	for (i = 0; i < HNS3_RSS_IND_TBL_SIZE; i++)
+		rss_cfg->rss_indirection_tbl[i] = i % queue_num;
+}
+
+/*
+ * RSS initialization for hns3 pmd driver.
+ */
+int
+hns3_config_rss(struct hns3_adapter *hns)
+{
+	struct hns3_hw *hw = &hns->hw;
+	struct hns3_rss_conf *rss_cfg = &hw->rss_info;
+	uint8_t hash_algo =
+		(hw->rss_info.conf.func == RTE_ETH_HASH_FUNCTION_TOEPLITZ ?
+		 HNS3_RSS_HASH_ALGO_TOEPLITZ : HNS3_RSS_HASH_ALGO_SIMPLE);
+	uint8_t *hash_key = rss_cfg->key;
+	int ret, ret1;
+
+	enum rte_eth_rx_mq_mode mq_mode = hw->data->dev_conf.rxmode.mq_mode;
+
+	/* When there is no open RSS, redirect the packet queue 0 */
+	if (((uint32_t)mq_mode & ETH_MQ_RX_RSS_FLAG) == 0) {
+		hns3_rss_uninit(hns);
+		return 0;
+	}
+
+	/* Configure RSS hash algorithm and hash key offset */
+	ret = hns3_set_rss_algo_key(hw, hash_algo, hash_key);
+	if (ret)
+		return ret;
+
+	/* Configure the tuple selection for RSS hash input */
+	ret = hns3_set_rss_input_tuple(hw);
+	if (ret)
+		return ret;
+
+	ret = hns3_set_rss_indir_table(hw, rss_cfg->rss_indirection_tbl,
+				       HNS3_RSS_IND_TBL_SIZE);
+	if (ret)
+		goto rss_tuple_uninit;
+
+	ret = hns3_set_rss_tc_mode(hw);
+	if (ret)
+		goto rss_indir_table_uninit;
+
+	return ret;
+
+rss_indir_table_uninit:
+	ret1 = hns3_rss_reset_indir_table(hw);
+	if (ret1 != 0)
+		return ret;
+
+rss_tuple_uninit:
+	hns3_rss_tuple_uninit(hw);
+
+	/* Disable RSS */
+	hw->rss_info.conf.types = 0;
+
+	return ret;
+}
+
+/*
+ * RSS uninitialization for hns3 pmd driver.
+ */
+void
+hns3_rss_uninit(struct hns3_adapter *hns)
+{
+	struct hns3_hw *hw = &hns->hw;
+	int ret;
+
+	hns3_rss_tuple_uninit(hw);
+	ret = hns3_rss_reset_indir_table(hw);
+	if (ret != 0)
+		return;
+
+	/* Disable RSS */
+	hw->rss_info.conf.types = 0;
+}
diff --git a/drivers/net/hns3/hns3_rss.h b/drivers/net/hns3/hns3_rss.h
new file mode 100644
index 0000000..7ffc151
--- /dev/null
+++ b/drivers/net/hns3/hns3_rss.h
@@ -0,0 +1,124 @@ 
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018-2019 Hisilicon Limited.
+ */
+
+#ifndef _HNS3_RSS_H_
+#define _HNS3_RSS_H_
+#include <rte_ethdev.h>
+#include <rte_flow.h>
+
+#define HNS3_ETH_RSS_SUPPORT ( \
+	ETH_RSS_FRAG_IPV4 | \
+	ETH_RSS_NONFRAG_IPV4_TCP | \
+	ETH_RSS_NONFRAG_IPV4_UDP | \
+	ETH_RSS_NONFRAG_IPV4_SCTP | \
+	ETH_RSS_NONFRAG_IPV4_OTHER | \
+	ETH_RSS_FRAG_IPV6 | \
+	ETH_RSS_NONFRAG_IPV6_TCP | \
+	ETH_RSS_NONFRAG_IPV6_UDP | \
+	ETH_RSS_NONFRAG_IPV6_SCTP | \
+	ETH_RSS_NONFRAG_IPV6_OTHER)
+
+#define HNS3_RSS_IND_TBL_SIZE	512 /* The size of hash lookup table */
+#define HNS3_RSS_KEY_SIZE	40
+#define HNS3_RSS_CFG_TBL_NUM \
+	(HNS3_RSS_IND_TBL_SIZE / HNS3_RSS_CFG_TBL_SIZE)
+#define HNS3_RSS_SET_BITMAP_MSK	0xffff
+
+#define HNS3_RSS_HASH_ALGO_TOEPLITZ	0
+#define HNS3_RSS_HASH_ALGO_SIMPLE	1
+#define HNS3_RSS_HASH_ALGO_SYMMETRIC	2
+#define HNS3_RSS_HASH_ALGO_MASK		0xf
+
+#define HNS3_RSS_INPUT_TUPLE_OTHER	GENMASK(3, 0)
+#define HNS3_RSS_INPUT_TUPLE_SCTP	GENMASK(4, 0)
+#define HNS3_IP_FRAG_BIT_MASK		GENMASK(3, 2)
+#define HNS3_IP_OTHER_BIT_MASK		GENMASK(1, 0)
+
+struct hns3_rss_tuple_cfg {
+	uint8_t ipv4_tcp_en;      /* Bit8.0~8.3 */
+	uint8_t ipv4_udp_en;      /* Bit9.0~9.3 */
+	uint8_t ipv4_sctp_en;     /* Bit10.0~10.4 */
+	uint8_t ipv4_fragment_en; /* Bit11.0~11.3 */
+	uint8_t ipv6_tcp_en;      /* Bit12.0~12.3 */
+	uint8_t ipv6_udp_en;      /* Bit13.0~13.3 */
+	uint8_t ipv6_sctp_en;     /* Bit14.0~14.4 */
+	uint8_t ipv6_fragment_en; /* Bit15.0~15.3 */
+};
+
+#define HNS3_RSS_QUEUES_BUFFER_NUM	64 /* Same as the Max rx/tx queue num */
+struct hns3_rss_conf {
+	/* RSS parameters :algorithm, flow_types,  key, queue */
+	struct rte_flow_action_rss conf;
+	uint8_t key[HNS3_RSS_KEY_SIZE];  /* Hash key */
+	struct hns3_rss_tuple_cfg rss_tuple_sets;
+	uint8_t rss_indirection_tbl[HNS3_RSS_IND_TBL_SIZE]; /* Shadow table */
+	uint16_t queue[HNS3_RSS_QUEUES_BUFFER_NUM]; /* Queues indices to use */
+};
+
+/* Bit 8 ~Bit 15 */
+#define HNS3_INSET_IPV4_SRC        0x00000100UL
+#define HNS3_INSET_IPV4_DST        0x00000200UL
+#define HNS3_INSET_IPV6_SRC        0x00000400UL
+#define HNS3_INSET_IPV6_DST        0x00000800UL
+#define HNS3_INSET_SRC_PORT        0x00001000UL
+#define HNS3_INSET_DST_PORT        0x00002000UL
+#define HNS3_INSET_SCTP_VT         0x00004000UL
+
+#ifndef ilog2
+static inline int rss_ilog2(uint32_t x)
+{
+	int log = 0;
+	x >>= 1;
+
+	while (x) {
+		log++;
+		x >>= 1;
+	}
+	return log;
+}
+#define ilog2(x) rss_ilog2(x)
+#endif
+
+static inline uint32_t fls(uint32_t x)
+{
+	uint32_t position;
+	uint32_t i;
+
+	if (x == 0)
+		return 0;
+
+	for (i = (x >> 1), position = 0; i != 0; ++position)
+		i >>= 1;
+
+	return position + 1;
+}
+
+static inline uint32_t roundup_pow_of_two(uint32_t x)
+{
+	return 1UL << fls(x - 1);
+}
+
+struct hns3_adapter;
+
+int hns3_dev_rss_hash_update(struct rte_eth_dev *dev,
+			     struct rte_eth_rss_conf *rss_conf);
+int hns3_dev_rss_hash_conf_get(struct rte_eth_dev *dev,
+			       struct rte_eth_rss_conf *rss_conf);
+int hns3_dev_rss_reta_update(struct rte_eth_dev *dev,
+			     struct rte_eth_rss_reta_entry64 *reta_conf,
+			     uint16_t reta_size);
+int hns3_dev_rss_reta_query(struct rte_eth_dev *dev,
+			    struct rte_eth_rss_reta_entry64 *reta_conf,
+			    uint16_t reta_size);
+void hns3_set_default_rss_args(struct hns3_hw *hw);
+int hns3_set_rss_indir_table(struct hns3_hw *hw, uint8_t *indir, uint16_t size);
+int hns3_rss_reset_indir_table(struct hns3_hw *hw);
+int hns3_config_rss(struct hns3_adapter *hns);
+void hns3_rss_uninit(struct hns3_adapter *hns);
+int hns3_set_rss_tuple_by_rss_hf(struct hns3_hw *hw,
+				 struct hns3_rss_tuple_cfg *tuple,
+				 uint64_t rss_hf);
+int hns3_set_rss_algo_key(struct hns3_hw *hw, uint8_t hash_algo,
+			  const uint8_t *key);
+#endif /* _HNS3_RSS_H_ */
diff --git a/drivers/net/hns3/meson.build b/drivers/net/hns3/meson.build
index aa90788..79453e6 100644
--- a/drivers/net/hns3/meson.build
+++ b/drivers/net/hns3/meson.build
@@ -17,5 +17,6 @@  sources = files('hns3_cmd.c',
 	'hns3_ethdev.c',
 	'hns3_fdir.c',
 	'hns3_flow.c',
+	'hns3_rss.c',
 	)
 deps += ['hash']