diff --git a/doc/guides/nics/i40e.rst b/doc/guides/nics/i40e.rst
index a0b81e6..077b3dc 100644
--- a/doc/guides/nics/i40e.rst
+++ b/doc/guides/nics/i40e.rst
@@ -585,9 +585,9 @@ Generic flow API
 - ``RSS Flow``
 
   RSS Flow supports to set hash input set, hash function, enable hash
-  and configure queue region.
+  and configure queues.
   For example:
-  Configure queue region as queue 0, 1, 2, 3.
+  Configure queues as queue 0, 1, 2, 3.
 
   .. code-block:: console
 
diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index 4778aaf..21903be 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -39,6 +39,7 @@
 #include "i40e_pf.h"
 #include "i40e_regs.h"
 #include "rte_pmd_i40e.h"
+#include "i40e_hash.h"
 
 #define ETH_I40E_FLOATING_VEB_ARG	"enable_floating_veb"
 #define ETH_I40E_FLOATING_VEB_LIST_ARG	"floating_veb_list"
@@ -399,7 +400,6 @@ static int i40e_sw_tunnel_filter_insert(struct i40e_pf *pf,
 static void i40e_tunnel_filter_restore(struct i40e_pf *pf);
 static void i40e_filter_restore(struct i40e_pf *pf);
 static void i40e_notify_all_vfs_link_status(struct rte_eth_dev *dev);
-static int i40e_pf_config_rss(struct i40e_pf *pf);
 
 static const char *const valid_keys[] = {
 	ETH_I40E_FLOATING_VEB_ARG,
@@ -1767,10 +1767,6 @@ static inline void i40e_config_automask(struct i40e_pf *pf)
 	/* initialize queue region configuration */
 	i40e_init_queue_region_conf(dev);
 
-	/* initialize RSS configuration from rte_flow */
-	memset(&pf->rss_info, 0,
-		sizeof(struct i40e_rte_flow_rss_conf));
-
 	/* reset all stats of the device, including pf and main vsi */
 	i40e_dev_stats_reset(dev);
 
@@ -4542,7 +4538,6 @@ static int i40e_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 {
 	struct i40e_pf *pf;
 	struct i40e_hw *hw;
-	int ret;
 
 	if (!vsi || !lut)
 		return -EINVAL;
@@ -4551,12 +4546,16 @@ static int i40e_dev_xstats_get_names(__rte_unused struct rte_eth_dev *dev,
 	hw = I40E_VSI_TO_HW(vsi);
 
 	if (pf->flags & I40E_FLAG_RSS_AQ_CAPABLE) {
-		ret = i40e_aq_set_rss_lut(hw, vsi->vsi_id,
-					  vsi->type != I40E_VSI_SRIOV,
-					  lut, lut_size);
-		if (ret) {
-			PMD_DRV_LOG(ERR, "Failed to set RSS lookup table");
-			return ret;
+		enum i40e_status_code status;
+
+		status = i40e_aq_set_rss_lut(hw, vsi->vsi_id,
+					     vsi->type != I40E_VSI_SRIOV,
+					     lut, lut_size);
+		if (status) {
+			PMD_DRV_LOG(ERR,
+				    "Failed to update RSS lookup table, error status: %d",
+				    status);
+			return -EIO;
 		}
 	} else {
 		uint32_t *lut_dw = (uint32_t *)lut;
@@ -7689,7 +7688,7 @@ struct i40e_vsi *
 }
 
 /* Disable RSS */
-static void
+void
 i40e_pf_disable_rss(struct i40e_pf *pf)
 {
 	struct i40e_hw *hw = I40E_PF_TO_HW(pf);
@@ -7707,7 +7706,6 @@ struct i40e_vsi *
 	uint16_t key_idx = (vsi->type == I40E_VSI_SRIOV) ?
 			   I40E_VFQF_HKEY_MAX_INDEX :
 			   I40E_PFQF_HKEY_MAX_INDEX;
-	int ret = 0;
 
 	if (!key || key_len == 0) {
 		PMD_DRV_LOG(DEBUG, "No key to be configured");
@@ -7720,11 +7718,16 @@ struct i40e_vsi *
 
 	if (pf->flags & I40E_FLAG_RSS_AQ_CAPABLE) {
 		struct i40e_aqc_get_set_rss_key_data *key_dw =
-			(struct i40e_aqc_get_set_rss_key_data *)key;
+				(struct i40e_aqc_get_set_rss_key_data *)key;
+		enum i40e_status_code status =
+				i40e_aq_set_rss_key(hw, vsi->vsi_id, key_dw);
 
-		ret = i40e_aq_set_rss_key(hw, vsi->vsi_id, key_dw);
-		if (ret)
-			PMD_INIT_LOG(ERR, "Failed to configure RSS key via AQ");
+		if (status) {
+			PMD_DRV_LOG(ERR,
+				    "Failed to configure RSS key via AQ, error status: %d",
+				    status);
+			return -EIO;
+		}
 	} else {
 		uint32_t *hash_key = (uint32_t *)key;
 		uint16_t i;
@@ -7744,7 +7747,7 @@ struct i40e_vsi *
 		I40E_WRITE_FLUSH(hw);
 	}
 
-	return ret;
+	return 0;
 }
 
 static int
@@ -9037,7 +9040,7 @@ i40e_status_code i40e_replace_gtp_cloud_filter(struct i40e_pf *pf)
 }
 
 /* Calculate the maximum number of contiguous PF queues that are configured */
-static int
+int
 i40e_pf_calc_configured_queues_num(struct i40e_pf *pf)
 {
 	struct rte_eth_dev_data *data = pf->dev_data;
@@ -9056,19 +9059,72 @@ i40e_status_code i40e_replace_gtp_cloud_filter(struct i40e_pf *pf)
 	return num;
 }
 
-/* Configure RSS */
-static int
-i40e_pf_config_rss(struct i40e_pf *pf)
+/* Reset the global configure of hash function and input sets */
+static void
+i40e_pf_global_rss_reset(struct i40e_pf *pf)
 {
-	enum rte_eth_rx_mq_mode mq_mode = pf->dev_data->dev_conf.rxmode.mq_mode;
 	struct i40e_hw *hw = I40E_PF_TO_HW(pf);
-	struct rte_eth_rss_conf rss_conf;
-	uint32_t i, lut = 0;
-	uint16_t j, num;
+	uint32_t reg, reg_val;
+	int i;
 
-	/*
-	 * If both VMDQ and RSS enabled, not all of PF queues are configured.
-	 * It's necessary to calculate the actual PF queues that are configured.
+	/* Reset global RSS function sets */
+	reg_val = i40e_read_rx_ctl(hw, I40E_GLQF_CTL);
+	if (!(reg_val & I40E_GLQF_CTL_HTOEP_MASK)) {
+		reg_val |= I40E_GLQF_CTL_HTOEP_MASK;
+		i40e_write_global_rx_ctl(hw, I40E_GLQF_CTL, reg_val);
+	}
+
+	for (i = 0; i <= I40E_FILTER_PCTYPE_L2_PAYLOAD; i++) {
+		uint64_t inset;
+		int j, pctype;
+
+		if (hw->mac.type == I40E_MAC_X722)
+			pctype = i40e_read_rx_ctl(hw, I40E_GLQF_FD_PCTYPES(i));
+		else
+			pctype = i;
+
+		/* Reset pctype insets */
+		inset = i40e_get_default_input_set(i);
+		if (inset) {
+			pf->hash_input_set[pctype] = inset;
+			inset = i40e_translate_input_set_reg(hw->mac.type,
+							     inset);
+
+			reg = I40E_GLQF_HASH_INSET(0, pctype);
+			i40e_check_write_global_reg(hw, reg, (uint32_t)inset);
+			reg = I40E_GLQF_HASH_INSET(1, pctype);
+			i40e_check_write_global_reg(hw, reg,
+						    (uint32_t)(inset >> 32));
+
+			/* Clear unused mask registers of the pctype */
+			for (j = 0; j < I40E_INSET_MASK_NUM_REG; j++) {
+				reg = I40E_GLQF_HASH_MSK(j, pctype);
+				i40e_check_write_global_reg(hw, reg, 0);
+			}
+		}
+
+		/* Reset pctype symmetric sets */
+		reg = I40E_GLQF_HSYM(pctype);
+		reg_val = i40e_read_rx_ctl(hw, reg);
+		if (reg_val & I40E_GLQF_HSYM_SYMH_ENA_MASK) {
+			reg_val &= ~I40E_GLQF_HSYM_SYMH_ENA_MASK;
+			i40e_write_global_rx_ctl(hw, reg, reg_val);
+		}
+	}
+	I40E_WRITE_FLUSH(hw);
+}
+
+int
+i40e_pf_reset_rss_reta(struct i40e_pf *pf)
+{
+	struct i40e_hw *hw = &pf->adapter->hw;
+	uint8_t lut[ETH_RSS_RETA_SIZE_512];
+	uint32_t i;
+	int num;
+
+	/* If both VMDQ and RSS enabled, not all of PF queues are
+	 * configured. It's necessary to calculate the actual PF
+	 * queues that are configured.
 	 */
 	if (pf->dev_data->dev_conf.rxmode.mq_mode & ETH_MQ_RX_VMDQ_FLAG)
 		num = i40e_pf_calc_configured_queues_num(pf);
@@ -9076,48 +9132,89 @@ i40e_status_code i40e_replace_gtp_cloud_filter(struct i40e_pf *pf)
 		num = pf->dev_data->nb_rx_queues;
 
 	num = RTE_MIN(num, I40E_MAX_Q_PER_TC);
-	PMD_INIT_LOG(INFO, "Max of contiguous %u PF queues are configured",
-			num);
+	if (num <= 0)
+		return 0;
 
-	if (num == 0) {
-		PMD_INIT_LOG(ERR,
-			"No PF queues are configured to enable RSS for port %u",
-			pf->dev_data->port_id);
-		return -ENOTSUP;
-	}
+	for (i = 0; i < hw->func_caps.rss_table_size; i++)
+		lut[i] = (uint8_t)(i % (uint32_t)num);
 
-	if (pf->adapter->rss_reta_updated == 0) {
-		for (i = 0, j = 0; i < hw->func_caps.rss_table_size; i++, j++) {
-			if (j == num)
-				j = 0;
-			lut = (lut << 8) | (j & ((0x1 <<
-				hw->func_caps.rss_table_entry_width) - 1));
-			if ((i & 3) == 3)
-				I40E_WRITE_REG(hw, I40E_PFQF_HLUT(i >> 2),
-					       rte_bswap32(lut));
-		}
-	}
+	return i40e_set_rss_lut(pf->main_vsi, lut, (uint16_t)i);
+}
 
-	rss_conf = pf->dev_data->dev_conf.rx_adv_conf.rss_conf;
-	if ((rss_conf.rss_hf & pf->adapter->flow_types_mask) == 0 ||
-	    !(mq_mode & ETH_MQ_RX_RSS_FLAG)) {
-		i40e_pf_disable_rss(pf);
-		return 0;
-	}
-	if (rss_conf.rss_key == NULL || rss_conf.rss_key_len <
-		(I40E_PFQF_HKEY_MAX_INDEX + 1) * sizeof(uint32_t)) {
-		/* Random default keys */
+int
+i40e_pf_reset_rss_key(struct i40e_pf *pf)
+{
+	const uint8_t key_len = (I40E_PFQF_HKEY_MAX_INDEX + 1) *
+			sizeof(uint32_t);
+	uint8_t *rss_key;
+
+	/* Reset key */
+	rss_key = pf->dev_data->dev_conf.rx_adv_conf.rss_conf.rss_key;
+	if (!rss_key ||
+	    pf->dev_data->dev_conf.rx_adv_conf.rss_conf.rss_key_len < key_len) {
 		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);
+		rss_key = (uint8_t *)rss_key_default;
+	}
+
+	return i40e_set_rss_key(pf->main_vsi, rss_key, key_len);
+}
+
+static int
+i40e_pf_rss_reset(struct i40e_pf *pf)
+{
+	struct i40e_hw *hw = I40E_PF_TO_HW(pf);
+
+	int ret;
+
+	pf->hash_filter_enable = 0;
+	i40e_pf_disable_rss(pf);
+	i40e_set_symmetric_hash_enable_per_port(hw, 0);
+
+	if (!pf->support_multi_driver)
+		i40e_pf_global_rss_reset(pf);
+
+	/* Reset RETA table */
+	if (pf->adapter->rss_reta_updated == 0) {
+		ret = i40e_pf_reset_rss_reta(pf);
+		if (ret)
+			return ret;
+	}
+
+	return i40e_pf_reset_rss_key(pf);
+}
+
+/* Configure RSS */
+int
+i40e_pf_config_rss(struct i40e_pf *pf)
+{
+	struct i40e_hw *hw;
+	enum rte_eth_rx_mq_mode mq_mode;
+	uint64_t rss_hf, hena;
+	int ret;
+
+	ret = i40e_pf_rss_reset(pf);
+	if (ret) {
+		PMD_DRV_LOG(ERR, "Reset RSS failed, RSS has been disabled");
+		return ret;
 	}
 
-	return i40e_hw_rss_hash_set(pf, &rss_conf);
+	rss_hf = pf->dev_data->dev_conf.rx_adv_conf.rss_conf.rss_hf;
+	mq_mode = pf->dev_data->dev_conf.rxmode.mq_mode;
+	if (!(rss_hf & pf->adapter->flow_types_mask) ||
+	    !(mq_mode & ETH_MQ_RX_RSS_FLAG))
+		return 0;
+
+	hw = I40E_PF_TO_HW(pf);
+	hena = i40e_config_hena(pf->adapter, rss_hf);
+	i40e_write_rx_ctl(hw, I40E_PFQF_HENA(0), (uint32_t)hena);
+	i40e_write_rx_ctl(hw, I40E_PFQF_HENA(1), (uint32_t)(hena >> 32));
+	I40E_WRITE_FLUSH(hw);
+
+	return 0;
 }
 
 static int
@@ -9283,24 +9380,20 @@ i40e_status_code i40e_replace_gtp_cloud_filter(struct i40e_pf *pf)
 }
 
 /* Set the symmetric hash enable configurations per port */
-static void
+void
 i40e_set_symmetric_hash_enable_per_port(struct i40e_hw *hw, uint8_t enable)
 {
 	uint32_t reg = i40e_read_rx_ctl(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");
+		if (reg & I40E_PRTQF_CTL_0_HSYM_ENA_MASK)
 			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");
+		if (!(reg & I40E_PRTQF_CTL_0_HSYM_ENA_MASK))
 			return;
-		}
+
 		reg &= ~I40E_PRTQF_CTL_0_HSYM_ENA_MASK;
 	}
 	i40e_write_rx_ctl(hw, I40E_PRTQF_CTL_0, reg);
@@ -10151,9 +10244,8 @@ i40e_status_code i40e_replace_gtp_cloud_filter(struct i40e_pf *pf)
 {
 	struct i40e_pf *pf = &((struct i40e_adapter *)hw->back)->pf;
 	enum i40e_filter_pctype pctype;
-	uint64_t input_set, inset_reg = 0;
-	uint32_t mask_reg[I40E_INSET_MASK_NUM_REG] = {0};
-	int ret, i, num;
+	uint64_t input_set;
+	int ret;
 
 	if (!conf) {
 		PMD_DRV_LOG(ERR, "Invalid pointer");
@@ -10165,31 +10257,42 @@ i40e_status_code i40e_replace_gtp_cloud_filter(struct i40e_pf *pf)
 		return -EINVAL;
 	}
 
-	if (pf->support_multi_driver) {
-		PMD_DRV_LOG(ERR, "Hash input set setting is not supported.");
-		return -ENOTSUP;
-	}
-
 	pctype = i40e_flowtype_to_pctype(pf->adapter, conf->flow_type);
 	if (pctype == I40E_FILTER_PCTYPE_INVALID) {
 		PMD_DRV_LOG(ERR, "invalid flow_type input.");
 		return -EINVAL;
 	}
 
-	if (hw->mac.type == I40E_MAC_X722) {
-		/* get translated pctype value in fd pctype register */
-		pctype = (enum i40e_filter_pctype)i40e_read_rx_ctl(hw,
-			I40E_GLQF_FD_PCTYPES((int)pctype));
-	}
-
 	ret = i40e_parse_input_set(&input_set, pctype, conf->field,
 				   conf->inset_size);
-	if (ret) {
-		PMD_DRV_LOG(ERR, "Failed to parse input set");
-		return -EINVAL;
+	if (ret)
+		return ret;
+
+	return i40e_set_hash_inset(hw, input_set, pctype,
+				   (conf->op == RTE_ETH_INPUT_SET_ADD) ?
+				   true : false);
+}
+
+int
+i40e_set_hash_inset(struct i40e_hw *hw, uint64_t input_set,
+		    uint32_t pctype, bool add)
+{
+	struct i40e_pf *pf = &((struct i40e_adapter *)hw->back)->pf;
+	uint32_t mask_reg[I40E_INSET_MASK_NUM_REG] = {0};
+	uint64_t inset_reg = 0;
+	int num, i;
+
+	if (pf->support_multi_driver) {
+		PMD_DRV_LOG(ERR,
+			    "Modify input set is not permitted when multi-driver enabled.");
+		return -EPERM;
 	}
 
-	if (conf->op == RTE_ETH_INPUT_SET_ADD) {
+	/* For X722, get translated pctype in fd pctype register */
+	if (hw->mac.type == I40E_MAC_X722)
+		pctype = i40e_read_rx_ctl(hw, I40E_GLQF_FD_PCTYPES(pctype));
+
+	if (add) {
 		/* get inset value in register */
 		inset_reg = i40e_read_rx_ctl(hw, I40E_GLQF_HASH_INSET(1, pctype));
 		inset_reg <<= I40E_32_BIT_WIDTH;
@@ -12623,25 +12726,13 @@ static int i40e_set_default_mac_addr(struct rte_eth_dev *dev,
 	}
 }
 
-/* Restore RSS filter */
-static inline void
-i40e_rss_filter_restore(struct i40e_pf *pf)
-{
-	struct i40e_rss_conf_list *list = &pf->rss_config_list;
-	struct i40e_rss_filter *filter;
-
-	TAILQ_FOREACH(filter, list, next) {
-		i40e_config_rss_filter(pf, &filter->rss_filter_info, TRUE);
-	}
-}
-
 static void
 i40e_filter_restore(struct i40e_pf *pf)
 {
 	i40e_ethertype_filter_restore(pf);
 	i40e_tunnel_filter_restore(pf);
 	i40e_fdir_filter_restore(pf);
-	i40e_rss_filter_restore(pf);
+	(void)i40e_hash_filter_restore(pf);
 }
 
 bool
@@ -13219,551 +13310,6 @@ struct i40e_customized_pctype*
 	return ret;
 }
 
-int
-i40e_rss_conf_init(struct i40e_rte_flow_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 && 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,
-		.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;
-}
-
-/* Write HENA register to enable hash */
-static int
-i40e_rss_hash_set(struct i40e_pf *pf, struct i40e_rte_flow_rss_conf *rss_conf)
-{
-	struct i40e_hw *hw = I40E_PF_TO_HW(pf);
-	uint8_t *key = (void *)(uintptr_t)rss_conf->conf.key;
-	uint64_t hena;
-	int ret;
-
-	ret = i40e_set_rss_key(pf->main_vsi, key,
-			       rss_conf->conf.key_len);
-	if (ret)
-		return ret;
-
-	hena = i40e_config_hena(pf->adapter, rss_conf->conf.types);
-	i40e_write_rx_ctl(hw, I40E_PFQF_HENA(0), (uint32_t)hena);
-	i40e_write_rx_ctl(hw, I40E_PFQF_HENA(1), (uint32_t)(hena >> 32));
-	I40E_WRITE_FLUSH(hw);
-
-	return 0;
-}
-
-/* Configure hash input set */
-static int
-i40e_rss_conf_hash_inset(struct i40e_pf *pf, uint64_t types)
-{
-	struct i40e_hw *hw = I40E_PF_TO_HW(pf);
-	struct rte_eth_input_set_conf conf;
-	uint64_t mask0;
-	int ret = 0;
-	uint32_t j;
-	int i;
-	static const struct {
-		uint64_t type;
-		enum rte_eth_input_set_field field;
-	} inset_match_table[] = {
-		{ETH_RSS_FRAG_IPV4 | ETH_RSS_L3_SRC_ONLY,
-			RTE_ETH_INPUT_SET_L3_SRC_IP4},
-		{ETH_RSS_FRAG_IPV4 | ETH_RSS_L3_DST_ONLY,
-			RTE_ETH_INPUT_SET_L3_DST_IP4},
-		{ETH_RSS_FRAG_IPV4 | ETH_RSS_L4_SRC_ONLY,
-			RTE_ETH_INPUT_SET_UNKNOWN},
-		{ETH_RSS_FRAG_IPV4 | ETH_RSS_L4_DST_ONLY,
-			RTE_ETH_INPUT_SET_UNKNOWN},
-
-		{ETH_RSS_NONFRAG_IPV4_TCP | ETH_RSS_L3_SRC_ONLY,
-			RTE_ETH_INPUT_SET_L3_SRC_IP4},
-		{ETH_RSS_NONFRAG_IPV4_TCP | ETH_RSS_L3_DST_ONLY,
-			RTE_ETH_INPUT_SET_L3_DST_IP4},
-		{ETH_RSS_NONFRAG_IPV4_TCP | ETH_RSS_L4_SRC_ONLY,
-			RTE_ETH_INPUT_SET_L4_TCP_SRC_PORT},
-		{ETH_RSS_NONFRAG_IPV4_TCP | ETH_RSS_L4_DST_ONLY,
-			RTE_ETH_INPUT_SET_L4_TCP_DST_PORT},
-
-		{ETH_RSS_NONFRAG_IPV4_UDP | ETH_RSS_L3_SRC_ONLY,
-			RTE_ETH_INPUT_SET_L3_SRC_IP4},
-		{ETH_RSS_NONFRAG_IPV4_UDP | ETH_RSS_L3_DST_ONLY,
-			RTE_ETH_INPUT_SET_L3_DST_IP4},
-		{ETH_RSS_NONFRAG_IPV4_UDP | ETH_RSS_L4_SRC_ONLY,
-			RTE_ETH_INPUT_SET_L4_UDP_SRC_PORT},
-		{ETH_RSS_NONFRAG_IPV4_UDP | ETH_RSS_L4_DST_ONLY,
-			RTE_ETH_INPUT_SET_L4_UDP_DST_PORT},
-
-		{ETH_RSS_NONFRAG_IPV4_SCTP | ETH_RSS_L3_SRC_ONLY,
-			RTE_ETH_INPUT_SET_L3_SRC_IP4},
-		{ETH_RSS_NONFRAG_IPV4_SCTP | ETH_RSS_L3_DST_ONLY,
-			RTE_ETH_INPUT_SET_L3_DST_IP4},
-		{ETH_RSS_NONFRAG_IPV4_SCTP | ETH_RSS_L4_SRC_ONLY,
-			RTE_ETH_INPUT_SET_L4_SCTP_SRC_PORT},
-		{ETH_RSS_NONFRAG_IPV4_SCTP | ETH_RSS_L4_DST_ONLY,
-			RTE_ETH_INPUT_SET_L4_SCTP_DST_PORT},
-
-		{ETH_RSS_NONFRAG_IPV4_OTHER | ETH_RSS_L3_SRC_ONLY,
-			RTE_ETH_INPUT_SET_L3_SRC_IP4},
-		{ETH_RSS_NONFRAG_IPV4_OTHER | ETH_RSS_L3_DST_ONLY,
-			RTE_ETH_INPUT_SET_L3_DST_IP4},
-		{ETH_RSS_NONFRAG_IPV4_OTHER | ETH_RSS_L4_SRC_ONLY,
-			RTE_ETH_INPUT_SET_UNKNOWN},
-		{ETH_RSS_NONFRAG_IPV4_OTHER | ETH_RSS_L4_DST_ONLY,
-			RTE_ETH_INPUT_SET_UNKNOWN},
-
-		{ETH_RSS_FRAG_IPV6 | ETH_RSS_L3_SRC_ONLY,
-			RTE_ETH_INPUT_SET_L3_SRC_IP6},
-		{ETH_RSS_FRAG_IPV6 | ETH_RSS_L3_DST_ONLY,
-			RTE_ETH_INPUT_SET_L3_DST_IP6},
-		{ETH_RSS_FRAG_IPV6 | ETH_RSS_L4_SRC_ONLY,
-			RTE_ETH_INPUT_SET_UNKNOWN},
-		{ETH_RSS_FRAG_IPV6 | ETH_RSS_L4_DST_ONLY,
-			RTE_ETH_INPUT_SET_UNKNOWN},
-
-		{ETH_RSS_NONFRAG_IPV6_TCP | ETH_RSS_L3_SRC_ONLY,
-			RTE_ETH_INPUT_SET_L3_SRC_IP6},
-		{ETH_RSS_NONFRAG_IPV6_TCP | ETH_RSS_L3_DST_ONLY,
-			RTE_ETH_INPUT_SET_L3_DST_IP6},
-		{ETH_RSS_NONFRAG_IPV6_TCP | ETH_RSS_L4_SRC_ONLY,
-			RTE_ETH_INPUT_SET_L4_TCP_SRC_PORT},
-		{ETH_RSS_NONFRAG_IPV6_TCP | ETH_RSS_L4_DST_ONLY,
-			RTE_ETH_INPUT_SET_L4_TCP_DST_PORT},
-
-		{ETH_RSS_NONFRAG_IPV6_UDP | ETH_RSS_L3_SRC_ONLY,
-			RTE_ETH_INPUT_SET_L3_SRC_IP6},
-		{ETH_RSS_NONFRAG_IPV6_UDP | ETH_RSS_L3_DST_ONLY,
-			RTE_ETH_INPUT_SET_L3_DST_IP6},
-		{ETH_RSS_NONFRAG_IPV6_UDP | ETH_RSS_L4_SRC_ONLY,
-			RTE_ETH_INPUT_SET_L4_UDP_SRC_PORT},
-		{ETH_RSS_NONFRAG_IPV6_UDP | ETH_RSS_L4_DST_ONLY,
-			RTE_ETH_INPUT_SET_L4_UDP_DST_PORT},
-
-		{ETH_RSS_NONFRAG_IPV6_SCTP | ETH_RSS_L3_SRC_ONLY,
-			RTE_ETH_INPUT_SET_L3_SRC_IP6},
-		{ETH_RSS_NONFRAG_IPV6_SCTP | ETH_RSS_L3_DST_ONLY,
-			RTE_ETH_INPUT_SET_L3_DST_IP6},
-		{ETH_RSS_NONFRAG_IPV6_SCTP | ETH_RSS_L4_SRC_ONLY,
-			RTE_ETH_INPUT_SET_L4_SCTP_SRC_PORT},
-		{ETH_RSS_NONFRAG_IPV6_SCTP | ETH_RSS_L4_DST_ONLY,
-			RTE_ETH_INPUT_SET_L4_SCTP_DST_PORT},
-
-		{ETH_RSS_NONFRAG_IPV6_OTHER | ETH_RSS_L3_SRC_ONLY,
-			RTE_ETH_INPUT_SET_L3_SRC_IP6},
-		{ETH_RSS_NONFRAG_IPV6_OTHER | ETH_RSS_L3_DST_ONLY,
-			RTE_ETH_INPUT_SET_L3_DST_IP6},
-		{ETH_RSS_NONFRAG_IPV6_OTHER | ETH_RSS_L4_SRC_ONLY,
-			RTE_ETH_INPUT_SET_UNKNOWN},
-		{ETH_RSS_NONFRAG_IPV6_OTHER | ETH_RSS_L4_DST_ONLY,
-			RTE_ETH_INPUT_SET_UNKNOWN},
-	};
-
-	mask0 = types & pf->adapter->flow_types_mask;
-	conf.op = RTE_ETH_INPUT_SET_SELECT;
-	conf.inset_size = 0;
-	for (i = RTE_ETH_FLOW_UNKNOWN + 1; i < RTE_ETH_FLOW_MAX; i++) {
-		if (mask0 & (1ULL << i)) {
-			conf.flow_type = i;
-			break;
-		}
-	}
-
-	for (j = 0; j < RTE_DIM(inset_match_table); j++) {
-		if ((types & inset_match_table[j].type) ==
-		    inset_match_table[j].type) {
-			if (inset_match_table[j].field ==
-			    RTE_ETH_INPUT_SET_UNKNOWN)
-				return -EINVAL;
-
-			conf.field[conf.inset_size] =
-				inset_match_table[j].field;
-			conf.inset_size++;
-		}
-	}
-
-	if (conf.inset_size) {
-		ret = i40e_hash_filter_inset_select(hw, &conf);
-		if (ret)
-			return ret;
-	}
-
-	return ret;
-}
-
-/* Look up the conflicted rule then mark it as invalid */
-static void
-i40e_rss_mark_invalid_rule(struct i40e_pf *pf,
-		struct i40e_rte_flow_rss_conf *conf)
-{
-	struct i40e_rss_filter *rss_item;
-	uint64_t rss_inset;
-
-	/* Clear input set bits before comparing the pctype */
-	rss_inset = ~(ETH_RSS_L3_SRC_ONLY | ETH_RSS_L3_DST_ONLY |
-		ETH_RSS_L4_SRC_ONLY | ETH_RSS_L4_DST_ONLY);
-
-	/* Look up the conflicted rule then mark it as invalid */
-	TAILQ_FOREACH(rss_item, &pf->rss_config_list, next) {
-		if (!rss_item->rss_filter_info.valid)
-			continue;
-
-		if (conf->conf.queue_num &&
-		    rss_item->rss_filter_info.conf.queue_num)
-			rss_item->rss_filter_info.valid = false;
-
-		if (conf->conf.types &&
-		    (rss_item->rss_filter_info.conf.types &
-		    rss_inset) ==
-		    (conf->conf.types & rss_inset))
-			rss_item->rss_filter_info.valid = false;
-
-		if (conf->conf.func ==
-		    RTE_ETH_HASH_FUNCTION_SIMPLE_XOR &&
-		    rss_item->rss_filter_info.conf.func ==
-		    RTE_ETH_HASH_FUNCTION_SIMPLE_XOR)
-			rss_item->rss_filter_info.valid = false;
-	}
-}
-
-/* Configure RSS hash function */
-static int
-i40e_rss_config_hash_function(struct i40e_pf *pf,
-		struct i40e_rte_flow_rss_conf *conf)
-{
-	struct i40e_hw *hw = I40E_PF_TO_HW(pf);
-	uint32_t reg, i;
-	uint64_t mask0;
-	uint16_t j;
-
-	if (conf->conf.func == RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) {
-		reg = i40e_read_rx_ctl(hw, I40E_GLQF_CTL);
-		if (!(reg & I40E_GLQF_CTL_HTOEP_MASK)) {
-			PMD_DRV_LOG(DEBUG, "Hash function already set to Simple XOR");
-			I40E_WRITE_FLUSH(hw);
-			i40e_rss_mark_invalid_rule(pf, conf);
-
-			return 0;
-		}
-		reg &= ~I40E_GLQF_CTL_HTOEP_MASK;
-
-		i40e_write_global_rx_ctl(hw, I40E_GLQF_CTL, reg);
-		I40E_WRITE_FLUSH(hw);
-		i40e_rss_mark_invalid_rule(pf, conf);
-	} else if (conf->conf.func ==
-		   RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ) {
-		mask0 = conf->conf.types & pf->adapter->flow_types_mask;
-
-		i40e_set_symmetric_hash_enable_per_port(hw, 1);
-		for (i = RTE_ETH_FLOW_UNKNOWN + 1; i < UINT64_BIT; i++) {
-			if (mask0 & (1UL << i))
-				break;
-		}
-
-		if (i == UINT64_BIT)
-			return -EINVAL;
-
-		for (j = I40E_FILTER_PCTYPE_INVALID + 1;
-		     j < I40E_FILTER_PCTYPE_MAX; j++) {
-			if (pf->adapter->pctypes_tbl[i] & (1ULL << j))
-				i40e_write_global_rx_ctl(hw,
-					I40E_GLQF_HSYM(j),
-					I40E_GLQF_HSYM_SYMH_ENA_MASK);
-		}
-	}
-
-	return 0;
-}
-
-/* Enable RSS according to the configuration */
-static int
-i40e_rss_enable_hash(struct i40e_pf *pf,
-		struct i40e_rte_flow_rss_conf *conf)
-{
-	struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info;
-	struct i40e_rte_flow_rss_conf rss_conf;
-
-	if (!(conf->conf.types & pf->adapter->flow_types_mask))
-		return -ENOTSUP;
-
-	memset(&rss_conf, 0, sizeof(rss_conf));
-	rte_memcpy(&rss_conf, conf, sizeof(rss_conf));
-
-	/* Configure hash input set */
-	if (i40e_rss_conf_hash_inset(pf, conf->conf.types))
-		return -EINVAL;
-
-	if (rss_conf.conf.key == NULL || rss_conf.conf.key_len <
-	    (I40E_PFQF_HKEY_MAX_INDEX + 1) * sizeof(uint32_t)) {
-		/* Random default keys */
-		static uint32_t rss_key_default[] = {0x6b793944,
-			0x23504cb5, 0x5bea75b6, 0x309f4f12, 0x3dc0a2b8,
-			0x024ddcdf, 0x339b8ca0, 0x4c4af64a, 0x34fac605,
-			0x55d85839, 0x3a58997d, 0x2ec938e1, 0x66031581};
-
-		rss_conf.conf.key = (uint8_t *)rss_key_default;
-		rss_conf.conf.key_len = (I40E_PFQF_HKEY_MAX_INDEX + 1) *
-				sizeof(uint32_t);
-		PMD_DRV_LOG(INFO,
-			"No valid RSS key config for i40e, using default\n");
-	}
-
-	rss_conf.conf.types |= rss_info->conf.types;
-	i40e_rss_hash_set(pf, &rss_conf);
-
-	if (conf->conf.func == RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ)
-		i40e_rss_config_hash_function(pf, conf);
-
-	i40e_rss_mark_invalid_rule(pf, conf);
-
-	return 0;
-}
-
-/* Configure RSS queue region */
-static int
-i40e_rss_config_queue_region(struct i40e_pf *pf,
-		struct i40e_rte_flow_rss_conf *conf)
-{
-	struct i40e_hw *hw = I40E_PF_TO_HW(pf);
-	uint32_t lut = 0;
-	uint16_t j, num;
-	uint32_t i;
-
-	/* If both VMDQ and RSS enabled, not all of PF queues are configured.
-	 * It's necessary to calculate the actual PF queues that are configured.
-	 */
-	if (pf->dev_data->dev_conf.rxmode.mq_mode & ETH_MQ_RX_VMDQ_FLAG)
-		num = i40e_pf_calc_configured_queues_num(pf);
-	else
-		num = pf->dev_data->nb_rx_queues;
-
-	num = RTE_MIN(num, conf->conf.queue_num);
-	PMD_DRV_LOG(INFO, "Max of contiguous %u PF queues are configured",
-			num);
-
-	if (num == 0) {
-		PMD_DRV_LOG(ERR,
-			"No PF queues are configured to enable RSS for port %u",
-			pf->dev_data->port_id);
-		return -ENOTSUP;
-	}
-
-	/* Fill in redirection table */
-	for (i = 0, j = 0; i < hw->func_caps.rss_table_size; i++, j++) {
-		if (j == num)
-			j = 0;
-		lut = (lut << 8) | (conf->conf.queue[j] & ((0x1 <<
-			hw->func_caps.rss_table_entry_width) - 1));
-		if ((i & 3) == 3)
-			I40E_WRITE_REG(hw, I40E_PFQF_HLUT(i >> 2), lut);
-	}
-
-	i40e_rss_mark_invalid_rule(pf, conf);
-
-	return 0;
-}
-
-/* Configure RSS hash function to default */
-static int
-i40e_rss_clear_hash_function(struct i40e_pf *pf,
-		struct i40e_rte_flow_rss_conf *conf)
-{
-	struct i40e_hw *hw = I40E_PF_TO_HW(pf);
-	uint32_t i, reg;
-	uint64_t mask0;
-	uint16_t j;
-
-	if (conf->conf.func == RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) {
-		reg = i40e_read_rx_ctl(hw, I40E_GLQF_CTL);
-		if (reg & I40E_GLQF_CTL_HTOEP_MASK) {
-			PMD_DRV_LOG(DEBUG,
-				"Hash function already set to Toeplitz");
-			I40E_WRITE_FLUSH(hw);
-
-			return 0;
-		}
-		reg |= I40E_GLQF_CTL_HTOEP_MASK;
-
-		i40e_write_global_rx_ctl(hw, I40E_GLQF_CTL, reg);
-		I40E_WRITE_FLUSH(hw);
-	} else if (conf->conf.func ==
-		   RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ) {
-		mask0 = conf->conf.types & pf->adapter->flow_types_mask;
-
-		for (i = RTE_ETH_FLOW_UNKNOWN + 1; i < UINT64_BIT; i++) {
-			if (mask0 & (1UL << i))
-				break;
-		}
-
-		if (i == UINT64_BIT)
-			return -EINVAL;
-
-		for (j = I40E_FILTER_PCTYPE_INVALID + 1;
-		     j < I40E_FILTER_PCTYPE_MAX; j++) {
-			if (pf->adapter->pctypes_tbl[i] & (1ULL << j))
-				i40e_write_global_rx_ctl(hw,
-					I40E_GLQF_HSYM(j),
-					0);
-		}
-	}
-
-	return 0;
-}
-
-/* Disable RSS hash and configure default input set */
-static int
-i40e_rss_disable_hash(struct i40e_pf *pf,
-		struct i40e_rte_flow_rss_conf *conf)
-{
-	struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info;
-	struct i40e_hw *hw = I40E_PF_TO_HW(pf);
-	struct i40e_rte_flow_rss_conf rss_conf;
-	uint32_t i;
-
-	memset(&rss_conf, 0, sizeof(rss_conf));
-	rte_memcpy(&rss_conf, conf, sizeof(rss_conf));
-
-	/* Disable RSS hash */
-	rss_conf.conf.types = rss_info->conf.types & ~(conf->conf.types);
-	i40e_rss_hash_set(pf, &rss_conf);
-
-	for (i = RTE_ETH_FLOW_IPV4; i <= RTE_ETH_FLOW_L2_PAYLOAD; i++) {
-		if (!(pf->adapter->flow_types_mask & (1ULL << i)) ||
-		    !(conf->conf.types & (1ULL << i)))
-			continue;
-
-		/* Configure default input set */
-		struct rte_eth_input_set_conf input_conf = {
-			.op = RTE_ETH_INPUT_SET_SELECT,
-			.flow_type = i,
-			.inset_size = 1,
-		};
-		input_conf.field[0] = RTE_ETH_INPUT_SET_DEFAULT;
-		i40e_hash_filter_inset_select(hw, &input_conf);
-	}
-
-	rss_info->conf.types = rss_conf.conf.types;
-
-	i40e_rss_clear_hash_function(pf, conf);
-
-	return 0;
-}
-
-/* Configure RSS queue region to default */
-static int
-i40e_rss_clear_queue_region(struct i40e_pf *pf)
-{
-	struct i40e_hw *hw = I40E_PF_TO_HW(pf);
-	struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info;
-	uint16_t queue[I40E_MAX_Q_PER_TC];
-	uint32_t num_rxq, i;
-	uint32_t lut = 0;
-	uint16_t j, num;
-
-	num_rxq = RTE_MIN(pf->dev_data->nb_rx_queues, I40E_MAX_Q_PER_TC);
-
-	for (j = 0; j < num_rxq; j++)
-		queue[j] = j;
-
-	/* If both VMDQ and RSS enabled, not all of PF queues are configured.
-	 * It's necessary to calculate the actual PF queues that are configured.
-	 */
-	if (pf->dev_data->dev_conf.rxmode.mq_mode & ETH_MQ_RX_VMDQ_FLAG)
-		num = i40e_pf_calc_configured_queues_num(pf);
-	else
-		num = pf->dev_data->nb_rx_queues;
-
-	num = RTE_MIN(num, num_rxq);
-	PMD_DRV_LOG(INFO, "Max of contiguous %u PF queues are configured",
-			num);
-
-	if (num == 0) {
-		PMD_DRV_LOG(ERR,
-			"No PF queues are configured to enable RSS for port %u",
-			pf->dev_data->port_id);
-		return -ENOTSUP;
-	}
-
-	/* Fill in redirection table */
-	for (i = 0, j = 0; i < hw->func_caps.rss_table_size; i++, j++) {
-		if (j == num)
-			j = 0;
-		lut = (lut << 8) | (queue[j] & ((0x1 <<
-			hw->func_caps.rss_table_entry_width) - 1));
-		if ((i & 3) == 3)
-			I40E_WRITE_REG(hw, I40E_PFQF_HLUT(i >> 2), lut);
-	}
-
-	rss_info->conf.queue_num = 0;
-	memset(&rss_info->conf.queue, 0, sizeof(uint16_t));
-
-	return 0;
-}
-
-int
-i40e_config_rss_filter(struct i40e_pf *pf,
-		struct i40e_rte_flow_rss_conf *conf, bool add)
-{
-	struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info;
-	struct rte_flow_action_rss update_conf = rss_info->conf;
-	int ret = 0;
-
-	if (add) {
-		if (conf->conf.queue_num) {
-			/* Configure RSS queue region */
-			ret = i40e_rss_config_queue_region(pf, conf);
-			if (ret)
-				return ret;
-
-			update_conf.queue_num = conf->conf.queue_num;
-			update_conf.queue = conf->conf.queue;
-		} else if (conf->conf.func ==
-			   RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) {
-			/* Configure hash function */
-			ret = i40e_rss_config_hash_function(pf, conf);
-			if (ret)
-				return ret;
-
-			update_conf.func = conf->conf.func;
-		} else {
-			/* Configure hash enable and input set */
-			ret = i40e_rss_enable_hash(pf, conf);
-			if (ret)
-				return ret;
-
-			update_conf.types |= conf->conf.types;
-			update_conf.key = conf->conf.key;
-			update_conf.key_len = conf->conf.key_len;
-		}
-
-		/* Update RSS info in pf */
-		if (i40e_rss_conf_init(rss_info, &update_conf))
-			return -EINVAL;
-	} else {
-		if (!conf->valid)
-			return 0;
-
-		if (conf->conf.queue_num)
-			i40e_rss_clear_queue_region(pf);
-		else if (conf->conf.func == RTE_ETH_HASH_FUNCTION_SIMPLE_XOR)
-			i40e_rss_clear_hash_function(pf, conf);
-		else
-			i40e_rss_disable_hash(pf, conf);
-	}
-
-	return 0;
-}
-
 RTE_LOG_REGISTER(i40e_logtype_init, pmd.net.i40e.init, NOTICE);
 RTE_LOG_REGISTER(i40e_logtype_driver, pmd.net.i40e.driver, NOTICE);
 #ifdef RTE_LIBRTE_I40E_DEBUG_RX
diff --git a/drivers/net/i40e/i40e_ethdev.h b/drivers/net/i40e/i40e_ethdev.h
index 1466998..4c84965 100644
--- a/drivers/net/i40e/i40e_ethdev.h
+++ b/drivers/net/i40e/i40e_ethdev.h
@@ -16,6 +16,8 @@
 #include "rte_pmd_i40e.h"
 
 #include "base/i40e_register.h"
+#include "base/i40e_type.h"
+#include "base/virtchnl.h"
 
 #define I40E_VLAN_TAG_SIZE        4
 
@@ -1047,17 +1049,24 @@ struct i40e_customized_pctype {
 	bool valid;   /* Check if it's valid */
 };
 
+#define I40E_MAX_PCTYPE_PER_RSS		8
+
 struct i40e_rte_flow_rss_conf {
-	struct rte_flow_action_rss conf; /**< RSS parameters. */
-	uint16_t queue_region_conf; /**< Queue region config flag */
+	struct rte_flow_action_rss conf;	/**< RSS parameters. */
+
 	uint8_t key[(I40E_VFQF_HKEY_MAX_INDEX > I40E_PFQF_HKEY_MAX_INDEX ?
 		     I40E_VFQF_HKEY_MAX_INDEX : I40E_PFQF_HKEY_MAX_INDEX + 1) *
-		    sizeof(uint32_t)]; /* Hash key. */
-	uint16_t queue[I40E_MAX_Q_PER_TC]; /**< Queues indices to use. */
-	bool valid; /* Check if it's valid */
-};
+		    sizeof(uint32_t)];		/**< Hash key. */
+	uint16_t queue[ETH_RSS_RETA_SIZE_512];	/**< Queues indices to use. */
 
-TAILQ_HEAD(i40e_rss_conf_list, i40e_rss_filter);
+	uint8_t pctypes[I40E_MAX_PCTYPE_PER_RSS];
+	uint8_t pctype_count;
+
+	uint8_t region_flags;	/**< configure a queue region, yes(1)/no(0) */
+	uint8_t region_priority;/**< queue region priority */
+	uint8_t region_queue_num;
+	uint16_t region_queue_start;
+};
 
 /* RSS filter list structure */
 struct i40e_rss_filter {
@@ -1065,6 +1074,8 @@ struct i40e_rss_filter {
 	struct i40e_rte_flow_rss_conf rss_filter_info;
 };
 
+TAILQ_HEAD(i40e_rss_conf_list, i40e_rss_filter);
+
 struct i40e_vf_msg_cfg {
 	/* maximal VF message during a statistic period */
 	uint32_t max_msg;
@@ -1119,6 +1130,7 @@ struct i40e_pf {
 	uint16_t fdir_qp_offset;
 
 	uint16_t hash_lut_size; /* The size of hash lookup table */
+	uint64_t hash_enabled_queues;
 	/* input set bits for each pctype */
 	uint64_t hash_input_set[I40E_FILTER_PCTYPE_MAX];
 	/* store VXLAN UDP ports */
@@ -1133,7 +1145,6 @@ struct i40e_pf {
 	struct i40e_fdir_info fdir; /* flow director info */
 	struct i40e_ethertype_rule ethertype; /* Ethertype filter rule */
 	struct i40e_tunnel_rule tunnel; /* Tunnel filter rule */
-	struct i40e_rte_flow_rss_conf rss_info; /* RSS info */
 	struct i40e_rss_conf_list rss_config_list; /* RSS rule list */
 	struct i40e_queue_regions queue_region; /* queue region info */
 	struct i40e_fc_conf fc_conf; /* Flow control conf */
@@ -1151,7 +1162,7 @@ struct i40e_pf {
 	bool dport_replace_flag;   /* Destination port replace is done */
 	struct i40e_tm_conf tm_conf;
 	bool support_multi_driver; /* 1 - support multiple driver */
-
+	bool hash_filter_enable;
 	/* Dynamic Device Personalization */
 	bool gtp_support; /* 1 - support GTP-C and GTP-U */
 	bool esp_support; /* 1 - support ESP SPI */
@@ -1364,6 +1375,8 @@ int i40e_select_filter_input_set(struct i40e_hw *hw,
 				 struct rte_eth_input_set_conf *conf,
 				 enum rte_filter_type filter);
 void i40e_fdir_filter_restore(struct i40e_pf *pf);
+int i40e_set_hash_inset(struct i40e_hw *hw, uint64_t input_set,
+			uint32_t pctype, bool add);
 int i40e_hash_filter_inset_select(struct i40e_hw *hw,
 			     struct rte_eth_input_set_conf *conf);
 int i40e_fdir_filter_inset_select(struct i40e_pf *pf,
@@ -1425,7 +1438,8 @@ int i40e_add_macvlan_filters(struct i40e_vsi *vsi,
 bool is_device_supported(struct rte_eth_dev *dev, struct rte_pci_driver *drv);
 bool is_i40e_supported(struct rte_eth_dev *dev);
 bool is_i40evf_supported(struct rte_eth_dev *dev);
-
+void i40e_set_symmetric_hash_enable_per_port(struct i40e_hw *hw,
+					     uint8_t enable);
 int i40e_validate_input_set(enum i40e_filter_pctype pctype,
 			    enum rte_filter_type filter, uint64_t inset);
 int i40e_generate_inset_mask_reg(uint64_t inset, uint32_t *mask,
@@ -1448,12 +1462,13 @@ int i40e_flush_queue_region_all_conf(struct rte_eth_dev *dev,
 		struct i40e_hw *hw, struct i40e_pf *pf, uint16_t on);
 void i40e_init_queue_region_conf(struct rte_eth_dev *dev);
 void i40e_flex_payload_reg_set_default(struct i40e_hw *hw);
+void i40e_pf_disable_rss(struct i40e_pf *pf);
+int i40e_pf_calc_configured_queues_num(struct i40e_pf *pf);
+int i40e_pf_reset_rss_reta(struct i40e_pf *pf);
+int i40e_pf_reset_rss_key(struct i40e_pf *pf);
+int i40e_pf_config_rss(struct i40e_pf *pf);
 int i40e_set_rss_key(struct i40e_vsi *vsi, uint8_t *key, uint8_t key_len);
 int i40e_set_rss_lut(struct i40e_vsi *vsi, uint8_t *lut, uint16_t lut_size);
-int i40e_rss_conf_init(struct i40e_rte_flow_rss_conf *out,
-		       const struct rte_flow_action_rss *in);
-int i40e_config_rss_filter(struct i40e_pf *pf,
-		struct i40e_rte_flow_rss_conf *conf, bool add);
 int i40e_vf_representor_init(struct rte_eth_dev *ethdev, void *init_params);
 int i40e_vf_representor_uninit(struct rte_eth_dev *ethdev);
 
diff --git a/drivers/net/i40e/i40e_flow.c b/drivers/net/i40e/i40e_flow.c
index adc5da1..e5fe912 100644
--- a/drivers/net/i40e/i40e_flow.c
+++ b/drivers/net/i40e/i40e_flow.c
@@ -23,6 +23,7 @@
 #include "base/i40e_type.h"
 #include "base/i40e_prototype.h"
 #include "i40e_ethdev.h"
+#include "i40e_hash.h"
 
 #define I40E_IPV6_TC_MASK	(0xFF << I40E_FDIR_IPv6_TC_OFFSET)
 #define I40E_IPV6_FRAG_HEADER	44
@@ -115,7 +116,6 @@ static int i40e_flow_destroy_tunnel_filter(struct i40e_pf *pf,
 static int i40e_flow_flush_fdir_filter(struct i40e_pf *pf);
 static int i40e_flow_flush_ethertype_filter(struct i40e_pf *pf);
 static int i40e_flow_flush_tunnel_filter(struct i40e_pf *pf);
-static int i40e_flow_flush_rss_filter(struct rte_eth_dev *dev);
 static int
 i40e_flow_parse_qinq_filter(struct rte_eth_dev *dev,
 			      const struct rte_flow_attr *attr,
@@ -4699,566 +4699,6 @@ static int i40e_flow_parse_l4_cloud_filter(struct rte_eth_dev *dev,
 	return ret;
 }
 
-/**
- * This function is used to do configuration i40e existing RSS with rte_flow.
- * It also enable queue region configuration using flow API for i40e.
- * pattern can be used indicate what parameters will be include in flow,
- * like user_priority or flowtype for queue region or HASH function for RSS.
- * Action is used to transmit parameter like queue index and HASH
- * function for RSS, or flowtype for queue region configuration.
- * For example:
- * pattern:
- * Case 1: try to transform patterns to pctype. valid pctype will be
- *         used in parse action.
- * Case 2: only ETH, indicate flowtype for queue region will be parsed.
- * Case 3: only VLAN, indicate user_priority for queue region will be parsed.
- * So, pattern choice is depened on the purpose of configuration of
- * that flow.
- * action:
- * action RSS will be used to transmit valid parameter with
- * struct rte_flow_action_rss for all the 3 case.
- */
-static int
-i40e_flow_parse_rss_pattern(__rte_unused struct rte_eth_dev *dev,
-			     const struct rte_flow_item *pattern,
-			     struct rte_flow_error *error,
-			     struct i40e_rss_pattern_info *p_info,
-			     struct i40e_queue_regions *info)
-{
-	const struct rte_flow_item_vlan *vlan_spec, *vlan_mask;
-	const struct rte_flow_item *item = pattern;
-	enum rte_flow_item_type item_type;
-	struct rte_flow_item *items;
-	uint32_t item_num = 0; /* non-void item number of pattern*/
-	uint32_t i = 0;
-	static const struct {
-		enum rte_flow_item_type *item_array;
-		uint64_t type;
-	} i40e_rss_pctype_patterns[] = {
-		{ pattern_fdir_ipv4,
-			ETH_RSS_FRAG_IPV4 | ETH_RSS_NONFRAG_IPV4_OTHER },
-		{ pattern_fdir_ipv4_tcp, ETH_RSS_NONFRAG_IPV4_TCP },
-		{ pattern_fdir_ipv4_udp, ETH_RSS_NONFRAG_IPV4_UDP },
-		{ pattern_fdir_ipv4_sctp, ETH_RSS_NONFRAG_IPV4_SCTP },
-		{ pattern_fdir_ipv4_esp, ETH_RSS_ESP },
-		{ pattern_fdir_ipv4_udp_esp, ETH_RSS_ESP },
-		{ pattern_fdir_ipv6,
-			ETH_RSS_FRAG_IPV6 | ETH_RSS_NONFRAG_IPV6_OTHER },
-		{ pattern_fdir_ipv6_tcp, ETH_RSS_NONFRAG_IPV6_TCP },
-		{ pattern_fdir_ipv6_udp, ETH_RSS_NONFRAG_IPV6_UDP },
-		{ pattern_fdir_ipv6_sctp, ETH_RSS_NONFRAG_IPV6_SCTP },
-		{ pattern_ethertype, ETH_RSS_L2_PAYLOAD },
-		{ pattern_fdir_ipv6_esp, ETH_RSS_ESP },
-		{ pattern_fdir_ipv6_udp_esp, ETH_RSS_ESP },
-	};
-
-	p_info->types = I40E_RSS_TYPE_INVALID;
-
-	if (item->type == RTE_FLOW_ITEM_TYPE_END) {
-		p_info->types = I40E_RSS_TYPE_NONE;
-		return 0;
-	}
-
-	/* Convert pattern to RSS offload types */
-	while ((pattern + i)->type != RTE_FLOW_ITEM_TYPE_END) {
-		if ((pattern + i)->type != RTE_FLOW_ITEM_TYPE_VOID)
-			item_num++;
-		i++;
-	}
-	item_num++;
-
-	items = rte_zmalloc("i40e_pattern",
-			    item_num * sizeof(struct rte_flow_item), 0);
-	if (!items) {
-		rte_flow_error_set(error, ENOMEM, RTE_FLOW_ERROR_TYPE_ITEM_NUM,
-				   NULL, "No memory for PMD internal items.");
-		return -ENOMEM;
-	}
-
-	i40e_pattern_skip_void_item(items, pattern);
-
-	for (i = 0; i < RTE_DIM(i40e_rss_pctype_patterns); i++) {
-		if (i40e_match_pattern(i40e_rss_pctype_patterns[i].item_array,
-					items)) {
-			p_info->types = i40e_rss_pctype_patterns[i].type;
-			break;
-		}
-	}
-
-	rte_free(items);
-
-	for (; item->type != RTE_FLOW_ITEM_TYPE_END; item++) {
-		if (item->last) {
-			rte_flow_error_set(error, EINVAL,
-					   RTE_FLOW_ERROR_TYPE_ITEM,
-					   item,
-					   "Not support range");
-			return -rte_errno;
-		}
-		item_type = item->type;
-		switch (item_type) {
-		case RTE_FLOW_ITEM_TYPE_ETH:
-			p_info->action_flag = 1;
-			break;
-		case RTE_FLOW_ITEM_TYPE_VLAN:
-			vlan_spec = item->spec;
-			vlan_mask = item->mask;
-			if (vlan_spec && vlan_mask) {
-				if (vlan_mask->tci ==
-					rte_cpu_to_be_16(I40E_TCI_MASK)) {
-					info->region[0].user_priority[0] =
-						(rte_be_to_cpu_16(
-						vlan_spec->tci) >> 13) & 0x7;
-					info->region[0].user_priority_num = 1;
-					info->queue_region_number = 1;
-					p_info->action_flag = 0;
-				}
-			}
-			break;
-		default:
-			p_info->action_flag = 0;
-			memset(info, 0, sizeof(struct i40e_queue_regions));
-			return 0;
-		}
-	}
-
-	return 0;
-}
-
-/**
- * This function is used to parse RSS queue index, total queue number and
- * hash functions, If the purpose of this configuration is for queue region
- * configuration, it will set queue_region_conf flag to TRUE, else to FALSE.
- * In queue region configuration, it also need to parse hardware flowtype
- * and user_priority from configuration, it will also cheeck the validity
- * of these parameters. For example, The queue region sizes should
- * be any of the following values: 1, 2, 4, 8, 16, 32, 64, the
- * hw_flowtype or PCTYPE max index should be 63, the user priority
- * max index should be 7, and so on. And also, queue index should be
- * continuous sequence and queue region index should be part of RSS
- * queue index for this port.
- * For hash params, the pctype in action and pattern must be same.
- * Set queue index must be with non-types.
- */
-static int
-i40e_flow_parse_rss_action(struct rte_eth_dev *dev,
-			    const struct rte_flow_action *actions,
-			    struct rte_flow_error *error,
-				struct i40e_rss_pattern_info p_info,
-			    struct i40e_queue_regions *conf_info,
-			    union i40e_filter_t *filter)
-{
-	const struct rte_flow_action *act;
-	const struct rte_flow_action_rss *rss;
-	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
-	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-	struct i40e_queue_regions *info = &pf->queue_region;
-	struct i40e_rte_flow_rss_conf *rss_config =
-			&filter->rss_conf;
-	struct i40e_rte_flow_rss_conf *rss_info = &pf->rss_info;
-	uint16_t i, j, n, m, tmp, nb_types;
-	uint32_t index = 0;
-	uint64_t hf_bit = 1;
-
-	static const struct {
-		uint64_t rss_type;
-		enum i40e_filter_pctype pctype;
-	} pctype_match_table[] = {
-		{ETH_RSS_FRAG_IPV4,
-			I40E_FILTER_PCTYPE_FRAG_IPV4},
-		{ETH_RSS_NONFRAG_IPV4_TCP,
-			I40E_FILTER_PCTYPE_NONF_IPV4_TCP},
-		{ETH_RSS_NONFRAG_IPV4_UDP,
-			I40E_FILTER_PCTYPE_NONF_IPV4_UDP},
-		{ETH_RSS_NONFRAG_IPV4_SCTP,
-			I40E_FILTER_PCTYPE_NONF_IPV4_SCTP},
-		{ETH_RSS_NONFRAG_IPV4_OTHER,
-			I40E_FILTER_PCTYPE_NONF_IPV4_OTHER},
-		{ETH_RSS_FRAG_IPV6,
-			I40E_FILTER_PCTYPE_FRAG_IPV6},
-		{ETH_RSS_NONFRAG_IPV6_TCP,
-			I40E_FILTER_PCTYPE_NONF_IPV6_TCP},
-		{ETH_RSS_NONFRAG_IPV6_UDP,
-			I40E_FILTER_PCTYPE_NONF_IPV6_UDP},
-		{ETH_RSS_NONFRAG_IPV6_SCTP,
-			I40E_FILTER_PCTYPE_NONF_IPV6_SCTP},
-		{ETH_RSS_NONFRAG_IPV6_OTHER,
-			I40E_FILTER_PCTYPE_NONF_IPV6_OTHER},
-		{ETH_RSS_L2_PAYLOAD,
-			I40E_FILTER_PCTYPE_L2_PAYLOAD},
-	};
-
-	static const struct {
-		uint64_t rss_type;
-		enum i40e_filter_pctype pctype;
-	} pctype_match_table_x722[] = {
-		{ETH_RSS_NONFRAG_IPV4_TCP,
-			I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK},
-		{ETH_RSS_NONFRAG_IPV4_UDP,
-			I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP},
-		{ETH_RSS_NONFRAG_IPV4_UDP,
-			I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP},
-		{ETH_RSS_NONFRAG_IPV6_TCP,
-			I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK},
-		{ETH_RSS_NONFRAG_IPV6_UDP,
-			I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP},
-		{ETH_RSS_NONFRAG_IPV6_UDP,
-			I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP},
-	};
-
-	NEXT_ITEM_OF_ACTION(act, actions, index);
-	rss = act->conf;
-
-	/**
-	 * RSS only supports forwarding,
-	 * check if the first not void action is RSS.
-	 */
-	if (act->type != RTE_FLOW_ACTION_TYPE_RSS) {
-		memset(rss_config, 0, sizeof(struct i40e_rte_flow_rss_conf));
-		rte_flow_error_set(error, EINVAL,
-			RTE_FLOW_ERROR_TYPE_ACTION,
-			act, "Not supported action.");
-		return -rte_errno;
-	}
-
-	if (p_info.action_flag && rss->queue_num) {
-		for (j = 0; j < RTE_DIM(pctype_match_table); j++) {
-			if (rss->types & pctype_match_table[j].rss_type) {
-				conf_info->region[0].hw_flowtype[0] =
-					(uint8_t)pctype_match_table[j].pctype;
-				conf_info->region[0].flowtype_num = 1;
-				conf_info->queue_region_number = 1;
-				break;
-			}
-		}
-
-		if (hw->mac.type == I40E_MAC_X722)
-			for (j = 0; j < RTE_DIM(pctype_match_table_x722); j++) {
-				if (rss->types &
-				    pctype_match_table_x722[j].rss_type) {
-					m = conf_info->region[0].flowtype_num;
-					conf_info->region[0].hw_flowtype[m] =
-						pctype_match_table_x722[j].pctype;
-					conf_info->region[0].flowtype_num++;
-					conf_info->queue_region_number = 1;
-				}
-			}
-	}
-
-	/**
-	 * Do some queue region related parameters check
-	 * in order to keep queue index for queue region to be
-	 * continuous sequence and also to be part of RSS
-	 * queue index for this port.
-	 */
-	if (conf_info->queue_region_number) {
-		for (i = 0; i < rss->queue_num; i++) {
-			for (j = 0; j < rss_info->conf.queue_num; j++) {
-				if (rss->queue[i] == rss_info->conf.queue[j])
-					break;
-			}
-			if (j == rss_info->conf.queue_num) {
-				rte_flow_error_set(error, EINVAL,
-					RTE_FLOW_ERROR_TYPE_ACTION,
-					act,
-					"no valid queues");
-				return -rte_errno;
-			}
-		}
-
-		for (i = 0; i < rss->queue_num - 1; i++) {
-			if (rss->queue[i + 1] != rss->queue[i] + 1) {
-				rte_flow_error_set(error, EINVAL,
-					RTE_FLOW_ERROR_TYPE_ACTION,
-					act,
-					"no valid queues");
-				return -rte_errno;
-			}
-		}
-	}
-
-	/* Parse queue region related parameters from configuration */
-	for (n = 0; n < conf_info->queue_region_number; n++) {
-		if (conf_info->region[n].user_priority_num ||
-				conf_info->region[n].flowtype_num) {
-			if (!((rte_is_power_of_2(rss->queue_num)) &&
-					rss->queue_num <= 64)) {
-				rte_flow_error_set(error, EINVAL,
-					RTE_FLOW_ERROR_TYPE_ACTION,
-					act,
-					"The region sizes should be any of the following values: 1, 2, 4, 8, 16, 32, 64 as long as the "
-					"total number of queues do not exceed the VSI allocation");
-				return -rte_errno;
-			}
-
-			if (conf_info->region[n].user_priority[n] >=
-					I40E_MAX_USER_PRIORITY) {
-				rte_flow_error_set(error, EINVAL,
-					RTE_FLOW_ERROR_TYPE_ACTION,
-					act,
-					"the user priority max index is 7");
-				return -rte_errno;
-			}
-
-			if (conf_info->region[n].hw_flowtype[n] >=
-					I40E_FILTER_PCTYPE_MAX) {
-				rte_flow_error_set(error, EINVAL,
-					RTE_FLOW_ERROR_TYPE_ACTION,
-					act,
-					"the hw_flowtype or PCTYPE max index is 63");
-				return -rte_errno;
-			}
-
-			for (i = 0; i < info->queue_region_number; i++) {
-				if (info->region[i].queue_num ==
-				    rss->queue_num &&
-					info->region[i].queue_start_index ==
-						rss->queue[0])
-					break;
-			}
-
-			if (i == info->queue_region_number) {
-				if (i > I40E_REGION_MAX_INDEX) {
-					rte_flow_error_set(error, EINVAL,
-						RTE_FLOW_ERROR_TYPE_ACTION,
-						act,
-						"the queue region max index is 7");
-					return -rte_errno;
-				}
-
-				info->region[i].queue_num =
-					rss->queue_num;
-				info->region[i].queue_start_index =
-					rss->queue[0];
-				info->region[i].region_id =
-					info->queue_region_number;
-
-				j = info->region[i].user_priority_num;
-				tmp = conf_info->region[n].user_priority[0];
-				if (conf_info->region[n].user_priority_num) {
-					info->region[i].user_priority[j] = tmp;
-					info->region[i].user_priority_num++;
-				}
-
-				for (m = 0; m < conf_info->region[n].flowtype_num; m++) {
-					j = info->region[i].flowtype_num;
-					tmp = conf_info->region[n].hw_flowtype[m];
-					info->region[i].hw_flowtype[j] = tmp;
-					info->region[i].flowtype_num++;
-				}
-				info->queue_region_number++;
-			} else {
-				j = info->region[i].user_priority_num;
-				tmp = conf_info->region[n].user_priority[0];
-				if (conf_info->region[n].user_priority_num) {
-					info->region[i].user_priority[j] = tmp;
-					info->region[i].user_priority_num++;
-				}
-
-				for (m = 0; m < conf_info->region[n].flowtype_num; m++) {
-					j = info->region[i].flowtype_num;
-					tmp = conf_info->region[n].hw_flowtype[m];
-					info->region[i].hw_flowtype[j] = tmp;
-					info->region[i].flowtype_num++;
-				}
-			}
-		}
-
-		rss_config->queue_region_conf = TRUE;
-	}
-
-	/**
-	 * Return function if this flow is used for queue region configuration
-	 */
-	if (rss_config->queue_region_conf)
-		return 0;
-
-	if (!rss) {
-		rte_flow_error_set(error, EINVAL,
-				RTE_FLOW_ERROR_TYPE_ACTION,
-				act,
-				"invalid rule");
-		return -rte_errno;
-	}
-
-	for (n = 0; n < rss->queue_num; n++) {
-		if (rss->queue[n] >= dev->data->nb_rx_queues) {
-			rte_flow_error_set(error, EINVAL,
-				   RTE_FLOW_ERROR_TYPE_ACTION,
-				   act,
-				   "queue id > max number of queues");
-			return -rte_errno;
-		}
-	}
-
-	if (rss->queue_num && (p_info.types || rss->types))
-		return rte_flow_error_set
-			(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act,
-			 "RSS types must be empty while configuring queue region");
-
-	/* validate pattern and pctype */
-	if (!(rss->types & p_info.types) &&
-	    (rss->types || p_info.types) && !rss->queue_num)
-		return rte_flow_error_set
-			(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION,
-			 act, "invalid pctype");
-
-	nb_types = 0;
-	for (n = 0; n < RTE_ETH_FLOW_MAX; n++) {
-		if (rss->types & (hf_bit << n))
-			nb_types++;
-		if (nb_types > 1)
-			return rte_flow_error_set
-				(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION,
-				 act, "multi pctype is not supported");
-	}
-
-	if (rss->func == RTE_ETH_HASH_FUNCTION_SIMPLE_XOR &&
-	    (p_info.types || rss->types || rss->queue_num))
-		return rte_flow_error_set
-			(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act,
-			 "pattern, type and queues must be empty while"
-			 " setting hash function as simple_xor");
-
-	if (rss->func == RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ &&
-	    !(p_info.types && rss->types))
-		return rte_flow_error_set
-			(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act,
-			 "pctype and queues can not be empty while"
-			 " setting hash function as symmetric toeplitz");
-
-	/* Parse RSS related parameters from configuration */
-	if (rss->func >= RTE_ETH_HASH_FUNCTION_MAX ||
-	    rss->func == RTE_ETH_HASH_FUNCTION_TOEPLITZ)
-		return rte_flow_error_set
-			(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act,
-			 "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_config->key))
-		return rte_flow_error_set
-			(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act,
-			 "RSS hash key too large");
-	if (rss->queue_num > RTE_DIM(rss_config->queue))
-		return rte_flow_error_set
-			(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ACTION, act,
-			 "too many queues for RSS context");
-	if (i40e_rss_conf_init(rss_config, rss))
-		return rte_flow_error_set
-			(error, EINVAL, RTE_FLOW_ERROR_TYPE_ACTION, act,
-			 "RSS context initialization failure");
-
-	index++;
-
-	/* check if the next not void action is END */
-	NEXT_ITEM_OF_ACTION(act, actions, index);
-	if (act->type != RTE_FLOW_ACTION_TYPE_END) {
-		memset(rss_config, 0, sizeof(struct i40e_rte_flow_rss_conf));
-		rte_flow_error_set(error, EINVAL,
-			RTE_FLOW_ERROR_TYPE_ACTION,
-			act, "Not supported action.");
-		return -rte_errno;
-	}
-	rss_config->queue_region_conf = FALSE;
-
-	return 0;
-}
-
-static int
-i40e_parse_rss_filter(struct rte_eth_dev *dev,
-			const struct rte_flow_attr *attr,
-			const struct rte_flow_item pattern[],
-			const struct rte_flow_action actions[],
-			union i40e_filter_t *filter,
-			struct rte_flow_error *error)
-{
-	struct i40e_rss_pattern_info p_info;
-	struct i40e_queue_regions info;
-	int ret;
-
-	memset(&info, 0, sizeof(struct i40e_queue_regions));
-	memset(&p_info, 0, sizeof(struct i40e_rss_pattern_info));
-
-	ret = i40e_flow_parse_rss_pattern(dev, pattern,
-					error, &p_info, &info);
-	if (ret)
-		return ret;
-
-	ret = i40e_flow_parse_rss_action(dev, actions, error,
-					p_info, &info, filter);
-	if (ret)
-		return ret;
-
-	ret = i40e_flow_parse_attr(attr, error);
-	if (ret)
-		return ret;
-
-	cons_filter_type = RTE_ETH_FILTER_HASH;
-
-	return 0;
-}
-
-static int
-i40e_config_rss_filter_set(struct rte_eth_dev *dev,
-		struct i40e_rte_flow_rss_conf *conf)
-{
-	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
-	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-	struct i40e_rss_filter *rss_filter;
-	int ret;
-
-	if (conf->queue_region_conf) {
-		ret = i40e_flush_queue_region_all_conf(dev, hw, pf, 1);
-	} else {
-		ret = i40e_config_rss_filter(pf, conf, 1);
-	}
-
-	if (ret)
-		return ret;
-
-	rss_filter = rte_zmalloc("i40e_rss_filter",
-				sizeof(*rss_filter), 0);
-	if (rss_filter == NULL) {
-		PMD_DRV_LOG(ERR, "Failed to alloc memory.");
-		return -ENOMEM;
-	}
-	rss_filter->rss_filter_info = *conf;
-	/* the rule new created is always valid
-	 * the existing rule covered by new rule will be set invalid
-	 */
-	rss_filter->rss_filter_info.valid = true;
-
-	TAILQ_INSERT_TAIL(&pf->rss_config_list, rss_filter, next);
-
-	return 0;
-}
-
-static int
-i40e_config_rss_filter_del(struct rte_eth_dev *dev,
-		struct i40e_rte_flow_rss_conf *conf)
-{
-	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
-	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-	struct i40e_rss_filter *rss_filter;
-	void *temp;
-
-	if (conf->queue_region_conf)
-		i40e_flush_queue_region_all_conf(dev, hw, pf, 0);
-	else
-		i40e_config_rss_filter(pf, conf, 0);
-
-	TAILQ_FOREACH_SAFE(rss_filter, &pf->rss_config_list, next, temp) {
-		if (!memcmp(&rss_filter->rss_filter_info, conf,
-			sizeof(struct rte_flow_action_rss))) {
-			TAILQ_REMOVE(&pf->rss_config_list, rss_filter, next);
-			rte_free(rss_filter);
-		}
-	}
-	return 0;
-}
-
 static int
 i40e_flow_validate(struct rte_eth_dev *dev,
 		   const struct rte_flow_attr *attr,
@@ -5299,9 +4739,13 @@ static int i40e_flow_parse_l4_cloud_filter(struct rte_eth_dev *dev,
 		i++;
 
 	if ((actions + i)->type == RTE_FLOW_ACTION_TYPE_RSS) {
-		ret = i40e_parse_rss_filter(dev, attr, pattern,
-					actions, &cons_filter, error);
-		return ret;
+		ret = i40e_flow_parse_attr(attr, error);
+		if (ret)
+			return ret;
+
+		cons_filter_type = RTE_ETH_FILTER_HASH;
+		return i40e_hash_parse(dev, pattern, actions + i,
+				       &cons_filter.rss_conf, error);
 	}
 
 	i = 0;
@@ -5416,12 +4860,11 @@ static int i40e_flow_parse_l4_cloud_filter(struct rte_eth_dev *dev,
 					i40e_tunnel_filter_list);
 		break;
 	case RTE_ETH_FILTER_HASH:
-		ret = i40e_config_rss_filter_set(dev,
-			    &cons_filter.rss_conf);
+		ret = i40e_hash_filter_create(pf, &cons_filter.rss_conf);
 		if (ret)
 			goto free_flow;
 		flow->rule = TAILQ_LAST(&pf->rss_config_list,
-				i40e_rss_conf_list);
+					i40e_rss_conf_list);
 		break;
 	default:
 		goto free_flow;
@@ -5474,8 +4917,7 @@ static int i40e_flow_parse_l4_cloud_filter(struct rte_eth_dev *dev,
 		}
 		break;
 	case RTE_ETH_FILTER_HASH:
-		ret = i40e_config_rss_filter_del(dev,
-			&((struct i40e_rss_filter *)flow->rule)->rss_filter_info);
+		ret = i40e_hash_filter_destroy(pf, flow->rule);
 		break;
 	default:
 		PMD_DRV_LOG(WARNING, "Filter type (%d) not supported",
@@ -5623,14 +5065,11 @@ static int i40e_flow_parse_l4_cloud_filter(struct rte_eth_dev *dev,
 		return -rte_errno;
 	}
 
-	ret = i40e_flow_flush_rss_filter(dev);
-	if (ret) {
+	ret = i40e_hash_filter_flush(pf);
+	if (ret)
 		rte_flow_error_set(error, -ret,
 				   RTE_FLOW_ERROR_TYPE_HANDLE, NULL,
 				   "Failed to flush RSS flows.");
-		return -rte_errno;
-	}
-
 	return ret;
 }
 
@@ -5747,36 +5186,6 @@ static int i40e_flow_parse_l4_cloud_filter(struct rte_eth_dev *dev,
 	return ret;
 }
 
-/* remove the RSS filter */
-static int
-i40e_flow_flush_rss_filter(struct rte_eth_dev *dev)
-{
-	struct i40e_pf *pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
-	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-	struct rte_flow *flow;
-	void *temp;
-	int32_t ret = -EINVAL;
-
-	ret = i40e_flush_queue_region_all_conf(dev, hw, pf, 0);
-
-	/* Delete RSS flows in flow list. */
-	TAILQ_FOREACH_SAFE(flow, &pf->flow_list, node, temp) {
-		if (flow->filter_type != RTE_ETH_FILTER_HASH)
-			continue;
-
-		if (flow->rule) {
-			ret = i40e_config_rss_filter_del(dev,
-				&((struct i40e_rss_filter *)flow->rule)->rss_filter_info);
-			if (ret)
-				return ret;
-		}
-		TAILQ_REMOVE(&pf->flow_list, flow, node);
-		rte_free(flow);
-	}
-
-	return ret;
-}
-
 static int
 i40e_flow_query(struct rte_eth_dev *dev __rte_unused,
 		struct rte_flow *flow,
diff --git a/drivers/net/i40e/i40e_hash.c b/drivers/net/i40e/i40e_hash.c
new file mode 100644
index 0000000..4e23984
--- /dev/null
+++ b/drivers/net/i40e/i40e_hash.c
@@ -0,0 +1,1315 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#include <sys/queue.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+
+#include <rte_malloc.h>
+#include <rte_tailq.h>
+#include "base/i40e_prototype.h"
+#include "i40e_logs.h"
+#include "i40e_ethdev.h"
+#include "i40e_hash.h"
+
+#ifndef BIT
+#define BIT(n)				(1UL << (n))
+#endif
+
+#ifndef BIT_ULL
+#define BIT_ULL(n)			(1ULL << (n))
+#endif
+
+#define I40E_TCI_MASK			0xFFFF
+
+/* Pattern item headers */
+#define I40E_HASH_HDR_ETH		0x01ULL
+#define I40E_HASH_HDR_IPV4		0x10ULL
+#define I40E_HASH_HDR_IPV6		0x20ULL
+#define I40E_HASH_HDR_TCP		0x100ULL
+#define I40E_HASH_HDR_UDP		0x200ULL
+#define I40E_HASH_HDR_SCTP		0x400ULL
+#define I40E_HASH_HDR_ESP		0x10000ULL
+#define I40E_HASH_HDR_L2TPV3		0x20000ULL
+#define I40E_HASH_HDR_AH		0x40000ULL
+#define I40E_HASH_HDR_GTPC		0x100000ULL
+#define I40E_HASH_HDR_GTPU		0x200000ULL
+
+#define I40E_HASH_HDR_INNER_SHIFT	32
+#define I40E_HASH_HDR_IPV4_INNER	(I40E_HASH_HDR_IPV4 << \
+					I40E_HASH_HDR_INNER_SHIFT)
+#define I40E_HASH_HDR_IPV6_INNER	(I40E_HASH_HDR_IPV6 << \
+					I40E_HASH_HDR_INNER_SHIFT)
+
+/* ETH */
+#define I40E_PHINT_ETH			I40E_HASH_HDR_ETH
+
+/* IPv4 */
+#define I40E_PHINT_IPV4			(I40E_HASH_HDR_ETH | I40E_HASH_HDR_IPV4)
+#define I40E_PHINT_IPV4_TCP		(I40E_PHINT_IPV4 | I40E_HASH_HDR_TCP)
+#define I40E_PHINT_IPV4_UDP		(I40E_PHINT_IPV4 | I40E_HASH_HDR_UDP)
+#define I40E_PHINT_IPV4_SCTP		(I40E_PHINT_IPV4 | I40E_HASH_HDR_SCTP)
+
+/* IPv6 */
+#define I40E_PHINT_IPV6			(I40E_HASH_HDR_ETH | I40E_HASH_HDR_IPV6)
+#define I40E_PHINT_IPV6_TCP		(I40E_PHINT_IPV6 | I40E_HASH_HDR_TCP)
+#define I40E_PHINT_IPV6_UDP		(I40E_PHINT_IPV6 | I40E_HASH_HDR_UDP)
+#define I40E_PHINT_IPV6_SCTP		(I40E_PHINT_IPV6 | I40E_HASH_HDR_SCTP)
+
+/* ESP */
+#define I40E_PHINT_IPV4_ESP		(I40E_PHINT_IPV4 | I40E_HASH_HDR_ESP)
+#define I40E_PHINT_IPV6_ESP		(I40E_PHINT_IPV6 | I40E_HASH_HDR_ESP)
+#define I40E_PHINT_IPV4_UDP_ESP		(I40E_PHINT_IPV4_UDP | \
+					I40E_HASH_HDR_ESP)
+#define I40E_PHINT_IPV6_UDP_ESP		(I40E_PHINT_IPV6_UDP | \
+					I40E_HASH_HDR_ESP)
+
+/* GTPC */
+#define I40E_PHINT_IPV4_GTPC		(I40E_PHINT_IPV4_UDP | \
+					I40E_HASH_HDR_GTPC)
+#define I40E_PHINT_IPV6_GTPC		(I40E_PHINT_IPV6_UDP | \
+					I40E_HASH_HDR_GTPC)
+
+/* GTPU */
+#define I40E_PHINT_IPV4_GTPU		(I40E_PHINT_IPV4_UDP | \
+					I40E_HASH_HDR_GTPU)
+#define I40E_PHINT_IPV4_GTPU_IPV4	(I40E_PHINT_IPV4_GTPU | \
+					I40E_HASH_HDR_IPV4_INNER)
+#define I40E_PHINT_IPV4_GTPU_IPV6	(I40E_PHINT_IPV4_GTPU | \
+					I40E_HASH_HDR_IPV6_INNER)
+#define I40E_PHINT_IPV6_GTPU		(I40E_PHINT_IPV6_UDP | \
+					I40E_HASH_HDR_GTPU)
+#define I40E_PHINT_IPV6_GTPU_IPV4	(I40E_PHINT_IPV6_GTPU | \
+					I40E_HASH_HDR_IPV4_INNER)
+#define I40E_PHINT_IPV6_GTPU_IPV6	(I40E_PHINT_IPV6_GTPU | \
+					I40E_HASH_HDR_IPV6_INNER)
+
+/* L2TPV3 */
+#define I40E_PHINT_IPV4_L2TPV3		(I40E_PHINT_IPV4 | I40E_HASH_HDR_L2TPV3)
+#define I40E_PHINT_IPV6_L2TPV3		(I40E_PHINT_IPV6 | I40E_HASH_HDR_L2TPV3)
+
+/* AH */
+#define I40E_PHINT_IPV4_AH		(I40E_PHINT_IPV4 | I40E_HASH_HDR_AH)
+#define I40E_PHINT_IPV6_AH		(I40E_PHINT_IPV6 | I40E_HASH_HDR_AH)
+
+/* Structure of mapping RSS type to input set */
+struct i40e_hash_map_rss_inset {
+	uint64_t rss_type;
+	uint64_t inset;
+};
+
+const struct i40e_hash_map_rss_inset i40e_hash_rss_inset[] = {
+	/* IPv4 */
+	{ ETH_RSS_IPV4, I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST },
+	{ ETH_RSS_FRAG_IPV4, I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST },
+
+	{ ETH_RSS_NONFRAG_IPV4_OTHER,
+	  I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST },
+
+	{ ETH_RSS_NONFRAG_IPV4_TCP, I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST |
+	  I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT },
+
+	{ ETH_RSS_NONFRAG_IPV4_UDP, I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST |
+	  I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT },
+
+	{ ETH_RSS_NONFRAG_IPV4_SCTP, I40E_INSET_IPV4_SRC | I40E_INSET_IPV4_DST |
+	  I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT | I40E_INSET_SCTP_VT },
+
+	/* IPv6 */
+	{ ETH_RSS_IPV6, I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST },
+	{ ETH_RSS_FRAG_IPV6, I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST },
+
+	{ ETH_RSS_NONFRAG_IPV6_OTHER,
+	  I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST },
+
+	{ ETH_RSS_NONFRAG_IPV6_TCP, I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST |
+	  I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT },
+
+	{ ETH_RSS_NONFRAG_IPV6_UDP, I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST |
+	  I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT },
+
+	{ ETH_RSS_NONFRAG_IPV6_SCTP, I40E_INSET_IPV6_SRC | I40E_INSET_IPV6_DST |
+	  I40E_INSET_SRC_PORT | I40E_INSET_DST_PORT | I40E_INSET_SCTP_VT },
+
+	/* Ether */
+	{ ETH_RSS_L2_PAYLOAD, I40E_INSET_LAST_ETHER_TYPE },
+	{ ETH_RSS_ETH, I40E_INSET_DMAC | I40E_INSET_SMAC },
+
+	/* VLAN */
+	{ ETH_RSS_S_VLAN, I40E_INSET_VLAN_OUTER },
+	{ ETH_RSS_C_VLAN, I40E_INSET_VLAN_INNER },
+};
+
+#define I40E_HASH_VOID_NEXT_ALLOW	BIT_ULL(RTE_FLOW_ITEM_TYPE_ETH)
+
+#define I40E_HASH_ETH_NEXT_ALLOW	(BIT_ULL(RTE_FLOW_ITEM_TYPE_IPV4) | \
+					BIT_ULL(RTE_FLOW_ITEM_TYPE_IPV6) | \
+					BIT_ULL(RTE_FLOW_ITEM_TYPE_VLAN))
+
+#define I40E_HASH_IP_NEXT_ALLOW		(BIT_ULL(RTE_FLOW_ITEM_TYPE_TCP) | \
+					BIT_ULL(RTE_FLOW_ITEM_TYPE_UDP) | \
+					BIT_ULL(RTE_FLOW_ITEM_TYPE_SCTP) | \
+					BIT_ULL(RTE_FLOW_ITEM_TYPE_ESP) | \
+					BIT_ULL(RTE_FLOW_ITEM_TYPE_L2TPV3OIP) |\
+					BIT_ULL(RTE_FLOW_ITEM_TYPE_AH))
+
+#define I40E_HASH_UDP_NEXT_ALLOW	BIT_ULL(RTE_FLOW_ITEM_TYPE_GTPU)
+
+#define I40E_HASH_GTPU_NEXT_ALLOW	(BIT_ULL(RTE_FLOW_ITEM_TYPE_IPV4) | \
+					BIT_ULL(RTE_FLOW_ITEM_TYPE_IPV6))
+
+static const uint64_t pattern_next_allow_items[] = {
+	[RTE_FLOW_ITEM_TYPE_VOID] = I40E_HASH_VOID_NEXT_ALLOW,
+	[RTE_FLOW_ITEM_TYPE_ETH] = I40E_HASH_ETH_NEXT_ALLOW,
+	[RTE_FLOW_ITEM_TYPE_IPV4] = I40E_HASH_IP_NEXT_ALLOW,
+	[RTE_FLOW_ITEM_TYPE_IPV6] = I40E_HASH_IP_NEXT_ALLOW,
+	[RTE_FLOW_ITEM_TYPE_UDP] = I40E_HASH_UDP_NEXT_ALLOW,
+	[RTE_FLOW_ITEM_TYPE_GTPU] = I40E_HASH_GTPU_NEXT_ALLOW,
+};
+
+static const uint64_t pattern_item_header[] = {
+	[RTE_FLOW_ITEM_TYPE_ETH] = I40E_HASH_HDR_ETH,
+	[RTE_FLOW_ITEM_TYPE_IPV4] = I40E_HASH_HDR_IPV4,
+	[RTE_FLOW_ITEM_TYPE_IPV6] = I40E_HASH_HDR_IPV6,
+	[RTE_FLOW_ITEM_TYPE_TCP] = I40E_HASH_HDR_TCP,
+	[RTE_FLOW_ITEM_TYPE_UDP] = I40E_HASH_HDR_UDP,
+	[RTE_FLOW_ITEM_TYPE_SCTP] = I40E_HASH_HDR_SCTP,
+	[RTE_FLOW_ITEM_TYPE_ESP] = I40E_HASH_HDR_ESP,
+	[RTE_FLOW_ITEM_TYPE_GTPU] = I40E_HASH_HDR_GTPU,
+	[RTE_FLOW_ITEM_TYPE_L2TPV3OIP] = I40E_HASH_HDR_L2TPV3,
+	[RTE_FLOW_ITEM_TYPE_AH] = I40E_HASH_HDR_AH,
+};
+
+/* Structure of matched pattern */
+struct i40e_hash_match_pattern {
+	uint64_t pattern_type;
+	uint64_t rss_mask;	/* Supported RSS type for this pattern */
+	bool custom_pctype_flag;/* true for custom packet type */
+	uint8_t pctype;
+};
+
+#define I40E_HASH_MAP_PATTERN(pattern, rss_mask, pctype) { \
+	pattern, rss_mask, false, pctype  }
+
+#define I40E_HASH_MAP_CUS_PATTERN(pattern, rss_mask, cus_pctype) { \
+	pattern, rss_mask, true, cus_pctype }
+
+#define I40E_HASH_VLAN_RSS_MASK		(ETH_RSS_S_VLAN | ETH_RSS_C_VLAN)
+#define I40E_HASH_L2_RSS_MASK		(ETH_RSS_ETH | ETH_RSS_L2_SRC_ONLY | \
+					ETH_RSS_L2_SRC_ONLY)
+
+#define I40E_HASH_L23_RSS_MASK		(I40E_HASH_L2_RSS_MASK | \
+					I40E_HASH_VLAN_RSS_MASK | \
+					ETH_RSS_L3_SRC_ONLY | \
+					ETH_RSS_L3_SRC_ONLY)
+
+#define I40E_HASH_L234_RSS_MASK		(I40E_HASH_L23_RSS_MASK | \
+					ETH_RSS_PORT | ETH_RSS_L3_SRC_ONLY | \
+					ETH_RSS_L3_SRC_ONLY)
+
+#define I40E_HASH_IPV4_L234_RSS_MASK	(I40E_HASH_L234_RSS_MASK | ETH_RSS_IPV4)
+#define I40E_HASH_IPV6_L234_RSS_MASK	(I40E_HASH_L234_RSS_MASK | ETH_RSS_IPV6)
+
+/* Current supported patterns and RSS types.
+ * All items that have the same pattern types are together.
+ */
+static const struct i40e_hash_match_pattern match_patterns[] = {
+	/* Ether */
+	I40E_HASH_MAP_PATTERN(I40E_PHINT_ETH,
+			      ETH_RSS_L2_PAYLOAD | I40E_HASH_L2_RSS_MASK,
+			      I40E_FILTER_PCTYPE_L2_PAYLOAD),
+
+	/* IPv4 */
+	I40E_HASH_MAP_PATTERN(I40E_PHINT_IPV4,
+			      ETH_RSS_FRAG_IPV4 | I40E_HASH_L23_RSS_MASK,
+			      I40E_FILTER_PCTYPE_FRAG_IPV4),
+
+	I40E_HASH_MAP_PATTERN(I40E_PHINT_IPV4,
+			      ETH_RSS_NONFRAG_IPV4_OTHER |
+			      I40E_HASH_L23_RSS_MASK,
+			      I40E_FILTER_PCTYPE_NONF_IPV4_OTHER),
+
+	I40E_HASH_MAP_PATTERN(I40E_PHINT_IPV4_TCP,
+			      ETH_RSS_NONFRAG_IPV4_TCP |
+			      I40E_HASH_IPV4_L234_RSS_MASK,
+			      I40E_FILTER_PCTYPE_NONF_IPV4_TCP),
+
+	I40E_HASH_MAP_PATTERN(I40E_PHINT_IPV4_UDP,
+			      ETH_RSS_NONFRAG_IPV4_UDP |
+			      I40E_HASH_IPV4_L234_RSS_MASK,
+			      I40E_FILTER_PCTYPE_NONF_IPV4_UDP),
+
+	I40E_HASH_MAP_PATTERN(I40E_PHINT_IPV4_SCTP,
+			      ETH_RSS_NONFRAG_IPV4_SCTP |
+			      I40E_HASH_IPV4_L234_RSS_MASK,
+			      I40E_FILTER_PCTYPE_NONF_IPV4_SCTP),
+
+	/* IPv6 */
+	I40E_HASH_MAP_PATTERN(I40E_PHINT_IPV6,
+			      ETH_RSS_FRAG_IPV6 | I40E_HASH_L23_RSS_MASK,
+			      I40E_FILTER_PCTYPE_FRAG_IPV6),
+
+	I40E_HASH_MAP_PATTERN(I40E_PHINT_IPV6,
+			      ETH_RSS_NONFRAG_IPV6_OTHER |
+			      I40E_HASH_L23_RSS_MASK,
+			      I40E_FILTER_PCTYPE_NONF_IPV6_OTHER),
+
+	I40E_HASH_MAP_PATTERN(I40E_PHINT_IPV6_TCP,
+			      ETH_RSS_NONFRAG_IPV6_TCP |
+			      I40E_HASH_IPV6_L234_RSS_MASK,
+			      I40E_FILTER_PCTYPE_NONF_IPV6_TCP),
+
+	I40E_HASH_MAP_PATTERN(I40E_PHINT_IPV6_UDP,
+			      ETH_RSS_NONFRAG_IPV6_UDP |
+			      I40E_HASH_IPV6_L234_RSS_MASK,
+			      I40E_FILTER_PCTYPE_NONF_IPV6_UDP),
+
+	I40E_HASH_MAP_PATTERN(I40E_PHINT_IPV6_SCTP,
+			      ETH_RSS_NONFRAG_IPV6_SCTP |
+			      I40E_HASH_IPV6_L234_RSS_MASK,
+			      I40E_FILTER_PCTYPE_NONF_IPV6_SCTP),
+
+	/* ESP */
+	I40E_HASH_MAP_CUS_PATTERN(I40E_PHINT_IPV4_ESP,
+				  ETH_RSS_ESP, I40E_CUSTOMIZED_ESP_IPV4),
+	I40E_HASH_MAP_CUS_PATTERN(I40E_PHINT_IPV6_ESP,
+				  ETH_RSS_ESP, I40E_CUSTOMIZED_ESP_IPV6),
+	I40E_HASH_MAP_CUS_PATTERN(I40E_PHINT_IPV4_UDP_ESP,
+				  ETH_RSS_ESP, I40E_CUSTOMIZED_ESP_IPV4_UDP),
+	I40E_HASH_MAP_CUS_PATTERN(I40E_PHINT_IPV6_UDP_ESP,
+				  ETH_RSS_ESP, I40E_CUSTOMIZED_ESP_IPV6_UDP),
+
+	/* GTPC */
+	I40E_HASH_MAP_CUS_PATTERN(I40E_PHINT_IPV4_GTPC,
+				  I40E_HASH_IPV4_L234_RSS_MASK,
+				  I40E_CUSTOMIZED_GTPC),
+	I40E_HASH_MAP_CUS_PATTERN(I40E_PHINT_IPV6_GTPC,
+				  I40E_HASH_IPV6_L234_RSS_MASK,
+				  I40E_CUSTOMIZED_GTPC),
+
+	/* GTPU */
+	I40E_HASH_MAP_CUS_PATTERN(I40E_PHINT_IPV4_GTPU,
+				  I40E_HASH_IPV4_L234_RSS_MASK,
+				  I40E_CUSTOMIZED_GTPU),
+	I40E_HASH_MAP_CUS_PATTERN(I40E_PHINT_IPV4_GTPU_IPV4,
+				  ETH_RSS_GTPU, I40E_CUSTOMIZED_GTPU_IPV4),
+	I40E_HASH_MAP_CUS_PATTERN(I40E_PHINT_IPV4_GTPU_IPV6,
+				  ETH_RSS_GTPU, I40E_CUSTOMIZED_GTPU_IPV6),
+	I40E_HASH_MAP_CUS_PATTERN(I40E_PHINT_IPV6_GTPU,
+				  I40E_HASH_IPV6_L234_RSS_MASK,
+				  I40E_CUSTOMIZED_GTPU),
+	I40E_HASH_MAP_CUS_PATTERN(I40E_PHINT_IPV6_GTPU_IPV4,
+				  ETH_RSS_GTPU, I40E_CUSTOMIZED_GTPU_IPV4),
+	I40E_HASH_MAP_CUS_PATTERN(I40E_PHINT_IPV6_GTPU_IPV6,
+				  ETH_RSS_GTPU, I40E_CUSTOMIZED_GTPU_IPV6),
+
+	/* L2TPV3 */
+	I40E_HASH_MAP_CUS_PATTERN(I40E_PHINT_IPV4_L2TPV3,
+				  ETH_RSS_L2TPV3, I40E_CUSTOMIZED_IPV4_L2TPV3),
+	I40E_HASH_MAP_CUS_PATTERN(I40E_PHINT_IPV6_L2TPV3,
+				  ETH_RSS_L2TPV3, I40E_CUSTOMIZED_IPV6_L2TPV3),
+
+	/* AH */
+	I40E_HASH_MAP_CUS_PATTERN(I40E_PHINT_IPV4_AH, ETH_RSS_AH,
+				  I40E_CUSTOMIZED_AH_IPV4),
+	I40E_HASH_MAP_CUS_PATTERN(I40E_PHINT_IPV6_AH, ETH_RSS_AH,
+				  I40E_CUSTOMIZED_AH_IPV6),
+};
+
+static int
+i40e_hash_get_pattern_type(const struct rte_flow_item pattern[],
+			   struct rte_flow_error *error,
+			   uint64_t *pattern_types)
+{
+	const char *message = "Pattern not supported";
+	enum rte_flow_item_type prev_item_type = RTE_FLOW_ITEM_TYPE_VOID;
+	enum rte_flow_item_type last_item_type = prev_item_type;
+	uint64_t item_hdr, pattern_hdrs = 0;
+	bool inner_flag = false;
+	int vlan_count = 0;
+
+	for (; pattern->type != RTE_FLOW_ITEM_TYPE_END; pattern++) {
+		if (pattern->type == RTE_FLOW_ITEM_TYPE_VOID)
+			continue;
+
+		if (pattern->mask || pattern->spec || pattern->last) {
+			message = "Header info should not be specified";
+			goto not_sup;
+		}
+
+		/* Check the previous item allows this sub-item. */
+		if (prev_item_type >= RTE_DIM(pattern_next_allow_items) ||
+		    !(pattern_next_allow_items[prev_item_type] &
+		    BIT_ULL(pattern->type)))
+			goto not_sup;
+
+		/* For VLAN item, it does no matter about to pattern type
+		 * recognition. So just count the number of VLAN and do not
+		 * change the value of prev_item_type.
+		 */
+		last_item_type = pattern->type;
+		if (last_item_type == RTE_FLOW_ITEM_TYPE_VLAN) {
+			if (vlan_count >= 2)
+				goto not_sup;
+			vlan_count++;
+			continue;
+		}
+
+		prev_item_type = last_item_type;
+		assert(last_item_type < RTE_DIM(pattern_item_header));
+		item_hdr = pattern_item_header[last_item_type];
+		assert(item_hdr);
+
+		if (inner_flag) {
+			item_hdr <<= I40E_HASH_HDR_INNER_SHIFT;
+
+			/* Inner layer should not have GTPU item */
+			if (last_item_type == RTE_FLOW_ITEM_TYPE_GTPU)
+				goto not_sup;
+
+		} else if (last_item_type == RTE_FLOW_ITEM_TYPE_GTPU) {
+			inner_flag = true;
+			vlan_count = 0;
+		}
+
+		if (item_hdr & pattern_hdrs)
+			goto not_sup;
+
+		pattern_hdrs |= item_hdr;
+	}
+
+	if (pattern_hdrs && last_item_type != RTE_FLOW_ITEM_TYPE_VLAN) {
+		*pattern_types = pattern_hdrs;
+		return 0;
+	}
+
+not_sup:
+	return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM,
+				  pattern, message);
+}
+
+static int
+i40e_hash_get_x722_ext_pctypes(const struct i40e_hash_match_pattern *match,
+			       struct i40e_rte_flow_rss_conf *rss_conf,
+			       struct rte_flow_error *error)
+{
+	uint8_t *pctypes = rss_conf->pctypes;
+	uint8_t count = rss_conf->pctype_count;
+
+	switch (match->pctype) {
+	case I40E_FILTER_PCTYPE_NONF_IPV4_TCP:
+		if (count >= RTE_DIM(rss_conf->pctypes))
+			goto out_of_range;
+
+		pctypes[count++] = I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK;
+		break;
+
+	case I40E_FILTER_PCTYPE_NONF_IPV4_UDP:
+		if (count + 2 > (int)RTE_DIM(rss_conf->pctypes))
+			goto out_of_range;
+
+		pctypes[count++] = I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP;
+		pctypes[count++] = I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP;
+		break;
+
+	case I40E_FILTER_PCTYPE_NONF_IPV6_TCP:
+		if (count >= RTE_DIM(rss_conf->pctypes))
+			goto out_of_range;
+
+		pctypes[count++] = I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK;
+		break;
+
+	case I40E_FILTER_PCTYPE_NONF_IPV6_UDP:
+		if (count + 2 > (int)RTE_DIM(rss_conf->pctypes))
+			goto out_of_range;
+
+		pctypes[count++] = I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP;
+		pctypes[count++] = I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP;
+		break;
+	}
+
+	rss_conf->pctype_count = count;
+	return 0;
+
+out_of_range:
+	return rte_flow_error_set(error, ERANGE,
+				  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+				  NULL, "RSS PCTYPE number out of range");
+}
+
+static int
+i40e_hash_get_pctypes(const struct rte_eth_dev *dev,
+		      const struct i40e_hash_match_pattern *match,
+		      struct i40e_rte_flow_rss_conf *rss_conf,
+		      struct rte_flow_error *error)
+{
+	if (rss_conf->pctype_count >= RTE_DIM(rss_conf->pctypes))
+		return rte_flow_error_set(error, ERANGE,
+					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+					  NULL,
+					  "RSS PCTYPE number out of range");
+
+	if (match->custom_pctype_flag) {
+		struct i40e_pf *pf;
+		struct i40e_customized_pctype *custom_type;
+
+		pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+		custom_type = i40e_find_customized_pctype(pf, match->pctype);
+		if (!custom_type || !custom_type->valid)
+			return rte_flow_error_set(error, ENOTSUP,
+						  RTE_FLOW_ERROR_TYPE_ITEM,
+						  NULL,
+						  "PCTYPE not supported");
+
+		rss_conf->pctypes[rss_conf->pctype_count] = custom_type->pctype;
+		rss_conf->pctype_count++;
+	} else {
+		struct i40e_hw *hw;
+
+		rss_conf->pctypes[rss_conf->pctype_count] = match->pctype;
+		rss_conf->pctype_count++;
+
+		hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+		if (hw->mac.type == I40E_MAC_X722)
+			return i40e_hash_get_x722_ext_pctypes(match,
+							      rss_conf, error);
+	}
+
+	return 0;
+}
+
+static int
+i40e_hash_get_pattern_pctypes(const struct rte_eth_dev *dev,
+			      const struct rte_flow_item pattern[],
+			      const struct rte_flow_action_rss *rss_act,
+			      struct i40e_rte_flow_rss_conf *rss_conf,
+			      struct rte_flow_error *error)
+{
+	uint64_t pattern_types = 0;
+	bool match_flag = false;
+	int i, ret;
+
+	ret = i40e_hash_get_pattern_type(pattern, error, &pattern_types);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < (int)RTE_DIM(match_patterns); i++) {
+		const struct i40e_hash_match_pattern *match =
+							&match_patterns[i];
+
+		/* Check pattern types match. All items that have the same
+		 * pattern types are together, so if the pattern types match
+		 * previous item but they doesn't match current item, it means
+		 * the pattern types do not match all remain items.
+		 */
+		if (pattern_types != match->pattern_type) {
+			if (match_flag)
+				break;
+			continue;
+		}
+		match_flag = true;
+
+		/* Check RSS types match */
+		if ((rss_act->types & ~match->rss_mask) == 0) {
+			ret = i40e_hash_get_pctypes(dev, match,
+						    rss_conf, error);
+			if (ret)
+				return ret;
+		}
+	}
+
+	if (rss_conf->pctype_count)
+		return 0;
+
+	if (match_flag)
+		return rte_flow_error_set(error, ENOTSUP,
+					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+					  NULL, "RSS types not supported");
+
+	return rte_flow_error_set(error, ENOTSUP, RTE_FLOW_ERROR_TYPE_ITEM,
+				  NULL, "Pattern not supported");
+}
+
+static int
+i40e_hash_config_pctype_inset(struct i40e_hw *hw, uint64_t rss_types,
+			      uint64_t inset, uint32_t pctype)
+{
+	uint64_t mask;
+
+	/* If SRC_ONLY and DST_ONLY of the same level are used simultaneously,
+	 * it is the same case as none of them are added.
+	 */
+	mask = rss_types & (ETH_RSS_L2_SRC_ONLY | ETH_RSS_L2_DST_ONLY);
+	if (mask == ETH_RSS_L2_SRC_ONLY)
+		inset &= ~I40E_INSET_DMAC;
+	else if (mask == ETH_RSS_L2_DST_ONLY)
+		inset &= ~I40E_INSET_SMAC;
+
+	mask = rss_types & (ETH_RSS_L4_SRC_ONLY | ETH_RSS_L4_DST_ONLY);
+	if (mask == ETH_RSS_L4_SRC_ONLY)
+		inset &= ~I40E_INSET_DST_PORT;
+	else if (mask == ETH_RSS_L4_DST_ONLY)
+		inset &= ~I40E_INSET_SRC_PORT;
+
+	mask = rss_types & (ETH_RSS_L3_SRC_ONLY | ETH_RSS_L3_DST_ONLY);
+	if (mask == ETH_RSS_L3_SRC_ONLY)
+		inset &= ~(I40E_INSET_IPV4_DST | I40E_INSET_IPV6_DST);
+	else if (mask == ETH_RSS_L3_DST_ONLY)
+		inset &= ~(I40E_INSET_IPV4_SRC | I40E_INSET_IPV6_SRC);
+
+	return i40e_set_hash_inset(hw, inset, pctype, false);
+}
+
+static int
+i40e_hash_config_func(struct i40e_hw *hw, enum rte_eth_hash_function func)
+{
+	struct i40e_pf *pf;
+	uint32_t reg;
+	uint8_t symmetric = 0;
+
+	reg = i40e_read_rx_ctl(hw, I40E_GLQF_CTL);
+
+	if (func == RTE_ETH_HASH_FUNCTION_SIMPLE_XOR) {
+		if (!(reg & I40E_GLQF_CTL_HTOEP_MASK))
+			goto set_symmetric;
+
+		reg &= ~I40E_GLQF_CTL_HTOEP_MASK;
+	} else {
+		if (func == RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ)
+			symmetric = 1;
+
+		if (reg & I40E_GLQF_CTL_HTOEP_MASK)
+			goto set_symmetric;
+
+		reg |= I40E_GLQF_CTL_HTOEP_MASK;
+	}
+
+	pf = &((struct i40e_adapter *)hw->back)->pf;
+	if (pf->support_multi_driver) {
+		PMD_DRV_LOG(ERR,
+			    "Modify hash function is not permitted when multi-driver enabled");
+		return -EPERM;
+	}
+
+	PMD_DRV_LOG(INFO, "NIC hash function is setting to %d", func);
+	i40e_write_rx_ctl(hw, I40E_GLQF_CTL, reg);
+	I40E_WRITE_FLUSH(hw);
+
+set_symmetric:
+	i40e_set_symmetric_hash_enable_per_port(hw, symmetric);
+	return 0;
+}
+
+static int
+i40e_hash_config_pctype_symmetric(struct i40e_hw *hw, uint32_t pctype,
+				  enum rte_eth_hash_function func)
+{
+	struct i40e_pf *pf = &((struct i40e_adapter *)hw->back)->pf;
+	uint32_t reg;
+
+	/* For X722, get translated pctype in fd pctype register */
+	if (hw->mac.type == I40E_MAC_X722)
+		pctype = i40e_read_rx_ctl(hw, I40E_GLQF_FD_PCTYPES(pctype));
+
+	reg = i40e_read_rx_ctl(hw, I40E_GLQF_HSYM(pctype));
+	if (func == RTE_ETH_HASH_FUNCTION_SYMMETRIC_TOEPLITZ) {
+		if (reg & I40E_GLQF_HSYM_SYMH_ENA_MASK)
+			return 0;
+		reg |= I40E_GLQF_HSYM_SYMH_ENA_MASK;
+	} else {
+		if (!(reg & I40E_GLQF_HSYM_SYMH_ENA_MASK))
+			return 0;
+		reg &= ~I40E_GLQF_HSYM_SYMH_ENA_MASK;
+	}
+
+	if (pf->support_multi_driver) {
+		PMD_DRV_LOG(ERR,
+			    "Enable/Disable symmetric hash is not permitted when multi-driver enabled");
+		return -EPERM;
+	}
+
+	i40e_write_rx_ctl(hw, I40E_GLQF_HSYM(pctype), reg);
+	I40E_WRITE_FLUSH(hw);
+	return 0;
+}
+
+static void
+i40e_hash_enable_pctype(struct i40e_hw *hw,
+			uint32_t pctype, bool enable)
+{
+	uint32_t reg, reg_val, mask;
+
+	/* For X722, get translated pctype in fd pctype register */
+	if (hw->mac.type == I40E_MAC_X722)
+		pctype = i40e_read_rx_ctl(hw, I40E_GLQF_FD_PCTYPES(pctype));
+
+	if (pctype < 32) {
+		mask = 1U << pctype;
+		reg = I40E_PFQF_HENA(0);
+	} else {
+		mask = 1U << (pctype - 32);
+		reg = I40E_PFQF_HENA(1);
+	}
+
+	reg_val = i40e_read_rx_ctl(hw, reg);
+
+	if (enable) {
+		if (reg_val & mask)
+			return;
+
+		reg_val |= mask;
+	} else {
+		if (!(reg_val & mask))
+			return;
+
+		reg_val &= ~mask;
+	}
+
+	i40e_write_rx_ctl(hw, reg, reg_val);
+	I40E_WRITE_FLUSH(hw);
+}
+
+static int
+i40e_hash_config_pctype(struct i40e_hw *hw,
+			const struct rte_flow_action_rss *rss_act,
+			uint32_t pctype)
+{
+	uint64_t inset = 0;
+	int i, ret;
+
+	if (rss_act->types == 0) {
+		i40e_hash_enable_pctype(hw, pctype, false);
+		return 0;
+	}
+
+	/* Get input sets */
+	for (i = 0; i < (int)RTE_DIM(i40e_hash_rss_inset); i++) {
+		if (rss_act->types & i40e_hash_rss_inset[i].rss_type)
+			inset |= i40e_hash_rss_inset[i].inset;
+	}
+
+	if (inset) {
+		ret = i40e_hash_config_pctype_inset(hw, rss_act->types,
+						    inset, pctype);
+		if (ret)
+			return ret;
+	}
+
+	if (rss_act->func != RTE_ETH_HASH_FUNCTION_DEFAULT) {
+		ret = i40e_hash_config_pctype_symmetric(hw, pctype,
+							rss_act->func);
+		if (ret)
+			return ret;
+	}
+
+	i40e_hash_enable_pctype(hw, pctype, true);
+	return 0;
+}
+
+static int
+i40e_hash_reset_pctype(struct i40e_hw *hw,
+		       const struct rte_flow_action_rss *rss_act,
+		       uint32_t pctype)
+{
+	const enum rte_eth_hash_function def_func =
+			RTE_ETH_HASH_FUNCTION_TOEPLITZ;
+	uint64_t inset = 0;
+	int ret;
+
+	i40e_hash_enable_pctype(hw, pctype, false);
+
+	inset = i40e_get_default_input_set(pctype);
+	if (inset) {
+		ret = i40e_set_hash_inset(hw, inset, pctype, false);
+		if (ret)
+			return ret;
+	}
+
+	if (rss_act->func != RTE_ETH_HASH_FUNCTION_DEFAULT &&
+	    rss_act->func != def_func) {
+		ret = i40e_hash_config_pctype_symmetric(hw, pctype, def_func);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int
+i40e_hash_config_region(struct i40e_pf *pf,
+			const struct i40e_rte_flow_rss_conf *rss_conf)
+{
+	struct i40e_hw *hw = &pf->adapter->hw;
+	struct rte_eth_dev *dev = pf->adapter->eth_dev;
+	struct i40e_queue_region_info *regions = pf->queue_region.region;
+	uint32_t num = pf->queue_region.queue_region_number;
+	uint32_t i, region_id_mask = 0;
+
+	if (!rss_conf->region_queue_num)
+		return 0;
+
+	RTE_BUILD_BUG_ON(I40E_REGION_MAX_INDEX > 31);
+
+	/* Re-configure the region if it existed */
+	for (i = 0; i < num; i++) {
+		if (rss_conf->region_queue_start ==
+		    regions[i].queue_start_index &&
+		    rss_conf->region_queue_num == regions[i].queue_num) {
+			regions[i].user_priority[0] = rss_conf->region_priority;
+
+			return i40e_flush_queue_region_all_conf(dev, hw, pf, 1);
+		}
+
+		region_id_mask |= BIT(regions[i].region_id);
+	}
+
+	if (num > I40E_REGION_MAX_INDEX) {
+		PMD_DRV_LOG(ERR, "Queue region resource used up");
+		return -ERANGE;
+	}
+
+	/* Add a new region */
+
+	pf->queue_region.queue_region_number++;
+	memset(&regions[num], 0, sizeof(regions[0]));
+
+	for (i = 0; i <= I40E_REGION_MAX_INDEX; i++)
+		if (!(BIT(i) & region_id_mask))
+			break;
+
+	regions[num].region_id = i;
+	regions[num].queue_num = rss_conf->region_queue_num;
+	regions[num].queue_start_index = rss_conf->region_queue_start;
+	regions[num].user_priority[0] = rss_conf->region_priority;
+	regions[num].user_priority_num = 1;
+
+	return i40e_flush_queue_region_all_conf(dev, hw, pf, 1);
+}
+
+static int
+i40e_hash_config(struct i40e_pf *pf,
+		 struct i40e_rte_flow_rss_conf *rss_conf)
+{
+	struct rte_flow_action_rss *rss_info = &rss_conf->conf;
+	struct i40e_hw *hw = &pf->adapter->hw;
+	uint32_t i;
+	int ret;
+
+	if (rss_conf->region_flags)
+		return i40e_hash_config_region(pf, rss_conf);
+
+	if (rss_info->key_len > 0) {
+		ret = i40e_set_rss_key(pf->main_vsi, rss_conf->key,
+				       rss_info->key_len);
+		if (ret)
+			return ret;
+	}
+
+	if (rss_info->func != RTE_ETH_HASH_FUNCTION_DEFAULT) {
+		ret = i40e_hash_config_func(hw, rss_conf->conf.func);
+		if (ret)
+			return ret;
+	}
+
+	/* Update lookup table */
+	if (rss_info->queue_num > 0) {
+		uint8_t lut[ETH_RSS_RETA_SIZE_512];
+		uint32_t j = 0;
+
+		for (i = 0; i < hw->func_caps.rss_table_size; i++) {
+			lut[i] = (uint8_t)rss_info->queue[j];
+			j = (j == rss_info->queue_num - 1) ? 0 : (j + 1);
+		}
+
+		ret = i40e_set_rss_lut(pf->main_vsi, lut, (uint16_t)i);
+		if (ret)
+			return ret;
+
+		pf->hash_enabled_queues = 0;
+		for (i = 0; i < rss_info->queue_num; i++)
+			pf->hash_enabled_queues |= BIT_ULL(lut[i]);
+
+		pf->adapter->rss_reta_updated = 0;
+	}
+
+	if (rss_conf->pctype_count <= 0)
+		return 0;
+
+	if (!pf->hash_filter_enable) {
+		i40e_pf_disable_rss(pf);
+		pf->hash_filter_enable = true;
+	}
+
+	for (i = 0; i < rss_conf->pctype_count; i++) {
+		ret = i40e_hash_config_pctype(hw, &rss_conf->conf,
+					      rss_conf->pctypes[i]);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+static void
+i40e_hash_parse_key(const struct rte_flow_action_rss *rss_act,
+		    struct i40e_rte_flow_rss_conf *rss_conf)
+{
+	const uint8_t *key = rss_act->key;
+
+	if (rss_act->key_len != sizeof(rss_conf->key)) {
+		const uint32_t rss_key_default[] = {0x6b793944,
+			0x23504cb5, 0x5bea75b6, 0x309f4f12, 0x3dc0a2b8,
+			0x024ddcdf, 0x339b8ca0, 0x4c4af64a, 0x34fac605,
+			0x55d85839, 0x3a58997d, 0x2ec938e1, 0x66031581};
+
+		PMD_DRV_LOG(WARNING, "RSS key invalid, set to default");
+		key = (const uint8_t *)rss_key_default;
+	}
+
+	memcpy(rss_conf->key, key, sizeof(rss_conf->key));
+	rss_conf->conf.key = rss_conf->key;
+	rss_conf->conf.key_len = sizeof(rss_conf->key);
+}
+
+static int
+i40e_hash_parse_queues(const struct rte_eth_dev *dev,
+		       const struct rte_flow_action_rss *rss_act,
+		       struct i40e_rte_flow_rss_conf *rss_conf,
+		       struct rte_flow_error *error)
+{
+	const char *message;
+	struct i40e_pf *pf;
+	struct i40e_hw *hw;
+	uint16_t i;
+	int max_queue;
+
+	hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	if (!rss_act->queue_num ||
+	    rss_act->queue_num > hw->func_caps.rss_table_size) {
+		message = "Invalid RSS queue number";
+		goto invalid;
+	}
+
+	if (rss_act->key_len)
+		PMD_DRV_LOG(WARNING,
+			    "RSS key is ignored when queues specified");
+
+	pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+	if (pf->dev_data->dev_conf.rxmode.mq_mode & ETH_MQ_RX_VMDQ_FLAG)
+		max_queue = i40e_pf_calc_configured_queues_num(pf);
+	else
+		max_queue = pf->dev_data->nb_rx_queues;
+
+	max_queue = RTE_MIN(max_queue, I40E_MAX_Q_PER_TC);
+
+	for (i = 0; i < rss_act->queue_num; i++) {
+		if ((int)rss_act->queue[i] >= max_queue) {
+			message = "Invalid RSS queues";
+			goto invalid;
+		}
+	}
+
+	memcpy(rss_conf->queue, rss_act->queue,
+	       rss_act->queue_num * sizeof(rss_conf->queue[0]));
+	rss_conf->conf.queue = rss_conf->queue;
+	rss_conf->conf.queue_num = rss_act->queue_num;
+
+	return 0;
+
+invalid:
+	return rte_flow_error_set(error, EINVAL,
+				  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+				  NULL, message);
+}
+
+static int
+i40e_hash_parse_queue_region(const struct rte_eth_dev *dev,
+			     const struct rte_flow_item pattern[],
+			     const struct rte_flow_action_rss *rss_act,
+			     struct i40e_rte_flow_rss_conf *rss_conf,
+			     struct rte_flow_error *error)
+{
+	struct i40e_pf *pf;
+	const struct rte_flow_item_vlan *vlan_spec, *vlan_mask;
+	uint64_t hash_queues;
+	uint32_t i;
+
+	if (pattern[1].type != RTE_FLOW_ITEM_TYPE_END)
+		return rte_flow_error_set(error, ENOTSUP,
+					  RTE_FLOW_ERROR_TYPE_ITEM_NUM,
+					  &pattern[1],
+					  "Pattern not supported.");
+
+	vlan_spec = pattern->spec;
+	vlan_mask = pattern->mask;
+	if (!vlan_spec || !vlan_mask ||
+	    vlan_mask->tci != rte_cpu_to_be_16(I40E_TCI_MASK))
+		return rte_flow_error_set(error, EINVAL,
+					  RTE_FLOW_ERROR_TYPE_ITEM,
+					  pattern,
+					  "Pattern error.");
+
+	if (!rss_act->queue)
+		return rte_flow_error_set(error, EINVAL,
+					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+					  NULL, "Queues not specified");
+
+	if (rss_act->types)
+		PMD_DRV_LOG(WARNING,
+			    "RSS type is ignored when configure queue region");
+
+	if (rss_act->key_len)
+		PMD_DRV_LOG(WARNING,
+			    "RSS key is ignored when configure queue region");
+
+	RTE_BUILD_BUG_ON(I40E_MAX_Q_PER_TC > 64);
+
+	if (!rss_act->queue_num ||
+	    rss_act->queue_num > I40E_MAX_Q_PER_TC ||
+	    !rte_is_power_of_2(rss_act->queue_num))
+		return rte_flow_error_set(error, EINVAL,
+					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+					  NULL, "Queue number error");
+
+	hash_queues = BIT_ULL(rss_act->queue[0]);
+
+	for (i = 1; i < rss_act->queue_num; i++) {
+		if (rss_act->queue[i - 1] + 1 != rss_act->queue[i]) {
+			rte_flow_error_set(error, EINVAL,
+					   RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+					   NULL,
+					   "Queues must be incremented continuously");
+			return -EINVAL;
+		}
+
+		hash_queues |= BIT_ULL(rss_act->queue[i]);
+	}
+
+	pf = I40E_DEV_PRIVATE_TO_PF(dev->data->dev_private);
+	if (hash_queues & ~pf->hash_enabled_queues)
+		return rte_flow_error_set(error, EINVAL,
+					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+					  NULL, "Invalid queues");
+
+	rss_conf->region_queue_num = (uint8_t)rss_act->queue_num;
+	rss_conf->region_queue_start = rss_act->queue[0];
+	rss_conf->region_priority = rte_be_to_cpu_16(vlan_spec->tci) >> 13;
+	rss_conf->region_flags = 1;
+	return 0;
+}
+
+static bool
+i40e_hash_validate_rss_types(uint64_t rss_types)
+{
+	uint64_t type, mask;
+
+	/* Validate L2 */
+	type = ETH_RSS_ETH & rss_types;
+	mask = (ETH_RSS_L2_SRC_ONLY | ETH_RSS_L2_DST_ONLY) & rss_types;
+	if (!type && mask)
+		return false;
+
+	/* Validate L4 */
+	type = (ETH_RSS_NONFRAG_IPV4_TCP | ETH_RSS_NONFRAG_IPV4_UDP |
+	       ETH_RSS_NONFRAG_IPV4_SCTP | ETH_RSS_NONFRAG_IPV6_TCP |
+	       ETH_RSS_NONFRAG_IPV6_UDP | ETH_RSS_NONFRAG_IPV6_SCTP) &
+	       rss_types;
+	mask = (ETH_RSS_L4_SRC_ONLY | ETH_RSS_L4_DST_ONLY) & rss_types;
+	if (!type && mask)
+		return false;
+
+	/* Validate L3 */
+	type = type | ((ETH_RSS_IPV4 | ETH_RSS_FRAG_IPV4 |
+	       ETH_RSS_NONFRAG_IPV4_OTHER | ETH_RSS_IPV6 |
+	       ETH_RSS_FRAG_IPV6 | ETH_RSS_NONFRAG_IPV6_OTHER) & rss_types);
+	mask = (ETH_RSS_L3_SRC_ONLY | ETH_RSS_L3_DST_ONLY) & rss_types;
+	if (!type && mask)
+		return false;
+
+	return true;
+}
+
+static int
+i40e_hash_parse_pattern_act(const struct rte_eth_dev *dev,
+			    const struct rte_flow_item pattern[],
+			    const struct rte_flow_action_rss *rss_act,
+			    struct i40e_rte_flow_rss_conf *rss_conf,
+			    struct rte_flow_error *error)
+{
+	if (rss_act->queue) {
+		const char *message =
+			"RSS Queues are not supported when pattern specified";
+		return rte_flow_error_set(error, EINVAL,
+					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+					  NULL, message);
+	}
+
+	if (!i40e_hash_validate_rss_types(rss_act->types))
+		return rte_flow_error_set(error, EINVAL,
+					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+					  NULL, "RSS types are invalid");
+
+	rss_conf->conf.types = rss_act->types;
+	return i40e_hash_get_pattern_pctypes(dev, pattern, rss_act,
+					     rss_conf, error);
+}
+
+int
+i40e_hash_parse(const struct rte_eth_dev *dev,
+		const struct rte_flow_item pattern[],
+		const struct rte_flow_action actions[],
+		struct i40e_rte_flow_rss_conf *rss_conf,
+		struct rte_flow_error *error)
+{
+	const struct rte_flow_action_rss *rss_act;
+
+	if (actions[1].type != RTE_FLOW_ACTION_TYPE_END)
+		return rte_flow_error_set(error, EINVAL,
+					  RTE_FLOW_ERROR_TYPE_ACTION,
+					  &actions[1],
+					  "Only support one action for RSS.");
+
+	rss_act = (const struct rte_flow_action_rss *)actions[0].conf;
+	if (rss_act->level)
+		return rte_flow_error_set(error, ENOTSUP,
+					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+					  actions,
+					  "RSS level is not supported");
+
+	while (pattern->type == RTE_FLOW_ITEM_TYPE_VOID)
+		pattern++;
+
+	if (pattern[0].type == RTE_FLOW_ITEM_TYPE_VLAN)
+		return i40e_hash_parse_queue_region(dev, pattern, rss_act,
+						    rss_conf, error);
+
+	if (pattern[0].type == RTE_FLOW_ITEM_TYPE_END) {
+		if (rss_act->types)
+			PMD_DRV_LOG(INFO,
+				    "RSS types are not supported when no pattern specified");
+
+		if (rss_act->queue)
+			return i40e_hash_parse_queues(dev, rss_act,
+						      rss_conf, error);
+
+		if (rss_act->key) {
+			i40e_hash_parse_key(rss_act, rss_conf);
+			return 0;
+		}
+
+		PMD_DRV_LOG(WARNING, "Nothing change");
+		return 0;
+	}
+
+	if (rss_act->key)
+		i40e_hash_parse_key(rss_act, rss_conf);
+
+	rss_conf->conf.func = rss_act->func;
+	return i40e_hash_parse_pattern_act(dev, pattern, rss_act,
+					   rss_conf, error);
+}
+
+int
+i40e_hash_filter_restore(struct i40e_pf *pf)
+{
+	struct i40e_rss_filter *filter;
+	int ret;
+
+	TAILQ_FOREACH(filter, &pf->rss_config_list, next) {
+		ret = i40e_hash_config(pf, &filter->rss_filter_info);
+		if (ret) {
+			pf->hash_filter_enable = 0;
+			i40e_pf_disable_rss(pf);
+			PMD_DRV_LOG(ERR,
+				    "Re-configure RSS failed, RSS has been disabled");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static void
+i40e_hash_invalidate_conf(const struct i40e_rte_flow_rss_conf *ref_conf,
+			  struct i40e_rte_flow_rss_conf *conf)
+{
+	int i, j;
+
+	if (ref_conf->region_flags) {
+		if (conf->region_flags &&
+		    ref_conf->region_queue_start == conf->region_queue_start &&
+		    ref_conf->region_queue_num == conf->region_queue_num)
+			conf->region_queue_num = 0;
+
+		return;
+	}
+
+	if (conf->region_flags)
+		return;
+
+	/* Set same PCTYPE input sets invalid */
+	for (i = 0; i < ref_conf->pctype_count; i++) {
+		for (j = 0; j < conf->pctype_count; j++) {
+			if (ref_conf->pctypes[i] == conf->pctypes[j]) {
+				conf->pctype_count--;
+				if (conf->pctype_count - j > 0)
+					memcpy(&conf->pctypes[j],
+					       &conf->pctypes[j + 1],
+					       (conf->pctype_count - j) *
+					       sizeof(conf->pctypes[0]));
+				break;
+			}
+		}
+	}
+
+	if (ref_conf->conf.key_len && conf->conf.key_len) {
+		conf->conf.key_len = 0;
+		conf->conf.key = NULL;
+	}
+
+	if (ref_conf->conf.queue_num && conf->conf.queue_num) {
+		conf->conf.queue_num = 0;
+		conf->conf.queue = NULL;
+	}
+
+	if (ref_conf->conf.func != RTE_ETH_HASH_FUNCTION_DEFAULT)
+		conf->conf.func = RTE_ETH_HASH_FUNCTION_DEFAULT;
+}
+
+int
+i40e_hash_filter_create(struct i40e_pf *pf,
+			struct i40e_rte_flow_rss_conf *rss_conf)
+{
+	struct i40e_rss_filter *filter, *old;
+	struct i40e_rte_flow_rss_conf *new_conf;
+	int ret;
+
+	filter = rte_zmalloc("i40e_rss_filter", sizeof(*filter), 0);
+	if (!filter) {
+		PMD_DRV_LOG(ERR, "Failed to allocate memory.");
+		return -ENOMEM;
+	}
+
+	new_conf = &filter->rss_filter_info;
+
+	memcpy(new_conf, rss_conf, sizeof(*new_conf));
+	if (rss_conf->conf.queue_num)
+		new_conf->conf.queue = new_conf->queue;
+	if (rss_conf->conf.key_len)
+		new_conf->conf.key = new_conf->key;
+
+	ret = i40e_hash_config(pf, rss_conf);
+	if (ret) {
+		rte_free(filter);
+		if (i40e_pf_config_rss(pf))
+			return ret;
+
+		(void)i40e_hash_filter_restore(pf);
+		return ret;
+	}
+
+	TAILQ_FOREACH(old, &pf->rss_config_list, next)
+		i40e_hash_invalidate_conf(new_conf, &old->rss_filter_info);
+
+	TAILQ_INSERT_TAIL(&pf->rss_config_list, filter, next);
+	return 0;
+}
+
+static int
+i40e_hash_reset_conf(struct i40e_pf *pf,
+		     const struct i40e_rte_flow_rss_conf *rss_conf)
+{
+	const struct rte_flow_action_rss *rss_act = &rss_conf->conf;
+	struct i40e_hw *hw = &pf->adapter->hw;
+	const enum rte_eth_hash_function def_func =
+				RTE_ETH_HASH_FUNCTION_TOEPLITZ;
+	uint32_t i;
+	int ret;
+
+	if (rss_conf->region_queue_num)
+		return i40e_flush_queue_region_all_conf(pf->adapter->eth_dev,
+							hw, pf, 0);
+
+	for (i = 0; i < rss_conf->pctype_count; i++) {
+		ret = i40e_hash_reset_pctype(hw, rss_act, rss_conf->pctypes[i]);
+		if (ret)
+			return ret;
+	}
+
+	if (rss_act->func != RTE_ETH_HASH_FUNCTION_DEFAULT &&
+	    rss_act->func != def_func) {
+		ret = i40e_hash_config_func(hw, def_func);
+		if (ret)
+			return ret;
+	}
+
+	if (rss_act->key) {
+		ret = i40e_pf_reset_rss_key(pf);
+		if (ret)
+			return ret;
+	}
+
+	if (rss_act->queue && !pf->adapter->rss_reta_updated) {
+		pf->hash_enabled_queues = 0;
+		return i40e_pf_reset_rss_reta(pf);
+	}
+
+	return 0;
+}
+
+int
+i40e_hash_filter_destroy(struct i40e_pf *pf,
+			 const struct i40e_rss_filter *rss_filter)
+{
+	struct i40e_rss_filter *filter;
+	int ret;
+
+	TAILQ_FOREACH(filter, &pf->rss_config_list, next) {
+		if (rss_filter == filter) {
+			ret = i40e_hash_reset_conf(pf,
+						   &filter->rss_filter_info);
+			if (ret)
+				return ret;
+
+			TAILQ_REMOVE(&pf->rss_config_list, filter, next);
+			rte_free(filter);
+			return 0;
+		}
+	}
+
+	return -ENOENT;
+}
+
+int
+i40e_hash_filter_flush(struct i40e_pf *pf)
+{
+	struct rte_flow *flow, *next;
+
+	TAILQ_FOREACH_SAFE(flow, &pf->flow_list, node, next) {
+		if (flow->filter_type != RTE_ETH_FILTER_HASH)
+			continue;
+
+		if (flow->rule) {
+			struct i40e_rss_filter *filter = flow->rule;
+			int ret;
+
+			ret = i40e_hash_reset_conf(pf,
+						   &filter->rss_filter_info);
+			if (ret)
+				return ret;
+
+			TAILQ_REMOVE(&pf->rss_config_list, filter, next);
+			rte_free(filter);
+		}
+
+		TAILQ_REMOVE(&pf->flow_list, flow, node);
+		rte_free(flow);
+	}
+
+	assert(!pf->rss_config_list.tqh_first);
+	return 0;
+}
diff --git a/drivers/net/i40e/i40e_hash.h b/drivers/net/i40e/i40e_hash.h
new file mode 100644
index 0000000..ff8c91c
--- /dev/null
+++ b/drivers/net/i40e/i40e_hash.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Intel Corporation
+ */
+
+#ifndef _I40E_HASH_H_
+#define _I40E_HASH_H_
+
+#include <rte_ethdev.h>
+#include <rte_flow.h>
+#include "i40e_ethdev.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int i40e_hash_parse(const struct rte_eth_dev *dev,
+		    const struct rte_flow_item pattern[],
+		    const struct rte_flow_action actions[],
+		    struct i40e_rte_flow_rss_conf *rss_conf,
+		    struct rte_flow_error *error);
+
+int i40e_hash_filter_create(struct i40e_pf *pf,
+			    struct i40e_rte_flow_rss_conf *rss_conf);
+
+int i40e_hash_filter_restore(struct i40e_pf *pf);
+int i40e_hash_filter_destroy(struct i40e_pf *pf,
+			     const struct i40e_rss_filter *rss_filter);
+int i40e_hash_filter_flush(struct i40e_pf *pf);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* I40E_HASH_H_ */
diff --git a/drivers/net/i40e/meson.build b/drivers/net/i40e/meson.build
index 68f9895..4dcb3a3 100644
--- a/drivers/net/i40e/meson.build
+++ b/drivers/net/i40e/meson.build
@@ -17,6 +17,7 @@ sources = files(
 	'i40e_fdir.c',
 	'i40e_flow.c',
 	'i40e_tm.c',
+	'i40e_hash.c',
 	'i40e_vf_representor.c',
 	'rte_pmd_i40e.c'
 	)
