From 248d3b4c9a396f89da43ec7f6becf377e69efeca Mon Sep 17 00:00:00 2001 From: Tariq Toukan Date: Mon, 16 Aug 2021 16:31:57 +0300 Subject: net/mlx5e: Support flow classification into RSS contexts Extend the existing flow classification support, to steer flows not only directly to a receive ring, but also into the new RSS contexts. Create needed TIR objects on demand, and hold reference on the RSS context. Signed-off-by: Tariq Toukan Reviewed-by: Maxim Mikityanskiy Signed-off-by: Saeed Mahameed --- drivers/net/ethernet/mellanox/mlx5/core/en/rss.c | 24 ++++++ drivers/net/ethernet/mellanox/mlx5/core/en/rss.h | 5 ++ .../net/ethernet/mellanox/mlx5/core/en/rx_res.c | 22 +++++ .../net/ethernet/mellanox/mlx5/core/en/rx_res.h | 2 + .../ethernet/mellanox/mlx5/core/en_fs_ethtool.c | 99 +++++++++++++++++----- 5 files changed, 131 insertions(+), 21 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/rss.c b/drivers/net/ethernet/mellanox/mlx5/core/en/rss.c index d2c4ace7c8ba..625cd49ef96c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/rss.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/rss.c @@ -367,6 +367,30 @@ u32 mlx5e_rss_get_tirn(struct mlx5e_rss *rss, enum mlx5_traffic_types tt, return mlx5e_tir_get_tirn(tir); } +/* Fill the "tirn" output parameter. + * Create the requested TIR if it's its first usage. + */ +int mlx5e_rss_obtain_tirn(struct mlx5e_rss *rss, + enum mlx5_traffic_types tt, + const struct mlx5e_lro_param *init_lro_param, + bool inner, u32 *tirn) +{ + struct mlx5e_tir *tir; + + tir = rss_get_tir(rss, tt, inner); + if (!tir) { /* TIR doesn't exist, create one */ + int err; + + err = mlx5e_rss_create_tir(rss, tt, init_lro_param, inner); + if (err) + return err; + tir = rss_get_tir(rss, tt, inner); + } + + *tirn = mlx5e_tir_get_tirn(tir); + return 0; +} + static void mlx5e_rss_apply(struct mlx5e_rss *rss, u32 *rqns, unsigned int num_rqns) { int err; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/rss.h b/drivers/net/ethernet/mellanox/mlx5/core/en/rss.h index 6f52d78a36da..d522a10dadf3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/rss.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/rss.h @@ -28,6 +28,11 @@ unsigned int mlx5e_rss_refcnt_read(struct mlx5e_rss *rss); u32 mlx5e_rss_get_tirn(struct mlx5e_rss *rss, enum mlx5_traffic_types tt, bool inner); +int mlx5e_rss_obtain_tirn(struct mlx5e_rss *rss, + enum mlx5_traffic_types tt, + const struct mlx5e_lro_param *init_lro_param, + bool inner, u32 *tirn); + void mlx5e_rss_enable(struct mlx5e_rss *rss, u32 *rqns, unsigned int num_rqns); void mlx5e_rss_disable(struct mlx5e_rss *rss); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/rx_res.c b/drivers/net/ethernet/mellanox/mlx5/core/en/rx_res.c index 432963594b8e..bf0313e2682b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/rx_res.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/rx_res.c @@ -245,6 +245,28 @@ int mlx5e_rx_res_rss_cnt(struct mlx5e_rx_res *res) return cnt; } +int mlx5e_rx_res_rss_index(struct mlx5e_rx_res *res, struct mlx5e_rss *rss) +{ + int i; + + if (!rss) + return -EINVAL; + + for (i = 0; i < MLX5E_MAX_NUM_RSS; i++) + if (rss == res->rss[i]) + return i; + + return -ENOENT; +} + +struct mlx5e_rss *mlx5e_rx_res_rss_get(struct mlx5e_rx_res *res, u32 rss_idx) +{ + if (rss_idx >= MLX5E_MAX_NUM_RSS) + return NULL; + + return res->rss[rss_idx]; +} + /* End of API rx_res_rss_* */ struct mlx5e_rx_res *mlx5e_rx_res_alloc(void) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/rx_res.h b/drivers/net/ethernet/mellanox/mlx5/core/en/rx_res.h index 8248caa36995..4a15942d79f7 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/rx_res.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/rx_res.h @@ -62,6 +62,8 @@ int mlx5e_rx_res_lro_set_param(struct mlx5e_rx_res *res, struct mlx5e_lro_param int mlx5e_rx_res_rss_init(struct mlx5e_rx_res *res, u32 *rss_idx, unsigned int init_nch); int mlx5e_rx_res_rss_destroy(struct mlx5e_rx_res *res, u32 rss_idx); int mlx5e_rx_res_rss_cnt(struct mlx5e_rx_res *res); +int mlx5e_rx_res_rss_index(struct mlx5e_rx_res *res, struct mlx5e_rss *rss); +struct mlx5e_rss *mlx5e_rx_res_rss_get(struct mlx5e_rx_res *res, u32 rss_idx); /* Workaround for hairpin */ struct mlx5e_rss_params_hash mlx5e_rx_res_get_current_hash(struct mlx5e_rx_res *res); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c index 3d8918f9399e..03693fa74a70 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_fs_ethtool.c @@ -35,11 +35,19 @@ #include "en/params.h" #include "en/xsk/pool.h" +static int flow_type_to_traffic_type(u32 flow_type); + +static u32 flow_type_mask(u32 flow_type) +{ + return flow_type & ~(FLOW_EXT | FLOW_MAC_EXT | FLOW_RSS); +} + struct mlx5e_ethtool_rule { struct list_head list; struct ethtool_rx_flow_spec flow_spec; struct mlx5_flow_handle *rule; struct mlx5e_ethtool_table *eth_ft; + struct mlx5e_rss *rss; }; static void put_flow_table(struct mlx5e_ethtool_table *eth_ft) @@ -66,7 +74,7 @@ static struct mlx5e_ethtool_table *get_flow_table(struct mlx5e_priv *priv, int table_size; int prio; - switch (fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) { + switch (flow_type_mask(fs->flow_type)) { case TCP_V4_FLOW: case UDP_V4_FLOW: case TCP_V6_FLOW: @@ -329,7 +337,7 @@ static int set_flow_attrs(u32 *match_c, u32 *match_v, outer_headers); void *outer_headers_v = MLX5_ADDR_OF(fte_match_param, match_v, outer_headers); - u32 flow_type = fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT); + u32 flow_type = flow_type_mask(fs->flow_type); switch (flow_type) { case TCP_V4_FLOW: @@ -397,10 +405,53 @@ static bool outer_header_zero(u32 *match_criteria) size - 1); } +static int flow_get_tirn(struct mlx5e_priv *priv, + struct mlx5e_ethtool_rule *eth_rule, + struct ethtool_rx_flow_spec *fs, + u32 rss_context, u32 *tirn) +{ + if (fs->flow_type & FLOW_RSS) { + struct mlx5e_lro_param lro_param; + struct mlx5e_rss *rss; + u32 flow_type; + int err; + int tt; + + rss = mlx5e_rx_res_rss_get(priv->rx_res, rss_context); + if (!rss) + return -ENOENT; + + flow_type = flow_type_mask(fs->flow_type); + tt = flow_type_to_traffic_type(flow_type); + if (tt < 0) + return -EINVAL; + + lro_param = mlx5e_get_lro_param(&priv->channels.params); + err = mlx5e_rss_obtain_tirn(rss, tt, &lro_param, false, tirn); + if (err) + return err; + eth_rule->rss = rss; + mlx5e_rss_refcnt_inc(eth_rule->rss); + } else { + struct mlx5e_params *params = &priv->channels.params; + enum mlx5e_rq_group group; + u16 ix; + + mlx5e_qid_get_ch_and_group(params, fs->ring_cookie, &ix, &group); + + *tirn = group == MLX5E_RQ_GROUP_XSK ? + mlx5e_rx_res_get_tirn_xsk(priv->rx_res, ix) : + mlx5e_rx_res_get_tirn_direct(priv->rx_res, ix); + } + + return 0; +} + static struct mlx5_flow_handle * add_ethtool_flow_rule(struct mlx5e_priv *priv, + struct mlx5e_ethtool_rule *eth_rule, struct mlx5_flow_table *ft, - struct ethtool_rx_flow_spec *fs) + struct ethtool_rx_flow_spec *fs, u32 rss_context) { struct mlx5_flow_act flow_act = { .flags = FLOW_ACT_NO_APPEND }; struct mlx5_flow_destination *dst = NULL; @@ -419,23 +470,17 @@ add_ethtool_flow_rule(struct mlx5e_priv *priv, if (fs->ring_cookie == RX_CLS_FLOW_DISC) { flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP; } else { - struct mlx5e_params *params = &priv->channels.params; - enum mlx5e_rq_group group; - u16 ix; - - mlx5e_qid_get_ch_and_group(params, fs->ring_cookie, &ix, &group); - dst = kzalloc(sizeof(*dst), GFP_KERNEL); if (!dst) { err = -ENOMEM; goto free; } + err = flow_get_tirn(priv, eth_rule, fs, rss_context, &dst->tir_num); + if (err) + goto free; + dst->type = MLX5_FLOW_DESTINATION_TYPE_TIR; - if (group == MLX5E_RQ_GROUP_XSK) - dst->tir_num = mlx5e_rx_res_get_tirn_xsk(priv->rx_res, ix); - else - dst->tir_num = mlx5e_rx_res_get_tirn_direct(priv->rx_res, ix); flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST; } @@ -459,6 +504,8 @@ static void del_ethtool_rule(struct mlx5e_priv *priv, { if (eth_rule->rule) mlx5_del_flow_rules(eth_rule->rule); + if (eth_rule->rss) + mlx5e_rss_refcnt_dec(eth_rule->rss); list_del(ð_rule->list); priv->fs.ethtool.tot_num_rules--; put_flow_table(eth_rule->eth_ft); @@ -619,7 +666,7 @@ static int validate_flow(struct mlx5e_priv *priv, fs->ring_cookie)) return -EINVAL; - switch (fs->flow_type & ~(FLOW_EXT | FLOW_MAC_EXT)) { + switch (flow_type_mask(fs->flow_type)) { case ETHER_FLOW: num_tuples += validate_ethter(fs); break; @@ -668,7 +715,7 @@ static int validate_flow(struct mlx5e_priv *priv, static int mlx5e_ethtool_flow_replace(struct mlx5e_priv *priv, - struct ethtool_rx_flow_spec *fs) + struct ethtool_rx_flow_spec *fs, u32 rss_context) { struct mlx5e_ethtool_table *eth_ft; struct mlx5e_ethtool_rule *eth_rule; @@ -699,7 +746,7 @@ mlx5e_ethtool_flow_replace(struct mlx5e_priv *priv, err = -EINVAL; goto del_ethtool_rule; } - rule = add_ethtool_flow_rule(priv, eth_ft->ft, fs); + rule = add_ethtool_flow_rule(priv, eth_rule, eth_ft->ft, fs, rss_context); if (IS_ERR(rule)) { err = PTR_ERR(rule); goto del_ethtool_rule; @@ -745,10 +792,20 @@ mlx5e_ethtool_get_flow(struct mlx5e_priv *priv, return -EINVAL; list_for_each_entry(eth_rule, &priv->fs.ethtool.rules, list) { - if (eth_rule->flow_spec.location == location) { - info->fs = eth_rule->flow_spec; + int index; + + if (eth_rule->flow_spec.location != location) + continue; + if (!info) return 0; - } + info->fs = eth_rule->flow_spec; + if (!eth_rule->rss) + return 0; + index = mlx5e_rx_res_rss_index(priv->rx_res, eth_rule->rss); + if (index < 0) + return index; + info->rss_context = index; + return 0; } return -ENOENT; @@ -764,7 +821,7 @@ mlx5e_ethtool_get_all_flows(struct mlx5e_priv *priv, info->data = MAX_NUM_OF_ETHTOOL_RULES; while ((!err || err == -ENOENT) && idx < info->rule_cnt) { - err = mlx5e_ethtool_get_flow(priv, info, location); + err = mlx5e_ethtool_get_flow(priv, NULL, location); if (!err) rule_locs[idx++] = location; location++; @@ -887,7 +944,7 @@ int mlx5e_ethtool_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) switch (cmd->cmd) { case ETHTOOL_SRXCLSRLINS: - err = mlx5e_ethtool_flow_replace(priv, &cmd->fs); + err = mlx5e_ethtool_flow_replace(priv, &cmd->fs, cmd->rss_context); break; case ETHTOOL_SRXCLSRLDEL: err = mlx5e_ethtool_flow_remove(priv, cmd->fs.location); -- cgit v1.2.3-59-g8ed1b