Skip to content

Commit

Permalink
net: hns3: refine the flow director handle
Browse files Browse the repository at this point in the history
In order to be compatible with aRFS rules, this patch adds
spin_lock for flow director rule adding, deleting, querying,
and packages the rule configuration.

Signed-off-by: Jian Shen <shenjian15@huawei.com>
Signed-off-by: Huazhong Tan <tanhuazhong@huawei.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Jian Shen authored and David S. Miller committed May 26, 2019
1 parent ffab969 commit 4412288
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 32 deletions.
131 changes: 99 additions & 32 deletions drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -1226,8 +1226,10 @@ static int hclge_configure(struct hclge_dev *hdev)
hdev->tm_info.hw_pfc_map = 0;
hdev->wanted_umv_size = cfg.umv_space;

if (hnae3_dev_fd_supported(hdev))
if (hnae3_dev_fd_supported(hdev)) {
hdev->fd_en = true;
hdev->fd_active_type = HCLGE_FD_RULE_NONE;
}

ret = hclge_parse_speed(cfg.default_speed, &hdev->hw.mac.speed);
if (ret) {
Expand Down Expand Up @@ -4906,14 +4908,18 @@ static bool hclge_fd_rule_exist(struct hclge_dev *hdev, u16 location)
struct hclge_fd_rule *rule = NULL;
struct hlist_node *node2;

spin_lock_bh(&hdev->fd_rule_lock);
hlist_for_each_entry_safe(rule, node2, &hdev->fd_rule_list, rule_node) {
if (rule->location >= location)
break;
}

spin_unlock_bh(&hdev->fd_rule_lock);

return rule && rule->location == location;
}

