diff --git a/drivers/net/hns3/hns3_cmd.c b/drivers/net/hns3/hns3_cmd.c
index 0299072..f7cfa00 100644
--- a/drivers/net/hns3/hns3_cmd.c
+++ b/drivers/net/hns3/hns3_cmd.c
@@ -433,8 +433,9 @@ static void hns3_parse_capability(struct hns3_hw *hw,
 
 	if (hns3_get_bit(caps, HNS3_CAPS_UDP_GSO_B))
 		hns3_set_bit(hw->capability, HNS3_DEV_SUPPORT_UDP_GSO_B, 1);
-	if (hns3_get_bit(caps, HNS3_CAPS_ADQ_B))
-		hns3_set_bit(hw->capability, HNS3_DEV_SUPPORT_ADQ_B, 1);
+	if (hns3_get_bit(caps, HNS3_CAPS_FD_QUEUE_REGION_B))
+		hns3_set_bit(hw->capability, HNS3_DEV_SUPPORT_FD_QUEUE_REGION_B,
+			     1);
 	if (hns3_get_bit(caps, HNS3_CAPS_PTP_B))
 		hns3_set_bit(hw->capability, HNS3_DEV_SUPPORT_PTP_B, 1);
 	if (hns3_get_bit(caps, HNS3_CAPS_TX_PUSH_B))
diff --git a/drivers/net/hns3/hns3_cmd.h b/drivers/net/hns3/hns3_cmd.h
index 629b114..510d68c 100644
--- a/drivers/net/hns3/hns3_cmd.h
+++ b/drivers/net/hns3/hns3_cmd.h
@@ -278,7 +278,7 @@ struct hns3_rx_priv_buff_cmd {
 enum HNS3_CAPS_BITS {
 	HNS3_CAPS_UDP_GSO_B,
 	HNS3_CAPS_ATR_B,
-	HNS3_CAPS_ADQ_B,
+	HNS3_CAPS_FD_QUEUE_REGION_B,
 	HNS3_CAPS_PTP_B,
 	HNS3_CAPS_INT_QL_B,
 	HNS3_CAPS_SIMPLE_BD_B,
diff --git a/drivers/net/hns3/hns3_ethdev.h b/drivers/net/hns3/hns3_ethdev.h
index 3f3f973..e1ed4d6 100644
--- a/drivers/net/hns3/hns3_ethdev.h
+++ b/drivers/net/hns3/hns3_ethdev.h
@@ -719,7 +719,7 @@ struct hns3_adapter {
 #define HNS3_DEV_SUPPORT_DCB_B			0x0
 #define HNS3_DEV_SUPPORT_COPPER_B		0x1
 #define HNS3_DEV_SUPPORT_UDP_GSO_B		0x2
-#define HNS3_DEV_SUPPORT_ADQ_B			0x3
+#define HNS3_DEV_SUPPORT_FD_QUEUE_REGION_B	0x3
 #define HNS3_DEV_SUPPORT_PTP_B			0x4
 #define HNS3_DEV_SUPPORT_TX_PUSH_B		0x5
 #define HNS3_DEV_SUPPORT_INDEP_TXRX_B		0x6
@@ -736,9 +736,9 @@ struct hns3_adapter {
 #define hns3_dev_udp_gso_supported(hw) \
 	hns3_get_bit((hw)->capability, HNS3_DEV_SUPPORT_UDP_GSO_B)
 
-/* Support Application Device Queue */
-#define hns3_dev_adq_supported(hw) \
-	hns3_get_bit((hw)->capability, HNS3_DEV_SUPPORT_ADQ_B)
+/* Support the queue region action rule of flow directory */
+#define hns3_dev_fd_queue_region_supported(hw) \
+	hns3_get_bit((hw)->capability, HNS3_DEV_SUPPORT_FD_QUEUE_REGION_B)
 
 /* Support PTP timestamp offload */
 #define hns3_dev_ptp_supported(hw) \
diff --git a/drivers/net/hns3/hns3_fdir.c b/drivers/net/hns3/hns3_fdir.c
index 5729923..bf698f3 100644
--- a/drivers/net/hns3/hns3_fdir.c
+++ b/drivers/net/hns3/hns3_fdir.c
@@ -29,20 +29,23 @@
 
 #define HNS3_FD_AD_DATA_S		32
 #define HNS3_FD_AD_DROP_B		0
-#define HNS3_FD_AD_DIRECT_QID_B	1
+#define HNS3_FD_AD_DIRECT_QID_B		1
 #define HNS3_FD_AD_QID_S		2
-#define HNS3_FD_AD_QID_M		GENMASK(12, 2)
+#define HNS3_FD_AD_QID_M		GENMASK(11, 2)
 #define HNS3_FD_AD_USE_COUNTER_B	12
 #define HNS3_FD_AD_COUNTER_NUM_S	13
-#define HNS3_FD_AD_COUNTER_NUM_M	GENMASK(20, 13)
+#define HNS3_FD_AD_COUNTER_NUM_M	GENMASK(19, 13)
 #define HNS3_FD_AD_NXT_STEP_B		20
 #define HNS3_FD_AD_NXT_KEY_S		21
-#define HNS3_FD_AD_NXT_KEY_M		GENMASK(26, 21)
-#define HNS3_FD_AD_WR_RULE_ID_B	0
+#define HNS3_FD_AD_NXT_KEY_M		GENMASK(25, 21)
+#define HNS3_FD_AD_WR_RULE_ID_B		0
 #define HNS3_FD_AD_RULE_ID_S		1
-#define HNS3_FD_AD_RULE_ID_M		GENMASK(13, 1)
-#define HNS3_FD_AD_COUNTER_HIGH_BIT     7
-#define HNS3_FD_AD_COUNTER_HIGH_BIT_B   26
+#define HNS3_FD_AD_RULE_ID_M		GENMASK(12, 1)
+#define HNS3_FD_AD_QUE_REGION_EN_B	16
+#define HNS3_FD_AD_QUE_REGION_SIZE_S	17
+#define HNS3_FD_AD_QUE_REGION_SIZE_M	GENMASK(20, 17)
+#define HNS3_FD_AD_COUNTER_HIGH_BIT	7
+#define HNS3_FD_AD_COUNTER_HIGH_BIT_B	26
 
 enum HNS3_PORT_TYPE {
 	HOST_PORT,
@@ -426,13 +429,19 @@ static int hns3_fd_ad_config(struct hns3_hw *hw, int loc,
 		     action->write_rule_id_to_bd);
 	hns3_set_field(ad_data, HNS3_FD_AD_RULE_ID_M, HNS3_FD_AD_RULE_ID_S,
 		       action->rule_id);
+	if (action->nb_queues > 1) {
+		hns3_set_bit(ad_data, HNS3_FD_AD_QUE_REGION_EN_B, 1);
+		hns3_set_field(ad_data, HNS3_FD_AD_QUE_REGION_SIZE_M,
+			       HNS3_FD_AD_QUE_REGION_SIZE_S,
+			       rte_log2_u32(action->nb_queues));
+	}
 	/* set extend bit if counter_id is in [128 ~ 255] */
 	if (action->counter_id & BIT(HNS3_FD_AD_COUNTER_HIGH_BIT))
 		hns3_set_bit(ad_data, HNS3_FD_AD_COUNTER_HIGH_BIT_B, 1);
 	ad_data <<= HNS3_FD_AD_DATA_S;
 	hns3_set_bit(ad_data, HNS3_FD_AD_DROP_B, action->drop_packet);
-	hns3_set_bit(ad_data, HNS3_FD_AD_DIRECT_QID_B,
-		     action->forward_to_direct_queue);
+	if (action->nb_queues == 1)
+		hns3_set_bit(ad_data, HNS3_FD_AD_DIRECT_QID_B, 1);
 	hns3_set_field(ad_data, HNS3_FD_AD_QID_M, HNS3_FD_AD_QID_S,
 		       action->queue_id);
 	hns3_set_bit(ad_data, HNS3_FD_AD_USE_COUNTER_B, action->use_counter);
@@ -440,7 +449,7 @@ static int hns3_fd_ad_config(struct hns3_hw *hw, int loc,
 		       HNS3_FD_AD_COUNTER_NUM_S, action->counter_id);
 	hns3_set_bit(ad_data, HNS3_FD_AD_NXT_STEP_B, action->use_next_stage);
 	hns3_set_field(ad_data, HNS3_FD_AD_NXT_KEY_M, HNS3_FD_AD_NXT_KEY_S,
-		       action->counter_id);
+		       action->next_input_key);
 
 	req->ad_data = rte_cpu_to_le_64(ad_data);
 	ret = hns3_cmd_send(hw, &desc, 1);
@@ -752,12 +761,12 @@ static int hns3_config_action(struct hns3_hw *hw, struct hns3_fdir_rule *rule)
 
 	if (rule->action == HNS3_FD_ACTION_DROP_PACKET) {
 		ad_data.drop_packet = true;
-		ad_data.forward_to_direct_queue = false;
 		ad_data.queue_id = 0;
+		ad_data.nb_queues = 0;
 	} else {
 		ad_data.drop_packet = false;
-		ad_data.forward_to_direct_queue = true;
 		ad_data.queue_id = rule->queue_id;
+		ad_data.nb_queues = rule->nb_queues;
 	}
 
 	if (unlikely(rule->flags & HNS3_RULE_FLAG_COUNTER)) {
diff --git a/drivers/net/hns3/hns3_fdir.h b/drivers/net/hns3/hns3_fdir.h
index f7b4216..a5760a3 100644
--- a/drivers/net/hns3/hns3_fdir.h
+++ b/drivers/net/hns3/hns3_fdir.h
@@ -104,8 +104,18 @@ struct hns3_fd_rule_tuples {
 struct hns3_fd_ad_data {
 	uint16_t ad_id;
 	uint8_t drop_packet;
-	uint8_t forward_to_direct_queue;
+	/*
+	 * equal 0 when action is drop.
+	 * index of queue when action is queue.
+	 * index of first queue of queue region when action is queue region.
+	 */
 	uint16_t queue_id;
+	/*
+	 * equal 0 when action is drop.
+	 * equal 1 when action is queue.
+	 * numbers of queues of queue region when action is queue region.
+	 */
+	uint16_t nb_queues;
 	uint8_t use_counter;
 	uint8_t counter_id;
 	uint8_t use_next_stage;
@@ -141,7 +151,18 @@ struct hns3_fdir_rule {
 	uint8_t action;
 	/* VF id, avaiblable when flags with HNS3_RULE_FLAG_VF_ID. */
 	uint8_t vf_id;
+	/*
+	 * equal 0 when action is drop.
+	 * index of queue when action is queue.
+	 * index of first queue of queue region when action is queue region.
+	 */
 	uint16_t queue_id;
+	/*
+	 * equal 0 when action is drop.
+	 * equal 1 when action is queue.
+	 * numbers of queues of queue region when action is queue region.
+	 */
+	uint16_t nb_queues;
 	uint16_t location;
 	struct rte_flow_action_count act_cnt;
 };
diff --git a/drivers/net/hns3/hns3_flow.c b/drivers/net/hns3/hns3_flow.c
index 7ec46ae..1bc5911 100644
--- a/drivers/net/hns3/hns3_flow.c
+++ b/drivers/net/hns3/hns3_flow.c
@@ -90,16 +90,56 @@ net_addr_to_host(uint32_t *dst, const rte_be32_t *src, size_t len)
 		dst[i] = rte_be_to_cpu_32(src[i]);
 }
 
-static inline const struct rte_flow_action *
-find_rss_action(const struct rte_flow_action actions[])
+/*
+ * This function is used to find rss general action.
+ * 1. As we know RSS is used to spread packets among several queues, the flow
+ *    API provide the struct rte_flow_action_rss, user could config it's field
+ *    sush as: func/level/types/key/queue to control RSS function.
+ * 2. The flow API also support queue region configuration for hns3. It was
+ *    implemented by FDIR + RSS in hns3 hardware, user can create one FDIR rule
+ *    which action is RSS queues region.
+ * 3. When action is RSS, we use the following rule to distinguish:
+ *    Case 1: pattern have ETH and action's queue_num > 0, indicate it is queue
+ *            region configuration.
+ *    Case other: an rss general action.
+ */
+static const struct rte_flow_action *
+hns3_find_rss_general_action(const struct rte_flow_item pattern[],
+			     const struct rte_flow_action actions[])
 {
-	const struct rte_flow_action *next = &actions[0];
+	const struct rte_flow_action *act = NULL;
+	const struct hns3_rss_conf *rss;
+	bool have_eth = false;
 
-	for (; next->type != RTE_FLOW_ACTION_TYPE_END; next++) {
-		if (next->type == RTE_FLOW_ACTION_TYPE_RSS)
-			return next;
+	for (; actions->type != RTE_FLOW_ACTION_TYPE_END; actions++) {
+		if (actions->type == RTE_FLOW_ACTION_TYPE_RSS) {
+			act = actions;
+			break;
+		}
 	}
-	return NULL;
+	if (!act)
+		return NULL;
+
+	for (; pattern->type != RTE_FLOW_ITEM_TYPE_END; pattern++) {
+		if (pattern->type == RTE_FLOW_ITEM_TYPE_ETH) {
+			have_eth = true;
+			break;
+		}
+	}
+
+	rss = act->conf;
+	if (have_eth && rss->conf.queue_num) {
+		/*
+		 * Patter have ETH and action's queue_num > 0, indicate this is
+		 * queue region configuration.
+		 * Because queue region is implemented by FDIR + RSS in hns3
+		 * hardware, it need enter FDIR process, so here return NULL to
+		 * avoid enter RSS process.
+		 */
+		return NULL;
+	}
+
+	return act;
 }
 
 static inline struct hns3_flow_counter *
@@ -233,11 +273,53 @@ hns3_handle_action_queue(struct rte_eth_dev *dev,
 			  "available queue (%d) in driver.",
 			  queue->index, hw->used_rx_queues);
 		return rte_flow_error_set(error, EINVAL,
-					  RTE_FLOW_ERROR_TYPE_ACTION, action,
-					  "Invalid queue ID in PF");
+					  RTE_FLOW_ERROR_TYPE_ACTION_CONF,
+					  action, "Invalid queue ID in PF");
 	}
 
 	rule->queue_id = queue->index;
+	rule->nb_queues = 1;
+	rule->action = HNS3_FD_ACTION_ACCEPT_PACKET;
+	return 0;
+}
+
+static int
+hns3_handle_action_queue_region(struct rte_eth_dev *dev,
+				const struct rte_flow_action *action,
+				struct hns3_fdir_rule *rule,
+				struct rte_flow_error *error)
+{
+	struct hns3_adapter *hns = dev->data->dev_private;
+	const struct rte_flow_action_rss *conf = action->conf;
+	struct hns3_hw *hw = &hns->hw;
+	uint16_t idx;
+
+	if (!hns3_dev_fd_queue_region_supported(hw))
+		return rte_flow_error_set(error, ENOTSUP,
+			RTE_FLOW_ERROR_TYPE_ACTION, action,
+			"Not support config queue region!");
+
+	if ((!rte_is_power_of_2(conf->queue_num)) ||
+		conf->queue_num > hw->rss_size_max ||
+		conf->queue[0] >= hw->used_rx_queues ||
+		conf->queue[0] + conf->queue_num > hw->used_rx_queues) {
+		return rte_flow_error_set(error, EINVAL,
+			RTE_FLOW_ERROR_TYPE_ACTION_CONF, action,
+			"Invalid start queue ID and queue num! the start queue "
+			"ID must valid, the queue num must be power of 2 and "
+			"<= rss_size_max.");
+	}
+
+	for (idx = 1; idx < conf->queue_num; idx++) {
+		if (conf->queue[idx] != conf->queue[idx - 1] + 1)
+			return rte_flow_error_set(error, EINVAL,
+				RTE_FLOW_ERROR_TYPE_ACTION_CONF, action,
+				"Invalid queue ID sequence! the queue ID "
+				"must be continuous increment.");
+	}
+
+	rule->queue_id = conf->queue[0];
+	rule->nb_queues = conf->queue_num;
 	rule->action = HNS3_FD_ACTION_ACCEPT_PACKET;
 	return 0;
 }
@@ -274,6 +356,19 @@ hns3_handle_actions(struct rte_eth_dev *dev,
 		case RTE_FLOW_ACTION_TYPE_DROP:
 			rule->action = HNS3_FD_ACTION_DROP_PACKET;
 			break;
+		/*
+		 * Here RSS's real action is queue region.
+		 * Queue region is implemented by FDIR + RSS in hns3 hardware,
+		 * the FDIR's action is one queue region (start_queue_id and
+		 * queue_num), then RSS spread packets to the queue region by
+		 * RSS algorigthm.
+		 */
+		case RTE_FLOW_ACTION_TYPE_RSS:
+			ret = hns3_handle_action_queue_region(dev, actions,
+							      rule, error);
+			if (ret)
+				return ret;
+			break;
 		case RTE_FLOW_ACTION_TYPE_MARK:
 			mark =
 			    (const struct rte_flow_action_mark *)actions->conf;
@@ -1629,7 +1724,7 @@ hns3_flow_validate(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
 	if (ret)
 		return ret;
 
-	if (find_rss_action(actions))
+	if (hns3_find_rss_general_action(pattern, actions))
 		return hns3_parse_rss_filter(dev, actions, error);
 
 	memset(&fdir_rule, 0, sizeof(struct hns3_fdir_rule));
@@ -1684,7 +1779,7 @@ hns3_flow_create(struct rte_eth_dev *dev, const struct rte_flow_attr *attr,
 	flow_node->flow = flow;
 	TAILQ_INSERT_TAIL(&process_list->flow_list, flow_node, entries);
 
-	act = find_rss_action(actions);
+	act = hns3_find_rss_general_action(pattern, actions);
 	if (act) {
 		rss_conf = act->conf;
 
