net/hns3: fix flow director lock
[dpdk.git] / drivers / net / hns3 / hns3_fdir.c
index 26c3117..87c1aef 100644 (file)
@@ -1,9 +1,8 @@
 /* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2018-2019 Hisilicon Limited.
+ * Copyright(c) 2018-2021 HiSilicon Limited.
  */
 
-#include <stdbool.h>
-#include <rte_ethdev_driver.h>
+#include <ethdev_driver.h>
 #include <rte_hash.h>
 #include <rte_hash_crc.h>
 #include <rte_io.h>
 
 #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_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
+#define HNS3_FD_AD_QUEUE_ID_HIGH_BIT   10
+#define HNS3_FD_AD_QUEUE_ID_HIGH_BIT_B 21
 
 enum HNS3_PORT_TYPE {
        HOST_PORT,
@@ -120,7 +126,6 @@ static const struct key_info tuple_key_info[] = {
        {INNER_SCTP_TAG, 32},
 };
 
-#define HNS3_BITS_PER_BYTE     8
 #define MAX_KEY_LENGTH         400
 #define MAX_200B_KEY_LENGTH    200
 #define MAX_META_DATA_LENGTH   16
@@ -315,7 +320,7 @@ int hns3_init_fd_config(struct hns3_adapter *hns)
                hns3_warn(hw, "Unsupported tunnel filter in 4K*200Bit");
                break;
        default:
-               hns3_err(hw, "Unsupported flow director mode %d",
+               hns3_err(hw, "Unsupported flow director mode %u",
                            pf->fdir.fd_cfg.fd_mode);
                return -EOPNOTSUPP;
        }
@@ -424,10 +429,22 @@ 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);
+       /* set extend bit if queue id > 1024 */
+       if (action->queue_id & BIT(HNS3_FD_AD_QUEUE_ID_HIGH_BIT))
+               hns3_set_bit(ad_data, HNS3_FD_AD_QUEUE_ID_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);
@@ -435,7 +452,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);
@@ -521,7 +538,8 @@ static inline void hns3_fd_convert_int32(uint32_t key, uint32_t mask,
        memcpy(val_y, &tmp_y_l, sizeof(tmp_y_l));
 }
 