/* make sure being called after lock up with fd_rule_lock */
static int hclge_fd_update_rule_list(struct hclge_dev *hdev,
struct hclge_fd_rule *new_rule,
u16 location,
Expand All @@ -4937,9 +4943,13 @@ static int hclge_fd_update_rule_list(struct hclge_dev *hdev,
kfree(rule);
hdev->hclge_fd_rule_num--;

if (!is_add)
return 0;
if (!is_add) {
if (!hdev->hclge_fd_rule_num)
hdev->fd_active_type = HCLGE_FD_RULE_NONE;
clear_bit(location, hdev->fd_bmap);

return 0;
}
} else if (!is_add) {
dev_err(&hdev->pdev->dev,
"delete fail, rule %d is inexistent\n",
Expand All @@ -4954,7 +4964,9 @@ static int hclge_fd_update_rule_list(struct hclge_dev *hdev,
else
hlist_add_head(&new_rule->rule_node, &hdev->fd_rule_list);

set_bit(location, hdev->fd_bmap);
hdev->hclge_fd_rule_num++;
hdev->fd_active_type = new_rule->rule_type;

return 0;
}
Expand Down Expand Up @@ -5112,6 +5124,36 @@ static int hclge_fd_get_tuple(struct hclge_dev *hdev,
return 0;
}

/* make sure being called after lock up with fd_rule_lock */
static int hclge_fd_config_rule(struct hclge_dev *hdev,
struct hclge_fd_rule *rule)
{
int ret;

if (!rule) {
dev_err(&hdev->pdev->dev,
"The flow director rule is NULL\n");
return -EINVAL;
}

/* it will never fail here, so needn't to check return value */
hclge_fd_update_rule_list(hdev, rule, rule->location, true);

ret = hclge_config_action(hdev, HCLGE_FD_STAGE_1, rule);
if (ret)
goto clear_rule;

ret = hclge_config_key(hdev, HCLGE_FD_STAGE_1, rule);
if (ret)
goto clear_rule;

return 0;

clear_rule:
hclge_fd_update_rule_list(hdev, rule, rule->location, false);
return ret;
}

static int hclge_add_fd_entry(struct hnae3_handle *handle,
struct ethtool_rxnfc *cmd)
{
Expand Down Expand Up @@ -5174,8 +5216,10 @@ static int hclge_add_fd_entry(struct hnae3_handle *handle,
return -ENOMEM;

ret = hclge_fd_get_tuple(hdev, fs, rule);
if (ret)
goto free_rule;
if (ret) {
kfree(rule);
return ret;
}

rule->flow_type = fs->flow_type;

Expand All @@ -5184,23 +5228,13 @@ static int hclge_add_fd_entry(struct hnae3_handle *handle,
rule->vf_id = dst_vport_id;
rule->queue_id = q_index;
rule->action = action;
rule->rule_type = HCLGE_FD_EP_ACTIVE;

ret = hclge_config_action(hdev, HCLGE_FD_STAGE_1, rule);
if (ret)
goto free_rule;

ret = hclge_config_key(hdev, HCLGE_FD_STAGE_1, rule);
if (ret)
goto free_rule;

ret = hclge_fd_update_rule_list(hdev, rule, fs->location, true);
if (ret)
goto free_rule;
spin_lock_bh(&hdev->fd_rule_lock);
ret = hclge_fd_config_rule(hdev, rule);

return ret;
spin_unlock_bh(&hdev->fd_rule_lock);

free_rule:
kfree(rule);
return ret;
}

Expand Down Expand Up @@ -5232,8 +5266,12 @@ static int hclge_del_fd_entry(struct hnae3_handle *handle,
if (ret)
return ret;

return hclge_fd_update_rule_list(hdev, NULL, fs->location,
false);
spin_lock_bh(&hdev->fd_rule_lock);
ret = hclge_fd_update_rule_list(hdev, NULL, fs->location, false);

spin_unlock_bh(&hdev->fd_rule_lock);

return ret;
}

static void hclge_del_all_fd_entries(struct hnae3_handle *handle,
Expand All @@ -5243,25 +5281,30 @@ static void hclge_del_all_fd_entries(struct hnae3_handle *handle,
struct hclge_dev *hdev = vport->back;
struct hclge_fd_rule *rule;
struct hlist_node *node;
u16 location;

if (!hnae3_dev_fd_supported(hdev))
return;

spin_lock_bh(&hdev->fd_rule_lock);
for_each_set_bit(location, hdev->fd_bmap,
hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1])
hclge_fd_tcam_config(hdev, HCLGE_FD_STAGE_1, true, location,
NULL, false);

if (clear_list) {
hlist_for_each_entry_safe(rule, node, &hdev->fd_rule_list,
rule_node) {
hclge_fd_tcam_config(hdev, HCLGE_FD_STAGE_1, true,
rule->location, NULL, false);
hlist_del(&rule->rule_node);
kfree(rule);
hdev->hclge_fd_rule_num--;
}
} else {
hlist_for_each_entry_safe(rule, node, &hdev->fd_rule_list,
rule_node)
hclge_fd_tcam_config(hdev, HCLGE_FD_STAGE_1, true,
rule->location, NULL, false);
hdev->fd_active_type = HCLGE_FD_RULE_NONE;
hdev->hclge_fd_rule_num = 0;
bitmap_zero(hdev->fd_bmap,
hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1]);
}

spin_unlock_bh(&hdev->fd_rule_lock);
}

static int hclge_restore_fd_entries(struct hnae3_handle *handle)
Expand All @@ -5283,6 +5326,7 @@ static int hclge_restore_fd_entries(struct hnae3_handle *handle)
if (!hdev->fd_en)
return 0;

spin_lock_bh(&hdev->fd_rule_lock);
hlist_for_each_entry_safe(rule, node, &hdev->fd_rule_list, rule_node) {
ret = hclge_config_action(hdev, HCLGE_FD_STAGE_1, rule);
if (!ret)
Expand All @@ -5292,11 +5336,18 @@ static int hclge_restore_fd_entries(struct hnae3_handle *handle)
dev_warn(&hdev->pdev->dev,
"Restore rule %d failed, remove it\n",
rule->location);
clear_bit(rule->location, hdev->fd_bmap);
hlist_del(&rule->rule_node);
kfree(rule);
hdev->hclge_fd_rule_num--;
}
}

if (hdev->hclge_fd_rule_num)
hdev->fd_active_type = HCLGE_FD_EP_ACTIVE;

spin_unlock_bh(&hdev->fd_rule_lock);

return 0;
}

Expand Down Expand Up @@ -5329,13 +5380,18 @@ static int hclge_get_fd_rule_info(struct hnae3_handle *handle,

fs = (struct ethtool_rx_flow_spec *)&cmd->fs;

spin_lock_bh(&hdev->fd_rule_lock);

hlist_for_each_entry_safe(rule, node2, &hdev->fd_rule_list, rule_node) {
if (rule->location >= fs->location)
break;
}

if (!rule || fs->location != rule->location)
if (!rule || fs->location != rule->location) {
spin_unlock_bh(&hdev->fd_rule_lock);

return -ENOENT;
}

fs->flow_type = rule->flow_type;
switch (fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) {
Expand Down Expand Up @@ -5474,6 +5530,7 @@ static int hclge_get_fd_rule_info(struct hnae3_handle *handle,

break;
default:
spin_unlock_bh(&hdev->fd_rule_lock);
return -EOPNOTSUPP;
}

Expand Down Expand Up @@ -5505,6 +5562,8 @@ static int hclge_get_fd_rule_info(struct hnae3_handle *handle,
fs->ring_cookie |= vf_id;
}

spin_unlock_bh(&hdev->fd_rule_lock);

return 0;
}

Expand All @@ -5522,15 +5581,20 @@ static int hclge_get_all_rules(struct hnae3_handle *handle,

cmd->data = hdev->fd_cfg.rule_num[HCLGE_FD_STAGE_1];

spin_lock_bh(&hdev->fd_rule_lock);
hlist_for_each_entry_safe(rule, node2,
&hdev->fd_rule_list, rule_node) {
if (cnt == cmd->rule_cnt)
if (cnt == cmd->rule_cnt) {
spin_unlock_bh(&hdev->fd_rule_lock);
return -EMSGSIZE;
}

rule_locs[cnt] = rule->location;
cnt++;
}

spin_unlock_bh(&hdev->fd_rule_lock);

cmd->rule_cnt = cnt;

return 0;
Expand Down Expand Up @@ -5565,10 +5629,12 @@ static void hclge_enable_fd(struct hnae3_handle *handle, bool enable)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
bool clear;

hdev->fd_en = enable;
clear = hdev->fd_active_type == HCLGE_FD_ARFS_ACTIVE ? true : false;
if (!enable)
hclge_del_all_fd_entries(handle, false);
hclge_del_all_fd_entries(handle, clear);
else
hclge_restore_fd_entries(handle);
}
Expand Down Expand Up @@ -8143,6 +8209,7 @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev)

mutex_init(&hdev->vport_lock);
mutex_init(&hdev->vport_cfg_mutex);
spin_lock_init(&hdev->fd_rule_lock);

ret = hclge_pci_init(hdev);
if (ret) {
Expand Down
13 changes: 13 additions & 0 deletions drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,15 @@ static const struct key_info tuple_key_info[] = {
#define MAX_KEY_BYTES (MAX_KEY_DWORDS * 4)
#define MAX_META_DATA_LENGTH 32

/* assigned by firmware, the real filter number for each pf may be less */
#define MAX_FD_FILTER_NUM 4096

enum HCLGE_FD_ACTIVE_RULE_TYPE {
HCLGE_FD_RULE_NONE,
HCLGE_FD_ARFS_ACTIVE,
HCLGE_FD_EP_ACTIVE,
};

enum HCLGE_FD_PACKET_TYPE {
NIC_PACKET,
ROCE_PACKET,
Expand Down Expand Up @@ -630,6 +639,7 @@ struct hclge_fd_rule {
u16 vf_id;
u16 queue_id;
u16 location;
enum HCLGE_FD_ACTIVE_RULE_TYPE rule_type;
};

struct hclge_fd_ad_data {
Expand Down Expand Up @@ -809,7 +819,10 @@ struct hclge_dev {

struct hclge_fd_cfg fd_cfg;
struct hlist_head fd_rule_list;
spinlock_t fd_rule_lock; /* protect fd_rule_list and fd_bmap */
u16 hclge_fd_rule_num;
unsigned long fd_bmap[BITS_TO_LONGS(MAX_FD_FILTER_NUM)];
enum HCLGE_FD_ACTIVE_RULE_TYPE fd_active_type;
u8 fd_en;

u16 wanted_umv_size;
Expand Down

0 comments on commit 4412288

Please sign in to comment.