net/hns3: support flow action of queue region
authorChengwen Feng <fengchengwen@huawei.com>
Tue, 22 Sep 2020 12:03:21 +0000 (20:03 +0800)
committerFerruh Yigit <ferruh.yigit@intel.com>
Wed, 30 Sep 2020 17:19:11 +0000 (19:19 +0200)
Kunpeng 930 hardware support spread packets to region of queues which can
be configured by FDIR rule, it means user can create one FDIR rule which
action is one region of queues, and then RSS use the region info to spread
packets.

As we know, RTE_FLOW_ACTION_TYPE_RSS is used to spread packets among
several queues, user could config such as func/level/types/key/queue
parameter to control RSS function, so we provide this feature under the
RTE_FLOW_ACTION_TYPE_RSS framework.

Consider RSS input tuple don't have eth header, we use the following
rule to distinguish them (whether it's queue region configuration or
rss general configuration):
Case 1: pattern have ETH and action's queue_num > 0, indicate it is
queue region configuration.
Case other: rss general configuration.

So if user want to configure one flow which ipv4=192.168.1.192 spread to
queue region of queue 0/1/2/3, the patter should:
  RTE_FLOW_ITEM_TYPE_ETH with spec=last=mask=NULL
  RTE_FLOW_ITEM_TYPE_IPV4 with spec=192.168.1.192 last=mask=NULL
  RTE_FLOW_ITEM_TYPE_END
the action should:
  RTE_FLOW_ACTION_TYPE_RSS with queue_num=4 queue=0/1/2/3
  RTE_FLOW_ACTION_TYPE_END
after calling rte_flow_create, one FDIR rule will be created.

Signed-off-by: Chengwen Feng <fengchengwen@huawei.com>
Signed-off-by: Wei Hu (Xavier) <xavier.huwei@huawei.com>
drivers/net/hns3/hns3_cmd.c
drivers/net/hns3/hns3_cmd.h
drivers/net/hns3/hns3_ethdev.h
drivers/net/hns3/hns3_fdir.c
drivers/net/hns3/hns3_fdir.h
drivers/net/hns3/hns3_flow.c

index 0299072..f7cfa00 100644 (file)
@@ -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))
index 629b114..510d68c 100644 (file)
@@ -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,
index 3f3f973..e1ed4d6 100644 (file)
@@ -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) \
index 5729923..65ab19d 100644 (file)
 
 #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_QUEUE_REGION_EN_B   16
+#define HNS3_FD_AD_QUEUE_REGION_SIZE_S 17
+#define HNS3_FD_AD_QUEUE_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_QUEUE_REGION_EN_B, 1);
+               hns3_set_field(ad_data, HNS3_FD_AD_QUEUE_REGION_SIZE_M,
+                              HNS3_FD_AD_QUEUE_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)) {
index f7b4216..a5760a3 100644 (file)
@@ -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;
 };
index 7ec46ae..1bc5911 100644 (file)
@@ -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;