-static bool hns3_fd_convert_tuple(uint32_t tuple, uint8_t *key_x,
+static bool hns3_fd_convert_tuple(struct hns3_hw *hw,
+                                 uint32_t tuple, uint8_t *key_x,
                                  uint8_t *key_y, struct hns3_fdir_rule *rule)
 {
        struct hns3_fdir_key_conf *key_conf;
@@ -598,6 +616,9 @@ static bool hns3_fd_convert_tuple(uint32_t tuple, uint8_t *key_x,
                calc_y(*key_y, key_conf->spec.ip_proto,
                       key_conf->mask.ip_proto);
                break;
+       default:
+               hns3_warn(hw, "not support tuple of (%u)", tuple);
+               break;
        }
        return true;
 }
@@ -619,7 +640,7 @@ static void hns3_fd_convert_meta_data(struct hns3_fd_key_cfg *cfg,
                                      uint8_t *key_x, uint8_t *key_y)
 {
        uint16_t meta_data = 0;
-       uint16_t port_number;
+       uint32_t port_number;
        uint8_t cur_pos = 0;
        uint8_t tuple_size;
        uint8_t shift_bits;
@@ -637,7 +658,7 @@ static void hns3_fd_convert_meta_data(struct hns3_fd_key_cfg *cfg,
                                     rule->key_conf.spec.tunnel_type ? 1 : 0);
                        cur_pos += tuple_size;
                } else if (i == VLAN_NUMBER) {
-                       uint8_t vlan_tag;
+                       uint32_t vlan_tag;
                        uint8_t vlan_num;
                        if (rule->key_conf.spec.tunnel_type == 0)
                                vlan_num = rule->key_conf.vlan_num;
@@ -705,7 +726,7 @@ static int hns3_config_key(struct hns3_adapter *hns,
 
                tuple_size = tuple_key_info[i].key_length / HNS3_BITS_PER_BYTE;
                if (key_cfg->tuple_active & BIT(i)) {
-                       tuple_valid = hns3_fd_convert_tuple(i, cur_key_x,
+                       tuple_valid = hns3_fd_convert_tuple(hw, i, cur_key_x,
                                                            cur_key_y, rule);
                        if (tuple_valid) {
                                cur_key_x += tuple_size;
@@ -723,14 +744,14 @@ static int hns3_config_key(struct hns3_adapter *hns,
 
        ret = hns3_fd_tcam_config(hw, false, rule->location, key_y, true);
        if (ret) {
-               hns3_err(hw, "Config fd key_y fail, loc=%d, ret=%d",
+               hns3_err(hw, "Config fd key_y fail, loc=%u, ret=%d",
                            rule->queue_id, ret);
                return ret;
        }
 
        ret = hns3_fd_tcam_config(hw, true, rule->location, key_x, true);
        if (ret)
-               hns3_err(hw, "Config fd key_x fail, loc=%d, ret=%d",
+               hns3_err(hw, "Config fd key_x fail, loc=%u, ret=%d",
                            rule->queue_id, ret);
        return ret;
 }
@@ -743,12 +764,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)) {
@@ -809,7 +830,6 @@ int hns3_fdir_filter_init(struct hns3_adapter *hns)
 
        fdir_hash_params.socket_id = rte_socket_id();
        TAILQ_INIT(&fdir_info->fdir_list);
-       rte_spinlock_init(&fdir_info->flows_lock);
        snprintf(fdir_hash_name, RTE_HASH_NAMESIZE, "%s", hns->hw.data->name);
        fdir_info->hash_handle = rte_hash_create(&fdir_hash_params);
        if (fdir_info->hash_handle == NULL) {
@@ -835,7 +855,6 @@ void hns3_fdir_filter_uninit(struct hns3_adapter *hns)
        struct hns3_fdir_info *fdir_info = &pf->fdir;
        struct hns3_fdir_rule_ele *fdir_filter;
 
-       rte_spinlock_lock(&fdir_info->flows_lock);
        if (fdir_info->hash_map) {
                rte_free(fdir_info->hash_map);
                fdir_info->hash_map = NULL;
@@ -844,7 +863,6 @@ void hns3_fdir_filter_uninit(struct hns3_adapter *hns)
                rte_hash_free(fdir_info->hash_handle);
                fdir_info->hash_handle = NULL;
        }
-       rte_spinlock_unlock(&fdir_info->flows_lock);
 
        fdir_filter = TAILQ_FIRST(&fdir_info->fdir_list);
        while (fdir_filter) {
@@ -870,10 +888,8 @@ static int hns3_fdir_filter_lookup(struct hns3_fdir_info *fdir_info,
        hash_sig_t sig;
        int ret;
 
-       rte_spinlock_lock(&fdir_info->flows_lock);
        sig = rte_hash_crc(key, sizeof(*key), 0);
        ret = rte_hash_lookup_with_hash(fdir_info->hash_handle, key, sig);
-       rte_spinlock_unlock(&fdir_info->flows_lock);
 
        return ret;
 }
@@ -887,19 +903,16 @@ static int hns3_insert_fdir_filter(struct hns3_hw *hw,
        int ret;
 
        key = &fdir_filter->fdir_conf.key_conf;
-       rte_spinlock_lock(&fdir_info->flows_lock);
        sig = rte_hash_crc(key, sizeof(*key), 0);
        ret = rte_hash_add_key_with_hash(fdir_info->hash_handle, key, sig);
        if (ret < 0) {
-               rte_spinlock_unlock(&fdir_info->flows_lock);
                hns3_err(hw, "Hash table full? err:%d(%s)!", ret,
-                        strerror(ret));
+                        strerror(-ret));
                return ret;
        }
 
        fdir_info->hash_map[ret] = fdir_filter;
        TAILQ_INSERT_TAIL(&fdir_info->fdir_list, fdir_filter, entries);
-       rte_spinlock_unlock(&fdir_info->flows_lock);
 
        return ret;
 }
@@ -912,11 +925,9 @@ static int hns3_remove_fdir_filter(struct hns3_hw *hw,
        hash_sig_t sig;
        int ret;
 
-       rte_spinlock_lock(&fdir_info->flows_lock);
        sig = rte_hash_crc(key, sizeof(*key), 0);
        ret = rte_hash_del_key_with_hash(fdir_info->hash_handle, key, sig);
        if (ret < 0) {
-               rte_spinlock_unlock(&fdir_info->flows_lock);
                hns3_err(hw, "Delete hash key fail ret=%d", ret);
                return ret;
        }
@@ -924,7 +935,6 @@ static int hns3_remove_fdir_filter(struct hns3_hw *hw,
        fdir_filter = fdir_info->hash_map[ret];
        fdir_info->hash_map[ret] = NULL;
        TAILQ_REMOVE(&fdir_info->fdir_list, fdir_filter, entries);
-       rte_spinlock_unlock(&fdir_info->flows_lock);
 
        rte_free(fdir_filter);
 
@@ -944,13 +954,13 @@ int hns3_fdir_filter_program(struct hns3_adapter *hns,
                ret = hns3_fd_tcam_config(hw, true, rule->location, NULL,
                                          false);
                if (ret)
-                       hns3_err(hw, "Failed to delete fdir: %d src_ip:%x "
-                                "dst_ip:%x src_port:%d dst_port:%d",
+                       hns3_err(hw, "Failed to delete fdir: %u src_ip:%x "
+                                "dst_ip:%x src_port:%u dst_port:%u ret = %d",
                                 rule->location,
                                 rule->key_conf.spec.src_ip[IP_ADDR_KEY_ID],
                                 rule->key_conf.spec.dst_ip[IP_ADDR_KEY_ID],
                                 rule->key_conf.spec.src_port,
-                                rule->key_conf.spec.dst_port);
+                                rule->key_conf.spec.dst_port, ret);
                else
                        hns3_remove_fdir_filter(hw, fdir_info, &rule->key_conf);
 
@@ -979,19 +989,17 @@ int hns3_fdir_filter_program(struct hns3_adapter *hns,
        rule->location = ret;
        node->fdir_conf.location = ret;
 
-       rte_spinlock_lock(&fdir_info->flows_lock);
        ret = hns3_config_action(hw, rule);
        if (!ret)
                ret = hns3_config_key(hns, rule);
-       rte_spinlock_unlock(&fdir_info->flows_lock);
        if (ret) {
-               hns3_err(hw, "Failed to config fdir: %d src_ip:%x dst_ip:%x "
-                        "src_port:%d dst_port:%d",
+               hns3_err(hw, "Failed to config fdir: %u src_ip:%x dst_ip:%x "
+                        "src_port:%u dst_port:%u ret = %d",
                         rule->location,
                         rule->key_conf.spec.src_ip[IP_ADDR_KEY_ID],
                         rule->key_conf.spec.dst_ip[IP_ADDR_KEY_ID],
                         rule->key_conf.spec.src_port,
-                        rule->key_conf.spec.dst_port);
+                        rule->key_conf.spec.dst_port, ret);
                (void)hns3_remove_fdir_filter(hw, fdir_info, &rule->key_conf);
        }
 
@@ -1008,9 +1016,7 @@ int hns3_clear_all_fdir_filter(struct hns3_adapter *hns)
        int ret = 0;
 
        /* flush flow director */
-       rte_spinlock_lock(&fdir_info->flows_lock);
        rte_hash_reset(fdir_info->hash_handle);
-       rte_spinlock_unlock(&fdir_info->flows_lock);
 
        fdir_filter = TAILQ_FIRST(&fdir_info->fdir_list);
        while (fdir_filter) {
@@ -1023,7 +1029,7 @@ int hns3_clear_all_fdir_filter(struct hns3_adapter *hns)
        }
 
        if (ret) {
-               hns3_err(hw, "Fail to delete FDIR filter!");
+               hns3_err(hw, "Fail to delete FDIR filter, ret = %d", ret);
                ret = -EIO;
        }
        return ret;
@@ -1038,6 +1044,17 @@ int hns3_restore_all_fdir_filter(struct hns3_adapter *hns)
        bool err = false;
        int ret;
 
+       /*
+        * This API is called in the reset recovery process, the parent function
+        * must hold hw->lock.
+        * There maybe deadlock if acquire hw->flows_lock directly because rte
+        * flow driver ops first acquire hw->flows_lock and then may acquire
+        * hw->lock.
+        * So here first release the hw->lock and then acquire the
+        * hw->flows_lock to avoid deadlock.
+        */
+       rte_spinlock_unlock(&hw->lock);
+       pthread_mutex_lock(&hw->flows_lock);
        TAILQ_FOREACH(fdir_filter, &fdir_info->fdir_list, entries) {
                ret = hns3_config_action(hw, &fdir_filter->fdir_conf);
                if (!ret)
@@ -1048,9 +1065,11 @@ int hns3_restore_all_fdir_filter(struct hns3_adapter *hns)
                                break;
                }
        }
+       pthread_mutex_unlock(&hw->flows_lock);
+       rte_spinlock_lock(&hw->lock);
 
        if (err) {
-               hns3_err(hw, "Fail to restore FDIR filter!");
+               hns3_err(hw, "Fail to restore FDIR filter, ret = %d", ret);
                return -EIO;
        }
        return 0;